feat: real XBee SPI transport and local AT commands (PR 8/10) - #43
Merged
Merged
Conversation
First functional radio link: replaces the XbeeControl stub from PR 7 with a real implementation talking to the XBee3 over SPI, and splits this PR out of the original PR 8 (transport + packet protocol) per the rewrite plan's own contingency — this alone is big enough on its own. The custom uplink/downlink state-report schema is now PR 9, and the final complications/handedness/shutdown work becomes PR 10. - xbee_frame.h/.cpp: pure XBee API frame logic — checksum compute/ validate, and AT Command (0x08) / AT Command Response (0x88) frame build/parse. Round-trip tested. - xbee_spi.cpp: thin SPI adapter (3MHz/MSB-first/mode 0, ATTN-polled reads) — ported from thePunderWoman/Amidala's proven xbee_spi.cpp read path (same module family), extended with a write path and a blocking AT-command round trip. Excluded from native build/coverage. - xbee_control.cpp: XbeeControl now issues real AT commands (NR/ID/AC) for leave/set-PAN/rejoin, and adds a real SL query for Device Info. Exact AT command sequencing is a best-effort reading of Digi's XBee3 manual, flagged in code for validation against real hardware. Now hardware-dependent, so it joins the native exclusion list. - droid_switcher.h/.cpp: DroidSwitcher (the pure orchestration logic, previously living alongside the now-excluded XbeeControl) moved to its own file so it stays compiled and covered natively — this is what broke the build the first time through and is why it's now separate. menu.h now depends on this instead of xbee_control.h, so the pure menu logic never needs to know XbeeControl/XbeeSpi exist at all. Device Info now shows the module's real SL once XbeeControl queries it at boot, replacing the PR 6 placeholder. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
4 tasks
thePunderWoman
added a commit
that referenced
this pull request
Sep 8, 2026
…44) Adds Snips' own application-level payload format, defined fresh since Amidala has no existing schema for this controller type (tracked as thePunderWoman/Amidala#204) — this was split out of the original PR 8 once that grew large enough on its own (see PR 8, #43). - xbee_frame.h/.cpp gains Transmit Request (0x10) / Receive Packet (0x90) frame build/parse, symmetric to PR 8's AT Command support — generic XBee envelope logic, pure and round-trip tested. Defaults to addressing the coordinator (64-bit 0, 16-bit 0x0000 per Digi's "unknown 64-bit, route by 16-bit" convention) — flagged for real-hardware validation like the rest of this PR's protocol-level assumptions. - packet.h/.cpp: fixed-width, big-endian encode/decode for UplinkPacket (button mask, calibrated trigger/stick, battery %, charge state — 7 bytes) and DownlinkPacket (handedness + Left/Right slot label+value — 33 bytes). Pure, round-trip tested including truncation/padding edge cases on the string fields. - xbee_spi.cpp gains sendPacket()/pollForPacket(), thin wrappers using the new frame types; XbeeControl exposes both as passthroughs so it stays the single facade over the one physical XBee connection. - SnipsController.ino sends the uplink every 50ms (faster than the 1s human-readable Serial telemetry, which stays as a bring-up aid) and polls for downlink packets every tick. Nothing consumes handedness or the Left/Right label+value yet — that's the complications system, PR 10 — so for now a decoded downlink just gets logged to prove the round trip works. Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
PR 8 of the firmware rewrite (PR 1: #35, PR 2: #36, PR 3: #38, PR 4: #39, PR 5: #40, PR 6: #41, PR 7: #42). First functional radio link.
Splits the original plan's PR 8 ("XBee SPI transport + packet protocol") into two, per the plan's own explicit contingency to do so if it got unwieldy — it did. This PR is the transport half; the custom uplink/downlink state-report schema becomes PR 9, and the final complications/handedness/shutdown work becomes PR 10.
xbee_frame.h/.cpp: pure XBee API frame logic — checksum compute/validate, and AT Command (0x08) / AT Command Response (0x88) frame build/parse. Round-trip tested.xbee_spi.cpp: thin SPI adapter (3MHz/MSB-first/mode 0, ATTN-polled reads) — ported fromthePunderWoman/Amidala's provenxbee_spi.cppread path (same XBee3 module family), extended with a write path and a blocking AT-command round trip. Excluded from native build/coverage.xbee_control.cpp:XbeeControlnow issues real AT commands (NR/ID/AC) for leave/set-PAN/rejoin instead of stubbing them out, and adds a realSLquery for Device Info. Exact AT command sequencing is a best-effort reading of Digi's XBee3 manual, flagged in code as needing validation against real hardware. Now hardware-dependent, so it joins the native exclusion list.droid_switcher.h/.cpp:DroidSwitcher(the pure orchestration logic, previously living alongsideXbeeControl) moved to its own file so it stays compiled and covered natively even thoughXbeeControlitself is now excluded — this is what broke the build the first time through this PR, and is why it's a separate file now.menu.hdepends on this instead ofxbee_control.h, so the pure menu logic never needs to knowXbeeControl/XbeeSpiexist.SL, queried once at boot, replacing PR 6's placeholder.Test plan
pio test -e native— all 149 test cases passgcovr --exclude 'src/SnipsController\.ino' --exclude 'src/oled\.cpp' --exclude 'src/rgb_led\.cpp' --exclude 'src/calibration_store\.cpp' --exclude 'src/droid_persistence\.cpp' --exclude 'src/xbee_spi\.cpp' --exclude 'src/xbee_control\.cpp' --fail-under-line 90— 98.4% line coveragepio run -e esp32s3— builds successfullyAP=1— required, SPI is dead in transparent mode): confirm Device Info shows a real, correctly-formattedSL; confirm Switch Droid's leave/set-PAN/rejoin sequence actually works end to end (this is the part most likely to need adjusting — see the sequencing caveat inxbee_control.cpp)🤖 Generated with Claude Code