radio.cpp 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111
  1. #include "radio.h"
  2. // Pairing rendezvous bytes from IBEX rodata. The 0x91A2A793 key preceding "ibex" is a DIFFERENT key,
  3. // NOT the discovery address.
  4. const uint8_t PAIR_BASE[4] = { 0x69, 0x62, 0x65, 0x78 }; // "ibex"
  5. uint8_t g_rfPrefix = 0x10;
  6. uint8_t g_rfCh = 2;
  7. uint8_t g_rfBase[4] = { 0x69, 0x62, 0x65, 0x78 }; // "ibex"
  8. // ch18: clean channel in the real puck's active hop set {18,2,80}; bad channels collide with trackpad
  9. // data bursts -> reply-rate crash. Tunable 'C'.
  10. uint8_t g_sessCh = 18;
  11. // Safe default; rfGenSessionAddr() overwrites with the per-device value at boot.
  12. uint8_t g_sessBase[4] = { 0x69, 0x62, 0x65, 0x78 };
  13. uint8_t g_sessPrefix = 0x10;
  14. void rfGenSessionAddr()
  15. {
  16. // Mix the 64-bit FICR DEVICEID into a 4-byte base + prefix: deterministic per chip, unique across chips
  17. // -> two OpenPucks never collide on the connected session. Avoid degenerate address bytes (0x00/0xFF) for
  18. // clean preamble correlation, and never reproduce the shared discovery base "ibex" (else isolation is lost).
  19. uint32_t h = NRF_FICR->DEVICEID[0] * 0x9E3779B1u ^
  20. NRF_FICR->DEVICEID[1];
  21. uint32_t h2 = NRF_FICR->DEVICEID[1] * 0x85EBCA6Bu ^
  22. NRF_FICR->DEVICEID[0];
  23. for (int i = 0; i < 4; i++) {
  24. uint8_t b = (uint8_t)(h >> (i * 8));
  25. if (b == 0x00 || b == 0xFF)
  26. b ^= 0x5A;
  27. g_sessBase[i] = b;
  28. }
  29. uint8_t p = (uint8_t)(h2 >> 16);
  30. if (p == 0x00 || p == 0xFF)
  31. p = 0x5C;
  32. g_sessPrefix = p;
  33. if (g_sessBase[0] == g_rfBase[0] && g_sessBase[1] == g_rfBase[1] &&
  34. g_sessBase[2] == g_rfBase[2] && g_sessBase[3] == g_rfBase[3])
  35. g_sessBase[0] ^= 0x80; // collided with discovery base "ibex"
  36. }
  37. uint8_t rfrx[100], rftx[100];
  38. uint32_t g_rfRxCount = 0;
  39. // Puck-link config decoded from real-puck capture: puck TX = Ble_2Mbit, ENDIAN=Big (MSB-first), NO whitening,
  40. // addr "ibex", CRC16 0x11021/0xFFFF; static-length frame.
  41. uint32_t g_crcinit = 0xFFFF;
  42. uint8_t g_whiteiv = 37;
  43. uint8_t g_mode = RADIO_MODE_MODE_Ble_2Mbit;
  44. // S0LEN0, LFLEN8, S1LEN3 (ESB DPL) - CRC-VALIDATED
  45. uint32_t g_pcnf0 = 0x00030008UL;
  46. uint8_t g_statlen = 0x20;
  47. // ENDIAN=Big, BALEN4, MAXLEN=96. MAXLEN must be >=66 or the controller's 0x43-battery-augmented F1 (66B)
  48. // truncates -> CRC-fail -> battery never arrives.
  49. uint32_t g_pcnf1 = 0x01040060;
  50. uint32_t g_crcpoly = 0x11021UL;
  51. uint16_t g_crccnf = 0x2; // CRC16, address included
  52. uint8_t g_pid = 0;
  53. uint8_t g_balen = 4; // ESB 5-byte addr
  54. bool g_prefixRaw = false;
  55. uint8_t rfBitrev8(uint8_t x)
  56. {
  57. uint8_t y = 0;
  58. for (int i = 0; i < 8; i++) {
  59. y = (y << 1) | (x & 1);
  60. x >>= 1;
  61. }
  62. return y;
  63. }
  64. void rfSetAddr(const uint8_t b4[4], uint8_t prefix)
  65. {
  66. uint8_t b[4];
  67. for (int i = 0; i < 4; i++)
  68. b[i] = rfBitrev8(b4[i]);
  69. NRF_RADIO->BASE0 = ((uint32_t)b[0] << 24) | ((uint32_t)b[1] << 16) |
  70. ((uint32_t)b[2] << 8) | b[3];
  71. NRF_RADIO->PREFIX0 = g_prefixRaw ? prefix : rfBitrev8(prefix);
  72. NRF_RADIO->TXADDRESS = 0;
  73. NRF_RADIO->RXADDRESSES = 1u << 0;
  74. }
  75. void rfConfig(uint8_t ch)
  76. {
  77. NRF_RADIO->TASKS_DISABLE = 1;
  78. RWAIT_DISABLED();
  79. NRF_RADIO->EVENTS_DISABLED = 0;
  80. NRF_RADIO->MODE = ((uint32_t)g_mode << RADIO_MODE_MODE_Pos);
  81. NRF_RADIO->FREQUENCY = ch;
  82. NRF_RADIO->TXPOWER =
  83. (RADIO_TXPOWER_TXPOWER_0dBm << RADIO_TXPOWER_TXPOWER_Pos);
  84. #if defined(RADIO_MODECNF0_RU_Fast)
  85. NRF_RADIO->MODECNF0 = (RADIO_MODECNF0_RU_Fast << RADIO_MODECNF0_RU_Pos);
  86. #endif
  87. NRF_RADIO->PCNF0 = g_pcnf0;
  88. // g_pcnf1=0 -> build static-length config from g_statlen/g_balen (ENDIAN=Big, WHITEEN=0)
  89. NRF_RADIO->PCNF1 =
  90. g_pcnf1 ? g_pcnf1 :
  91. ((1u << RADIO_PCNF1_ENDIAN_Pos) |
  92. ((uint32_t)g_balen << RADIO_PCNF1_BALEN_Pos) |
  93. ((uint32_t)g_statlen << RADIO_PCNF1_STATLEN_Pos) |
  94. ((uint32_t)g_statlen << RADIO_PCNF1_MAXLEN_Pos));
  95. NRF_RADIO->CRCCNF = g_crccnf; // CRC16, address included
  96. NRF_RADIO->CRCPOLY = g_crcpoly;
  97. NRF_RADIO->CRCINIT = g_crcinit;
  98. NRF_RADIO->DATAWHITEIV = g_whiteiv;
  99. NRF_RADIO->PACKETPTR = (uint32_t)rfrx;
  100. }