Files
firmware/src/board/traits.rs
T
swaits aca4c3cffd feat(t114): add Heltec Mesh Node T114 board support
Adds nRF52840 + SX1262 + 1.14" 240×135 ST7789 color TFT support. First
color display board in the project; introduces a BoardDisplay trait so
each board renders to its native pixel format and resolution without
aliasing or color-quantization round-trips.

Architecture:
- New BoardDisplay trait (src/display.rs) bundles render_*, present(),
  set_bright/set_dim. Replaces the old DrawTarget<Color=BinaryColor>
  + DisplayBrightness combo as the LoRaBoard::DisplayDriver bound.
- Mono OLED drivers (Sh1106, Ssd1306Async) get adapter impls that
  delegate to the existing display::render module — no behavior change
  for any existing board.
- T114 ST7789 driver (src/driver/st7789.rs) wraps lcd-async (async fork
  of mipidsi) with a 64,800-byte raw byte framebuffer in .bss. Renders
  via lcd_async::raw_framebuf::RawFrameBuf<Rgb565, _>, presents via a
  single async DMA blit (panel.show_raw_data(...).await) — the await
  yields the executor for the ~65 ms SPI transfer so the radio task
  isn't starved during repaints.
- PWM backlight on PWM0 / P0.15 (active-LOW, inverted polarity) for
  smooth dim/bright transitions instead of GPIO toggle.
- Native 240×135 Rgb565 renderer (src/display/render_color.rs) with
  splash + dashboard + sparkline.
- Shared QR-code blit (src/display/qr.rs), generic over PixelColor,
  re-centers the 64×64 bitmap which has cells in cols 0..50 and ~14 px
  of right-side padding — both mono and color splash now show the QR
  with 7 px quiet zones on all four sides (was visibly left-shifted).
- Shared content types (BoardInfo, DashboardCtx) decouple what to draw
  from how each board renders it.
- create_display() now takes the board's full DisplayParts bundle
  (was just the I2C bus) so non-I2C displays can carry SPI + control
  pins through.

Hardware:
- VEXT_ENABLE on P0.21 driven HIGH at boot — powers the SX1262 + TFT
  rail. Without this, lora-phy init succeeds at the SPI level but
  TX_DONE never fires.
- VTFT_CTRL on P0.03, active LOW; backlight on P0.15, active LOW.
- TFT SPI2 (SCK P1.08 / MOSI P1.09) at 8 MHz over EasyDMA. Async
  ExclusiveDevice from embedded-hal-bus (with the 'async' feature).
- lcd-async builder at display_size(135, 240), display_offset(52, 40),
  Deg90 rotation, ColorInversion::Inverted — standard 1.14" ST7789
  die mapping.
- Linker: shared ld/nrf52840-memory.x (S140 SoftDevice preserved at
  0x01000-0x26000 per project policy).
2026-04-30 03:11:36 -06:00

95 lines
3.2 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
//! Board abstraction trait.
//!
//! Every board must implement [`LoRaBoard`] with concrete associated types
//! for its radio, host communication, display, and LED peripherals. The
//! compiler enforces completeness — missing types or methods are compile errors.
//!
//! See `src/board/PORTING.md` for a step-by-step guide to adding a new board.
use crate::display::BoardDisplay;
/// Async RGB LED control. Boards without an LED use `()` which is a no-op.
pub trait RgbLed {
fn set_rgb(&mut self, r: u8, g: u8, b: u8) -> impl core::future::Future<Output = ()>;
}
impl RgbLed for () {
async fn set_rgb(&mut self, _r: u8, _g: u8, _b: u8) {}
}
/// Compile-time contract for a DongLoRa board.
pub trait LoRaBoard: Sized {
/// Human-readable board name (shown on display splash screen).
const NAME: &'static str;
/// TX power range in dBm (min, max) for this board's radio + PA.
const TX_POWER_RANGE: (i8, i8);
/// Radio peripheral bundle (driver + delay).
type RadioParts;
/// Host communication peripheral bundle (USB or UART driver).
type CommParts;
/// Display peripheral bundle (I2C bus for display init).
type DisplayParts;
/// Concrete display driver type. Each board's driver implements
/// [`BoardDisplay`] to render the splash + dashboard content into its
/// native pixel format and resolution and to flush / dim the panel.
type DisplayDriver: BoardDisplay;
/// RGB LED driver. Boards without an LED use `()`.
type LedDriver: RgbLed;
/// Initialize the board hardware.
fn init() -> Self;
/// Read the board's unique hardware address (MAC, device ID, etc.).
fn mac_address() -> [u8; 6];
/// Radio chip identifier reported in `GET_INFO`. Defaults to SX1262
/// (`0x0002`), matching every currently-supported board. Override for
/// boards that carry a different chip (LLCC68, SX1261, LR11xx, …).
fn radio_chip_id() -> u16 {
// SX1262 — see PROTOCOL.md §8.
0x0002
}
/// (freq_min_hz, freq_max_hz) — the RF front-end's effective tuning
/// window on this specific board. Reported in `GET_INFO`. Defaults
/// to the SX1262's nominal 150–960 MHz range.
fn freq_range_hz() -> (u32, u32) {
(150_000_000, 960_000_000)
}
/// Bitmap of supported LoRa spreading factors — bit N = SF N. Defaults
/// to SX126x's SF5–SF12 (`0x1FE0`). SX127x boards must override to
/// `0x1FC0` (SF6–SF12); LLCC68 boards to `0x0FE0` (SF5–SF11).
fn supported_sf_bitmap() -> u16 {
0x1FE0
}
/// Bitmap of supported LoRa bandwidths. Bit positions match
/// `LoRaBandwidth::as_u8()` (sub-GHz BW enum values 0..9). Defaults
/// to all sub-GHz BWs (`0x03FF`). SX128x boards flip the 2.4 GHz
/// bits when we add them.
fn supported_bw_bitmap() -> u16 {
0x03FF
}
/// Decompose initialized board into peripheral bundles for each task.
fn into_parts(
self,
) -> BoardParts<Self::RadioParts, Self::CommParts, Self::DisplayParts, Self::LedDriver>;
}
/// Peripheral bundles for each firmware task, produced by [`LoRaBoard::into_parts`].
pub struct BoardParts<R, C, D, L> {
pub radio: R,
pub host: C,
pub display: Option<D>,
pub led: L,
pub mac: [u8; 6],
}