feat: show MAC address on splash screen
Splash/waiting screen now shows: Row 1: "DongLoRa" (bold) Row 2: "Board Name vX.Y.Z" Row 3: MAC address (XX:XX:XX:XX:XX:XX) Row 4: "Waiting for host..." Each board reads its MAC at init: - ESP32-S3: efuse MAC via esp_hal::efuse::Efuse::mac_address() - nRF52840: FICR device address registers BoardInfo struct bundles name/version/mac to keep dashboard() under clippy's argument limit.
This commit is contained in:
5 files changed
+67
-19
No files matched your search
@@ -41,6 +41,7 @@ pub struct UsbParts {
|
||||
|
||||
pub struct DisplayParts {
|
||||
pub i2c: DisplayI2c,
|
||||
pub mac: [u8; 6],
|
||||
}
|
||||
|
||||
// ── Board init ───────────────────────────────────────────────────────
|
||||
@@ -130,7 +131,8 @@ impl Board {
|
||||
.with_sda(p.GPIO17)
|
||||
.with_scl(p.GPIO18)
|
||||
.into_async();
|
||||
let display = Some(DisplayParts { i2c });
|
||||
let mac = esp_hal::efuse::Efuse::mac_address();
|
||||
let display = Some(DisplayParts { i2c, mac });
|
||||
|
||||
(radio, usb, display)
|
||||
}
|
||||
|
||||
@@ -41,6 +41,7 @@ pub struct UsbParts {
|
||||
|
||||
pub struct DisplayParts {
|
||||
pub i2c: DisplayI2c,
|
||||
pub mac: [u8; 6],
|
||||
}
|
||||
|
||||
// ── Board init ───────────────────────────────────────────────────────
|
||||
@@ -141,7 +142,8 @@ impl Board {
|
||||
.with_sda(p.GPIO17)
|
||||
.with_scl(p.GPIO18)
|
||||
.into_async();
|
||||
let display = Some(DisplayParts { i2c });
|
||||
let mac = esp_hal::efuse::Efuse::mac_address();
|
||||
let display = Some(DisplayParts { i2c, mac });
|
||||
|
||||
(radio, usb, display)
|
||||
}
|
||||
|
||||
@@ -49,6 +49,7 @@ pub struct UsbParts {
|
||||
|
||||
pub struct DisplayParts {
|
||||
pub i2c: DisplayI2c,
|
||||
pub mac: [u8; 6],
|
||||
}
|
||||
|
||||
// ── Board init ───────────────────────────────────────────────────────
|
||||
@@ -110,7 +111,23 @@ impl Board {
|
||||
// via SSD1306 init (fails gracefully if no display attached).
|
||||
let i2c_cfg = twim::Config::default();
|
||||
let i2c = Twim::new(p.TWISPI0, Irqs, p.P0_13, p.P0_14, i2c_cfg);
|
||||
let display = Some(DisplayParts { i2c });
|
||||
// Read device address from FICR (factory info registers).
|
||||
// FICR is at fixed address 0x10000000 on nRF52840.
|
||||
let mac = unsafe {
|
||||
let ficr = 0x10000000 as *const u32;
|
||||
// DEVICEADDR[0] at offset 0x0A4, DEVICEADDR[1] at offset 0x0A8
|
||||
let addr0 = core::ptr::read_volatile(ficr.byte_add(0x0A4));
|
||||
let addr1 = core::ptr::read_volatile(ficr.byte_add(0x0A8));
|
||||
[
|
||||
addr0 as u8,
|
||||
(addr0 >> 8) as u8,
|
||||
(addr0 >> 16) as u8,
|
||||
(addr0 >> 24) as u8,
|
||||
addr1 as u8,
|
||||
(addr1 >> 8) as u8,
|
||||
]
|
||||
};
|
||||
let display = Some(DisplayParts { i2c, mac });
|
||||
|
||||
(radio, usb, display)
|
||||
}
|
||||
|
||||
+19
-8
@@ -26,6 +26,13 @@ const SPARK_H: i32 = 19; // y=45..63
|
||||
const RSSI_MIN: i16 = -120;
|
||||
const RSSI_MAX: i16 = 0;
|
||||
|
||||
/// Static board identity info for display rendering.
|
||||
pub struct BoardInfo<'a> {
|
||||
pub name: &'a str,
|
||||
pub version: &'a str,
|
||||
pub mac: &'a str,
|
||||
}
|
||||
|
||||
/// Render the main status dashboard.
|
||||
pub fn dashboard(
|
||||
target: &mut impl DrawTarget<Color = BinaryColor>,
|
||||
@@ -33,16 +40,14 @@ pub fn dashboard(
|
||||
rssi_history: &[i16; RSSI_HISTORY_LEN],
|
||||
tx_history: &[bool; RSSI_HISTORY_LEN],
|
||||
rssi_count: usize,
|
||||
board_name: &str,
|
||||
version: &str,
|
||||
board: &BoardInfo,
|
||||
) {
|
||||
let _ = target.clear(BinaryColor::Off);
|
||||
let style = MonoTextStyle::new(&FONT_6X10, BinaryColor::On);
|
||||
let mut buf: String<32> = String::new();
|
||||
|
||||
match status.config {
|
||||
Some(cfg) => {
|
||||
// Row 0: state + frequency, TX power right-justified
|
||||
let mut buf: String<32> = String::new();
|
||||
let freq_mhz = cfg.freq_hz / 1_000_000;
|
||||
let freq_khz = (cfg.freq_hz % 1_000_000) / 1_000;
|
||||
let _ = write!(buf, " {}.{:03}MHz", freq_mhz, freq_khz);
|
||||
@@ -145,24 +150,30 @@ pub fn dashboard(
|
||||
rssi_sparkline(target, rssi_history, tx_history, rssi_count);
|
||||
}
|
||||
None => {
|
||||
// Row 1: "DongLoRa" in bold
|
||||
let title_style = MonoTextStyle::new(&FONT_9X15_BOLD, BinaryColor::On);
|
||||
Text::with_alignment(
|
||||
"DongLoRa",
|
||||
Point::new(W / 2, 24),
|
||||
Point::new(W / 2, 15),
|
||||
title_style,
|
||||
Alignment::Center,
|
||||
)
|
||||
.draw(target)
|
||||
.ok();
|
||||
Text::with_alignment(version, Point::new(W / 2, 38), style, Alignment::Center)
|
||||
// Row 2: "Board Name v0.1.0"
|
||||
buf.clear();
|
||||
let _ = write!(buf, "{} v{}", board.name, board.version);
|
||||
Text::with_alignment(&buf, Point::new(W / 2, 28), style, Alignment::Center)
|
||||
.draw(target)
|
||||
.ok();
|
||||
Text::with_alignment(board_name, Point::new(W / 2, 50), style, Alignment::Center)
|
||||
// Row 3: MAC address
|
||||
Text::with_alignment(board.mac, Point::new(W / 2, 41), style, Alignment::Center)
|
||||
.draw(target)
|
||||
.ok();
|
||||
// Row 4: status
|
||||
Text::with_alignment(
|
||||
"Waiting for host...",
|
||||
Point::new(W / 2, 63),
|
||||
Point::new(W / 2, 54),
|
||||
style,
|
||||
Alignment::Center,
|
||||
)
|
||||
|
||||
+24
-8
@@ -81,6 +81,23 @@ pub async fn display_task(
|
||||
status: &'static StatusWatch,
|
||||
display_commands: &'static DisplayCommandChannel,
|
||||
) {
|
||||
// Format MAC address as "XX:XX:XX:XX:XX:XX"
|
||||
let mut mac_str: heapless::String<18> = heapless::String::new();
|
||||
let m = parts.mac;
|
||||
let _ = core::fmt::Write::write_fmt(
|
||||
&mut mac_str,
|
||||
format_args!(
|
||||
"{:02X}:{:02X}:{:02X}:{:02X}:{:02X}:{:02X}",
|
||||
m[0], m[1], m[2], m[3], m[4], m[5]
|
||||
),
|
||||
);
|
||||
|
||||
let board_info = render::BoardInfo {
|
||||
name: BOARD_NAME,
|
||||
version: env!("CARGO_PKG_VERSION"),
|
||||
mac: &mac_str,
|
||||
};
|
||||
|
||||
let interface = I2CDisplayInterface::new(parts.i2c);
|
||||
let mut display = Ssd1306Async::new(interface, DisplaySize128x64, DisplayRotation::Rotate0)
|
||||
.into_buffered_graphics_mode();
|
||||
@@ -104,7 +121,7 @@ pub async fn display_task(
|
||||
};
|
||||
|
||||
// Show splash/waiting screen (dashboard with no config renders it)
|
||||
render_and_flush(&mut display, &state).await;
|
||||
render_and_flush(&mut display, &state, &board_info).await;
|
||||
|
||||
loop {
|
||||
match select3(
|
||||
@@ -129,7 +146,7 @@ pub async fn display_task(
|
||||
state.last_status = radio_status;
|
||||
|
||||
if state.display_on {
|
||||
render_and_flush(&mut display, &state).await;
|
||||
render_and_flush(&mut display, &state, &board_info).await;
|
||||
}
|
||||
}
|
||||
Either3::Second(cmd) => match cmd {
|
||||
@@ -145,18 +162,18 @@ pub async fn display_task(
|
||||
if let Some(s) = receiver.try_get() {
|
||||
state.last_status = s;
|
||||
}
|
||||
render_and_flush(&mut display, &state).await;
|
||||
render_and_flush(&mut display, &state, &board_info).await;
|
||||
}
|
||||
DisplayCommand::Reset => {
|
||||
state = DisplayState::new();
|
||||
render_and_flush(&mut display, &state).await;
|
||||
render_and_flush(&mut display, &state, &board_info).await;
|
||||
}
|
||||
},
|
||||
Either3::Third(()) => {
|
||||
// Timer tick: advance sparkline slot
|
||||
state.advance_slot();
|
||||
if state.display_on {
|
||||
render_and_flush(&mut display, &state).await;
|
||||
render_and_flush(&mut display, &state, &board_info).await;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -171,7 +188,7 @@ type Display<I> = ssd1306::Ssd1306Async<
|
||||
ssd1306::mode::BufferedGraphicsModeAsync<DisplaySize128x64>,
|
||||
>;
|
||||
|
||||
async fn render_and_flush<I>(display: &mut Display<I>, state: &DisplayState)
|
||||
async fn render_and_flush<I>(display: &mut Display<I>, state: &DisplayState, board: &render::BoardInfo<'_>)
|
||||
where
|
||||
I: display_interface::AsyncWriteOnlyDataCommand,
|
||||
{
|
||||
@@ -181,8 +198,7 @@ where
|
||||
&state.rssi_history,
|
||||
&state.tx_history,
|
||||
state.rssi_count,
|
||||
BOARD_NAME,
|
||||
env!("CARGO_PKG_VERSION"),
|
||||
board,
|
||||
);
|
||||
let _ = display.flush().await;
|
||||
}
|
||||
Reference in new issue
Block a user