Move common type aliases, peripheral bundles, and init helpers for
ESP32-S3 boards into src/board/esp32s3.rs. Heltec V3 (146->48 lines)
and V4 (155->57 lines) become thin wrappers containing only
board-specific code (Vext GPIO pin, display reset sequence).
Update build.rs to exclude esp32s3.rs from board discovery and
mod.rs.j2 to include the shared module under an ESP feature gate.
Every board's Board struct now implements the LoRaBoard trait, which
enforces that NAME, TX_POWER_RANGE, init(), and mac_address() are all
provided. Missing any of these is a compile error — no "good intentions"
needed.
The trait verifies metadata and initialization. Tasks use the board's
concrete types directly (Embassy tasks must be concrete). Board-specific
type aliases (RadioDriver, UsbDriver, DisplayI2c) and struct definitions
(RadioParts, UsbParts, DisplayParts) remain in each board file.
- New: src/board/traits.rs (LoRaBoard trait definition)
- Modified: all 3 board files (implement trait, remove standalone constants)
- Modified: main.rs (import trait for init)
- Modified: radio/task.rs (use Board::TX_POWER_RANGE via trait)
- Modified: display/task.rs (use Board::NAME via trait)
- Modified: build.rs (exclude traits.rs from board discovery)
- Removed: embedded-hal-async direct dep (not needed for trait approach)