From 6485f277b509939835d007dce1151e2f259a8595 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Martin?= Date: Mon, 5 Oct 2026 18:44:25 +0200 Subject: [PATCH] M3 plan: radio bring-up, receive only (Q89-Q104) The Radio Service owns the SX1262 and shares the SPI bus with the card; the LoRa Scanner shows packets (Sniffer) and the band (Sweep). Nothing in M3 can transmit. Notes and the File Browser move to issues #19 and #3. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01EhqxQ49eCju4CzKYNjZzwT --- CONTEXT.md | 5 +++++ docs/milestones/M3.md | 51 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 56 insertions(+) create mode 100644 docs/milestones/M3.md diff --git a/CONTEXT.md b/CONTEXT.md index de4b688..a6c083b 100644 --- a/CONTEXT.md +++ b/CONTEXT.md @@ -20,6 +20,10 @@ _Avoid_: daemon, task, driver The Service that keeps the device participating in a mesh network at all times: receiving, relaying, and sending on behalf of Apps. _Avoid_: radio, LoRa app +**Radio Service**: +The Service that owns the LoRa radio on the Cap: it configures it, shares the SPI bus with the SD card, and receives in the background. The LoRa Scanner uses it directly; the Mesh Service sits on top of it. +_Avoid_: LoRa driver, modem + **Mesh Protocol**: One on-air language the Mesh Service can speak (Meshtastic first; others may follow). The Mesh Service speaks Mesh Protocols; Apps don't. _Avoid_: stack, mode @@ -159,6 +163,7 @@ _Avoid_: telnet, remote shell - The **Mesh Service** speaks one or more **Mesh Protocols** and tracks the known **Nodes**. - The **Wi-Fi Service** is either Connected or Monitoring, never both. Monitoring pauses the **IRC Service**, which reconnects and rejoins its **Buffers** afterwards. - **Services** raise **Notifications**; the **Status Bar** summarises **Service** state. +- The **Radio Service** owns the radio; the **Mesh Service** and the LoRa Scanner use it. - A **Sweep** pauses the **Mesh Service**; a **Sniffer** does not. - Every transmission is bounded by the **Region** and its **Duty Cycle Budget**. - Past 90% SD usage, **Logs** stop being written; the remaining space is kept for **Captures**. Nothing is deleted without the user's confirmation. diff --git a/docs/milestones/M3.md b/docs/milestones/M3.md new file mode 100644 index 0000000..ca3d8f7 --- /dev/null +++ b/docs/milestones/M3.md @@ -0,0 +1,51 @@ +# M3 — Radio bring-up: the LoRa Scanner + +**Status:** planned (branch `m3`). + +**Goal:** the LoRa radio on the Cap works, receive only: a Radio Service owns it and shares the SPI bus with the SD card safely, and a LoRa Scanner App shows what's on the air, either packets (Sniffer) or energy across the band (Sweep). Nothing in M3 can transmit. The mesh comes on top of this in M4 (receive) and M5 (transmit). + +**Hardware:** the Cap LoRa-1262 carries an SX1262 (868–923 MHz, +22 dBm) with an RP-SMA antenna. Pins, as in Meshtastic's board file for the Cardputer ADV: **NSS 5, RST 3, DIO1 (IRQ) 4, BUSY 6**, on the SPI bus shared with the microSD card (SCK 40, MISO 39, MOSI 14; card CS 12). Meshtastic uses DIO2 as the RF switch and DIO3 for a 1.8 V TCXO, marked optional. M5Stack's page adds an FM8625H antenna switch enabled by P0 of a PI4IOE5V6408 I/O expander on the internal I2C bus, address not given; Meshtastic doesn't mention it. Step 1 measures which is true. + +**No other LoRa device yet.** meshmap.net (2026-10-05) lists two Meshtastic nodes within 10 km of the desk and six within 30 km, with positions blurred by a few km; none is known to be in range. M3 needs none: it only receives. + +## Decisions (design round 2026-10-05) + +| # | Decision | +|---|---| +| Q89 | **M3 is the radio only:** Radio Service, Sniffer, Sweep. Notes and the File Browser (Q30) move out to issue #3 and a Notes issue, as a later side milestone. | +| Q90 | **RadioLib**, pinned (ADR 0001). SX1262 on NSS 5, RST 3, DIO1 4, BUSY 6; DIO2 as RF switch; TCXO at 1.8 V tried first, falling back to the crystal (Meshtastic's `TCXO_OPTIONAL`). | +| Q91 | Step 1 is `lora probe`: chip status and version, which oscillator setting worked, and an I2C scan of the internal bus for the PI4IOE5V6408. If present, its P0 is set high at boot (harmless) and DIO2 stays the switch. A wrong switch receives deaf, so compare noise floors. | +| Q92 | A **Radio Service** owns the SX1262: driver, bus lock, IRQ task. The LoRa Scanner uses it in M3; the Mesh Service sits on top of it in M4. | +| Q93 | Every radio transfer takes the shared bus lock (`SPI.beginTransaction`, as the card does). DIO1's interrupt only wakes the task; no SPI in the ISR. **Done when** a Gemini page streams to the card while the Sniffer receives, with no lost packets and no card errors (`lora status` counters). | +| Q94 | **Receive only:** the Radio Service has no transmit function in M3. It doesn't exist, rather than being unused. | +| Q95 | Sniffer defaults: **EU868 LongFast**, 869.525 MHz, BW 250 kHz, SF 11, CR 4/5, sync word 0x2B, preamble 16 (Q19). The other Meshtastic presets are offered, plus custom settings. | +| Q96 | The Sniffer lists packets (time, RSSI, SNR, frequency error, length; hex dump on Enter) **and decodes the Meshtastic header**: the first 16 bytes are never encrypted (destination, sender, packet ID, hop limit and hop start, channel hash, next hop, relay node). Host-tested. Payload decryption is M4. | +| Q97 | A Sniffer **Capture** is pcap with **LoRaTap** headers (link type 270), for Wireshark. Started by hand, Status Bar mark, its own Clean-up category, the 90% rule. | +| Q98 | **Sweep** steps across the Region's band (863–870 MHz) in 100 kHz steps by default, reading instant RSSI: bars with peak hold, and a waterfall, Wi-Fi Tools style. Optionally CAD on the preset's frequency to tell LoRa traffic from noise. | +| Q99 | Sweep takes the radio and pauses the Sniffer, visibly (Q18). From M4 it pauses the Mesh Service the same way. | +| Q100 | The Sniffer runs while the App is open **or a Capture is recording**; otherwise the radio sleeps. From M4 the Mesh Service keeps it on. | +| Q101 | **Status Bar:** a radio mark while receiving, flashing on each packet; muted during a Sweep. | +| Q102 | Debug aids: `lora status` (settings, counters, last RSSI/SNR, noise floor), `lora probe`, `lora rx on/off` (packets on the consoles). Raw packets are never written to the card outside a Capture. | +| Q103 | A ring of the **last 32 packets** in RAM (about 9 KB at full length); older ones are dropped unless capturing. IRQ task stack trimmed by measurement; RadioLib's flash and RAM measured in step 1 against the floors. | +| Q104 | **Done when** (below) includes an hour of listening on LongFast by a window. Real packets heard become M4 test fixtures. If none are heard, M3 still closes, and a reference Meshtastic node (Q21) becomes a requirement for M4. | + +## Done when + +- `lora probe` reports the SX1262, its oscillator setting and the RF switch arrangement, and the result is written here. +- The Sniffer receives on LongFast with the App open or a Capture running, and the radio sleeps otherwise. +- Sweep shows the noise floor across 863–870 MHz, and a known signal (a remote key fob, a 868 MHz sensor, anything) stands out. +- The shared-bus test passes (Q93): a Gemini page to the card while the Sniffer receives, no lost packets, no card errors. +- A Capture opens in Wireshark with LoRaTap fields. +- The Status Bar mark follows Q101. +- One hour of LongFast listening by a window has been run and its result recorded here. +- Free heap stays above the floors (Q86) with the Sniffer, Wi-Fi, IRC on TLS and the UI running. +- Nothing in the firmware can transmit. + +## Work breakdown + +1. **Hardware check:** RadioLib in the build, `lora probe` (Q91), flash and RAM cost measured. +2. **Meshtastic header and LoRaTap** (host-tested): header parsing, presets and their radio settings, pcap/LoRaTap writing. +3. **Radio Service:** receive on its own task behind the bus lock, the packet ring, `lora status` and `lora rx`, the shared-bus test. +4. **LoRa Scanner App, Sniffer:** the packet list, details, preset choice, Captures, Status Bar mark. +5. **Sweep:** the RSSI sweep, bars and waterfall, pausing the Sniffer. +6. **Listening hour** and the measurements above, recorded here.