rf_link.h 4.1 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061
  1. // rf_link.h -- the operational puck<->controller RF protocol (the "dongle" role).
  2. //
  3. // Built on the radio HW layer (radio.cpp), this is what makes the device act as a puck once a controller is
  4. // bonded: it transmits the host frame the bonded controller reconnects on, runs the connected-mode poll loop
  5. // (E7 awake announce -> E3 + GET-report-0x45 each cycle), and decodes the controller's 0xF1 input reply. The
  6. // decode fills the shared g_in (triton.h) and dispatches to the active IController; it also handles the
  7. // mode-switch chord, USB remote-wakeup on a Steam short-press, adaptive channel hopping (QoS), and the
  8. // host-frame keepalive beacons. RE/calibration scaffolding lives separately in rf_diag.cpp.
  9. //
  10. // RECIPE (IBEX disasm @0x18d80): the controller streams 0xF1 ONLY when (a) connstate==3 [host frame E1
  11. // establishes it], (b) we mark host-awake via E7 [00][00], and (c) each E3 poll carries a GET-report-0x45
  12. // sub-TLV. F1 reply = type 0xF1 then TLV type4(analog/buttons)+type6(per-module gyro/accel/sticks).
  13. #pragma once
  14. #include <stdint.h>
  15. // ---- operational toggles + tunables (set from the CDC console / WebUSB; read here + by webusb status) ----
  16. extern bool g_rfHost; // auto-start host beacon on boot (resumes puck role after a USB replug)
  17. extern bool g_connOn; // auto-start connected-mode poll on boot
  18. extern uint8_t g_connType; // start packet type (E7 handshake, then E3)
  19. extern uint8_t g_e7b; // E7 payload B-byte: 0=current(slow/awake), 1=test protocol-version-1
  20. extern uint8_t g_connLen;
  21. extern uint8_t g_getParam; // GET report 0x45 param byte
  22. extern uint8_t g_e3mode; // E3-poll PID/S1 mode (0=fixed07, 1=cyclePID+noack1, 2=cyclePID+noack0)
  23. extern bool g_connVerbose; // full multi-line debug dump vs compact "I45 <hex>" stream
  24. extern uint32_t g_rxWin; // poll RX-window (us): caps poll rate (~1e6/rxWin)
  25. extern unsigned long g_connCooldown; // set on 0xF2 disconnect; pauses beacon+poll so a powering-off controller can sleep
  26. // connected-mode state (reset by the 'k' console toggle)
  27. extern uint8_t g_connSt, g_connStep;
  28. extern uint16_t g_connPoll;
  29. extern uint32_t g_connF1; // count of 0xF1 input reports seen
  30. extern uint8_t g_connF3v; // last protocol version the controller reported in an F3 reply (0xFF=none)
  31. // QoS adaptive channel hopping
  32. extern uint8_t g_qos; // 0=off (static g_sessCh), 1=auto-hop on degradation
  33. extern uint8_t g_hopIdx;
  34. extern volatile uint16_t g_qosBad;
  35. extern unsigned long g_qosCheckMs, g_qosLastHopMs;
  36. // per-second rate readouts for the WebUSB status blob
  37. extern uint16_t g_f1ps; // last completed second's F1 rate
  38. extern uint16_t g_newps; // genuine new-report rate (report 0x45 seq byte changes)
  39. extern uint16_t g_pollsps; // last second's poll TX count (GET+relay) -- vs F1 tells starvation from reply-loss
  40. extern uint16_t g_pollPeriodUs; // MEASURED avg us between GET-poll fires (compare to the intended g_pollUs=4000)
  41. // Smoothed controller->puck signal strength, sampled by the radio (RSSISAMPLE) on each CRC-good controller
  42. // reply during the poll. Stored as the dBm MAGNITUDE (35 = -35dBm); 0 = no sample yet. puck_hid reports it
  43. // to Steam in status report 0x7B byte 8 (signed dBm), after subtracting RSSI_DBM_OFFSET.
  44. extern volatile uint8_t g_linkRssi;
  45. // dB to subtract from our raw RSSI magnitude before reporting, to match the real puck's close-range -35dBm
  46. // (compensates the Pro Micro antenna vs Valve's front-end). Tune against one known-distance reading.
  47. #define RSSI_DBM_OFFSET 20
  48. // TX one connected packet [LEN][S1][payload] on channel ch, then RX the reply into rfrx; decodes 0xF1.
  49. // rxWinUs overrides the reply-wait window (0 = use g_rxWin). Pass a tiny value for NO-ACK relays that expect
  50. // no reply, so they don't burn a full ~1.2ms window of dead air per haptic.
  51. uint8_t rfConnTx(uint8_t ch, uint8_t s1, const uint8_t* payload, uint8_t plen, uint16_t rxWinUs=0);
  52. // Mid-session channel hop: advertise newCh on the current channel a few times, then move the poll to newCh.
  53. void rfHopTo(uint8_t newCh);
  54. // Per-loop: host-frame beacons + connected-mode poll + remote-wakeup + QoS hop + per-second stats.
  55. void rfLinkTask();