[workspace] members = ["."] [package] name = "donglora" version = "1.5.1" edition = "2021" build = "build.rs" authors = ["Stephen Waits "] license = "MIT" description = "Transparent LoRa radio over USB — plug in a board, talk LoRa from your host" repository = "https://github.com/donglora/firmware" homepage = "https://github.com/donglora/firmware" keywords = ["lora", "radio", "embedded", "usb", "firmware"] categories = ["embedded", "hardware-support", "no-std"] [dependencies] cfg-if = "1.0" critical-section = "1.2" defmt = "0.3" embedded-hal = "1.0" embedded-hal-async = "1.0" embassy-embedded-hal = "0.6" embassy-executor = "0.10" embassy-sync = "0.8" embassy-time = "0.5" embassy-usb = { version = "0.6", features = ["defmt"] } embassy-usb-driver = "0.2" ucobs = { version = "0.3", features = ["legacy-msrv"] } heapless = "0.9" donglora-protocol = "1" hsmc = { version = "0.6", default-features = false, features = ["embassy", "trace-defmt"] } # Fork branch carrying CAD IRQ-clear / standby-after-CAD fixes awaiting upstream PRs. # Switch back to crates.io once changes are upstreamed. lora-phy = { git = "https://github.com/swaits/lora-rs.git", branch = "fixed", features = ["defmt-03"] } portable-atomic = { version = "1", default-features = false, features = ["critical-section"] } static_cell = "2.1" # Display rendering display-interface = "0.5" embedded-graphics = "0.8" ssd1306 = { version = "0.10", features = ["async"] } # T114 ST7789 TFT (color, async SPI). Optional — only pulled in by the # heltec_mesh_node_t114 feature. Mono OLED boards keep their existing # display-interface + ssd1306/sh1106 stack and don't pay for these. # # `lcd-async` is an async fork of mipidsi: same model/builder shape but # `init()` and pixel writes are `async fn`s. Combined with embassy-nrf's # DMA-backed async Spim, the dashboard repaint yields the executor for # the duration of the SPI transfer instead of busy-looping for ~65 ms, # so the radio task isn't starved. # # embedded-hal-bus needs the `async` feature for `ExclusiveDevice` to # implement `embedded_hal_async::spi::SpiDevice` (in addition to the # blocking impl). lcd-async = { version = "0.1", optional = true } embedded-hal-bus = { version = "0.3", optional = true, features = ["async"] } # Async IO traits and combinators embedded-io-async = "0.7" embassy-futures = "0.1" # Xtensa ESP crates — requires esp toolchain (espup). The chip feature # (esp32 / esp32s3) is selected per board via the board-level feature flag # below, so the same dep lines support both classic ESP32 and ESP32-S3. esp-backtrace = { version = "0.19", optional = true, features = [ "panic-handler", "defmt", ] } esp-hal = { version = "1.1", optional = true, features = [ "unstable", ] } esp-println = { version = "0.17", optional = true, features = [ "defmt-espflash", ] } esp-rtos = { version = "0.3", optional = true, features = [ "embassy", ] } # Emits the IDF app descriptor (`.flash.appdesc`) that espflash v4 # requires in every ESP binary. The chip subfeature is selected per # board below alongside the other esp-* chip features. esp-bootloader-esp-idf = { version = "0.5", optional = true, features = [ "defmt", ] } # nRF52840 (RAK 4631) cortex-m = { version = "0.7", optional = true, features = [ "critical-section-single-core", ] } cortex-m-rt = { version = "0.7", optional = true } defmt-rtt = { version = "0.4", optional = true } embassy-nrf = { version = "0.10", optional = true, features = [ "nrf52840", "gpiote", "time-driver-rtc1", "defmt", # UICR pin-config flags — must match what the Adafruit nRF52 bootloader # actually programmed into UICR on this board. Verified empirically on # RAK4631 via `probe-rs read b32 0x10001200 4`: # PSELRESET[0/1] = 0x12 (P0.18 connected as RESET — NOT gpio) # NFCPINS = 0xFFFFFFFE (bit 0 = 0 → NFC pins as GPIO) # So `nfc-pins-as-gpio` matches; `reset-pin-as-gpio` would NOT match # (would request GPIO when UICR has RESET enabled). The bootloader # uses NRESET for its physical button-reset path, so leaving the pin # as RESET is the right state. "nfc-pins-as-gpio", ] } panic-probe = { version = "1.0", optional = true, features = ["print-defmt"] } # RP2040 (Waveshare RP2040-LoRa) embassy-rp = { version = "0.10", optional = true, features = [ "rp2040", "time-driver", "defmt", ] } [build-dependencies] minijinja = "2.18" owo-colors = "4.3" [features] # Bridge features for hsmc's macro-expanded `#[cfg(feature = "...")]` # attributes. Macros expand into the *call-site* crate, so any cfg the # macro emits is evaluated against THIS crate's feature set, not hsmc's. # That means enabling `hsmc/embassy` or `hsmc/trace-defmt` via the dep # only activates them inside hsmc's own compilation — for the cfg gates # inside expanded macro bodies to fire here, we need same-named features # in this Cargo.toml. `tokio` is declared just to silence the macro's # `#[cfg(feature = "tokio")]` checks. # # `trace-defmt` must be in every board feature so chart trace lines # (entries, exits, transitions, etc.) actually compile in. Without it, # hsmc 0.4's `__chart_observe!` macro expands to nothing for the defmt # arm and you get silent statecharts. embassy = [] tokio = [] trace-defmt = [] # When enabled, replaces the display task with a LED-based diagnostic # blinker driven by `crate::debug_blink::CHECKPOINT`. Used for diagnosing # the firmware on UART-only boards where defmt output would corrupt the # host protocol on the same UART. The LED flashes N times then pauses — # a human watches the pattern and reports N to determine where execution # reached / stopped. debug-checkpoint = [] # NOTE: chart auto-tracing in hsmc 0.4 emits `__chart_observe!` calls # whose defmt arm is gated on `#[cfg(feature = "trace-defmt")]`. That # cfg is evaluated against THIS crate (proc-macro cfg quirk above), so # every board feature includes `trace-defmt` to keep the arm live. The # `trace;` keyword in `statechart!` blocks is deprecated in 0.4 and # no longer gates emission. Whether trace lines actually emit at # runtime is still controlled by defmt's standard compile-time level # filter (`DEFMT_LOG` env var) -- release builds with `DEFMT_LOG` # unset compile the calls out to nothing. # When enabled, the SH1106 OLED driver emits a defmt::info! line for # every I2C transaction it issues — bytes, lengths, addresses. Used to # debug the embassy_nrf::twim assertion panic at twim.rs:541 (cannot # happen via the documented call path; instrumenting the SH1106 path # captures the actual transaction sequence preceding the panic so we # can root-cause). Off by default; opt in via # `just flash-attach rak_wisblock_4631 debug-twim`. debug-twim = [] heltec_v3 = [ "embassy", "trace-defmt", "dep:esp-backtrace", "dep:esp-bootloader-esp-idf", "dep:esp-hal", "dep:esp-println", "dep:esp-rtos", "esp-backtrace/esp32s3", "esp-bootloader-esp-idf/esp32s3", "esp-hal/esp32s3", "esp-println/esp32s3", "esp-rtos/esp32s3", ] heltec_v3_uart = [ "embassy", "trace-defmt", "dep:esp-backtrace", "dep:esp-bootloader-esp-idf", "dep:esp-hal", "dep:esp-println", "dep:esp-rtos", "esp-backtrace/esp32s3", "esp-bootloader-esp-idf/esp32s3", "esp-hal/esp32s3", "esp-println/esp32s3", "esp-rtos/esp32s3", ] heltec_v4 = [ "embassy", "trace-defmt", "dep:esp-backtrace", "dep:esp-bootloader-esp-idf", "dep:esp-hal", "dep:esp-println", "dep:esp-rtos", "esp-backtrace/esp32s3", "esp-bootloader-esp-idf/esp32s3", "esp-hal/esp32s3", "esp-println/esp32s3", "esp-rtos/esp32s3", ] elecrow_thinknode_m2 = [ "embassy", "trace-defmt", "dep:esp-backtrace", "dep:esp-bootloader-esp-idf", "dep:esp-hal", "dep:esp-println", "dep:esp-rtos", "esp-backtrace/esp32s3", "esp-bootloader-esp-idf/esp32s3", "esp-hal/esp32s3", "esp-println/esp32s3", "esp-rtos/esp32s3", ] lilygo_tbeam_supreme = [ "embassy", "trace-defmt", "dep:esp-backtrace", "dep:esp-bootloader-esp-idf", "dep:esp-hal", "dep:esp-println", "dep:esp-rtos", "esp-backtrace/esp32s3", "esp-bootloader-esp-idf/esp32s3", "esp-hal/esp32s3", "esp-println/esp32s3", "esp-rtos/esp32s3", ] lilygo_tbeam = [ "embassy", "trace-defmt", "dep:esp-backtrace", "dep:esp-bootloader-esp-idf", "dep:esp-hal", "dep:esp-println", "dep:esp-rtos", "esp-backtrace/esp32", "esp-bootloader-esp-idf/esp32", "esp-hal/esp32", "esp-println/esp32", "esp-rtos/esp32", ] rak_wisblock_4631 = [ "embassy", "trace-defmt", "dep:cortex-m", "dep:cortex-m-rt", "cortex-m-rt/set-vtor", "dep:defmt-rtt", "dep:embassy-nrf", "dep:panic-probe", "embassy-executor/platform-cortex-m", "embassy-executor/executor-thread", ] wio_tracker_l1 = [ "embassy", "trace-defmt", "dep:cortex-m", "dep:cortex-m-rt", "cortex-m-rt/set-vtor", "dep:defmt-rtt", "dep:embassy-nrf", "dep:panic-probe", "embassy-executor/platform-cortex-m", "embassy-executor/executor-thread", ] heltec_mesh_node_t114 = [ "embassy", "trace-defmt", "dep:cortex-m", "dep:cortex-m-rt", "cortex-m-rt/set-vtor", "dep:defmt-rtt", "dep:embassy-nrf", "dep:panic-probe", "dep:lcd-async", "dep:embedded-hal-bus", "embassy-executor/platform-cortex-m", "embassy-executor/executor-thread", ] waveshare_rp2040_lora = [ "embassy", "trace-defmt", "dep:cortex-m", "dep:cortex-m-rt", "dep:defmt-rtt", "dep:embassy-rp", "dep:panic-probe", "embassy-executor/platform-cortex-m", "embassy-executor/executor-thread", ] [lints.rust] # hsmc 0.3's `statechart!` macro emits `#[cfg(feature = "journal")]` # attributes (and others). check-cfg evaluates those in the CALLER's # crate context, so unless donglora declares the same feature names # (we don't — they're hsmc's, not ours), rustc lints them. Per hsmc's # README, the documented fix is to allow the lint with an explicit # check-cfg list so other unexpected cfgs still surface as warnings. unexpected_cfgs = { level = "allow", check-cfg = [ 'cfg(feature, values("tokio", "embassy", "journal", "trace-defmt", "trace-log", "trace-tracing"))', ] } [lints.clippy] undocumented_unsafe_blocks = "deny" [profile.release] codegen-units = 1 lto = "fat" opt-level = 3 # "s"/"z" break Xtensa (l32r literal range exceeded) panic = "abort" # `strip = true` was killing defmt's `_defmt_version_` / `_defmt_encoding_` # symbols, breaking RTT log decoding via probe-rs. Keep symbols + DWARF # so probe-rs can show source locations for log lines. strip = false debug = 2