radio.h 3.7 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667
  1. // radio.h -- bare-metal nRF52 RADIO (ESB-style) hardware layer.
  2. //
  3. // Drives the RADIO peripheral directly with NO SoftDevice (BLE is never started), coexisting with TinyUSB.
  4. // Owns the register-level config (PHY/CRC/whitening/address, all live-tunable from the CDC console),
  5. // rfConfig()/rfSetAddr() to program the radio, and the rfrx/rftx DMA buffers. The puck protocol on top lives
  6. // in rf_link.cpp; the RE/calibration tooling in rf_diag.cpp.
  7. //
  8. // Register-confirmed config (decoded from real-puck capture): PHY=Ble_2Mbit, ENDIAN=Big (MSB-first), whitening
  9. // off, addr "ibex", CRC16 poly 0x11021 init 0xFFFF (address included). On-air address = bitrev8 of stored bytes.
  10. #pragma once
  11. #include <stdint.h>
  12. #include <Arduino.h>
  13. // Bounded radio-disable wait: NEVER spin forever. A wedged RADIO would hang the main loop (USB stops being
  14. // serviced -> device "dies" until replug). On timeout we bail; the next rfConfig re-inits the radio.
  15. #define RWAIT_DISABLED() \
  16. do { \
  17. uint32_t _w = micros(); \
  18. while (!NRF_RADIO->EVENTS_DISABLED && \
  19. (uint32_t)(micros() - _w) < 3000) { \
  20. } \
  21. } while (0)
  22. // Discovery/reconnect address (IBEX FUN_00019000, firmware-derived, definitive):
  23. // base = "ibex" (69 62 65 78), prefix = 0x10, channel = 2.
  24. extern const uint8_t PAIR_BASE[4]; // "ibex"
  25. extern uint8_t g_rfPrefix; // discovery prefix (rodata byte @0x56f98)
  26. extern uint8_t g_rfCh; // current TX/RX channel (hopped during beacon/poll)
  27. extern uint8_t g_rfBase[4]; // "ibex"
  28. // connected-session channel: a CLEAN data channel off the congested adv ch2 (shared by all slots on a puck)
  29. extern uint8_t g_sessCh;
  30. // Per-bond SESSION address (base+prefix). Discovery stays on the SHARED "ibex" address (g_rfBase) so any
  31. // controller can find us; the host frame advertises THIS slot's unique address and the controller adopts it
  32. // for the session. Two OpenPucks never share an on-air session address, and two slots on the SAME puck have
  33. // distinct addresses so each controller only hears its own polls -> no crosstalk, no cross-wake, no per-slot
  34. // relay broadcast. Derived from the bond UUID (8 bytes) + FICR DEVICEID (8 bytes) so the address is
  35. // deterministic per (puck, controller) pair and stable across reboots without a bonds.bin schema bump.
  36. #include "bonds.h" // NSLOT
  37. extern uint8_t g_sessBase[NSLOT][4];
  38. extern uint8_t g_sessPrefix[NSLOT];
  39. void rfGenSessionAddr(int slot);
  40. // RADIO DMA buffers (>= MAXLEN+2; the controller's 0x43-augmented F1 is ~66B)
  41. extern uint8_t rfrx[100], rftx[100];
  42. extern uint32_t g_rfRxCount;
  43. // ---- tunable radio parameters (CDC console M/0/2/i/w/I/P/N/T/A) ----
  44. extern uint32_t g_crcinit;
  45. extern uint8_t g_whiteiv;
  46. extern uint8_t g_mode; // RADIO_MODE_MODE_* (real puck = Ble_2Mbit)
  47. extern uint32_t g_pcnf0; // S0LEN0, LFLEN8, S1LEN3 (ESB DPL) -- CRC-VALIDATED
  48. extern uint8_t g_statlen; // static-mode payload length
  49. extern uint32_t g_pcnf1; // ENDIAN=Big, BALEN4, MAXLEN64 -- CRC-VALIDATED
  50. extern uint32_t g_crcpoly;
  51. extern uint16_t g_crccnf; // CRC16, address included
  52. extern uint8_t g_pid;
  53. extern uint8_t g_balen; // ESB 5-byte addr
  54. // false = bitrev8 prefix (ESB addr_conv); true = raw prefix byte
  55. extern bool g_prefixRaw;
  56. uint8_t rfBitrev8(uint8_t x);
  57. // Access address (IBEX FUN_00037530): BASE0 = bitrev8 each base byte packed big-endian; PREFIX0 = raw or
  58. // bitrev8 prefix per g_prefixRaw. "ibex" 69 62 65 78 -> BASE0=0x9646A61E, PREFIX0=0x10.
  59. void rfSetAddr(const uint8_t b4[4], uint8_t prefix);
  60. // Program MODE/FREQUENCY/PCNF/CRC/whitening from the tunables above onto channel ch (radio left disabled).
  61. void rfConfig(uint8_t ch);