config.h 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102
  1. // config.h -- USB-presentation modes + persisted, runtime-tunable settings.
  2. //
  3. // One puck speaks the SAME RF protocol no matter which USB face it wears; only the USB enumeration and the
  4. // input-report mapping change. The active face is g_usbMode, persisted to flash (cfg.bin). Tunables here
  5. // (mouse sensitivity, back-paddle mapping, A/B swap, chord assignments, QoS) are set over the CDC console
  6. // (serial_console.cpp) and the WebUSB panel (webusb_config.cpp) and likewise persist.
  7. #pragma once
  8. #include <stdint.h>
  9. // ---- Compile-time logging / diagnostics ----
  10. // 0 (default) = PRODUCTION build: no host->controller capture ring (reclaims ~80KB RAM), no per-event
  11. // logging, no main-loop section timing, no WebUSB capture channel. The functional bits (haptic reconnect
  12. // block, the buzz-clear re-init, rate stats) stay. Build the diagnostic firmware with -DOPK_LOG=1.
  13. // The WebUSB panel reads this back in the status blob and hides its logging UI when it's 0.
  14. #ifndef OPK_LOG
  15. #define OPK_LOG 0
  16. #endif
  17. // Build-time FACTORY RESET (recovery build). 0 (default) = normal. Build with -DOPK_FACTORY_RESET=1 to produce a
  18. // firmware that wipes ALL persistent storage (cfg.bin + bonds.bin) ONCE -- on the first boot after flashing --
  19. // then behaves exactly like a normal build that persists settings. It is NOT a wipe-every-boot image: a git-hash
  20. // tag file (written after the wipe) records that this build already did its one-time reset, so subsequent boots
  21. // skip it. This makes it a safe recovery image for a bad config/bond: flash it, boot once (cleaned), keep using
  22. // it. Flashing a DIFFERENT build re-triggers the one-time wipe; for an on-demand wipe use the serial "ERASE-ALL"
  23. // or WebUSB "Factory erase". Re-pair the controller after the reset. See factoryResetOnce() in config.cpp.
  24. #ifndef OPK_FACTORY_RESET
  25. #define OPK_FACTORY_RESET 0
  26. #endif
  27. // ---- USB presentation modes (g_usbMode). RF poll/relay is identical across all; only USB enumeration +
  28. // report mapping differ. ----
  29. #define MODE_STEAM 0 // Valve puck; auto-lizard when Steam closed
  30. #define MODE_XBOX 1 // XInput + right-pad mouse
  31. #define MODE_SW_HORI 2 // HORIPAD (Switch console whitelist)
  32. #define MODE_LIZARD 3 // Puck HID; always keyboard+mouse (ignores Steam heartbeat)
  33. #define MODE_SW_PRO 4 // Nintendo Switch Pro Controller (057E:2009) + gyro
  34. #define MODE_PS5 5 // Sony DualSense (054C:0CE6) + gyro + split trackpad (+ wake mouse + WebUSB panel)
  35. #define MODE_HIDGYRO 6 // DS4-layout generic HID gamepad + gyro (+ wake mouse + WebUSB panel)
  36. #define MODE_PS5_GAME 7 // DualSense, CLEAN single-HID (no wake/WebUSB) so PC games classify it as PlayStation (Fortnite)
  37. #define MODE_DS4_GAME 8 // DS4, CLEAN single-HID (no wake/WebUSB) for game PlayStation classification
  38. #define MODE_MAX 8
  39. // The two "game" personalities drop the wake-mouse + WebUSB interfaces so the device is a genuine single-HID PS
  40. // controller (some PC games -- e.g. Fortnite/UE GameInput -- refuse PS classification when extra interfaces are
  41. // present). Cost: no config panel / host-wake while in these modes; chord back to Steam (back4 + A) for the panel.
  42. static inline bool modeIsCleanPS(uint8_t m){ return m==MODE_PS5_GAME || m==MODE_DS4_GAME; }
  43. static inline bool modeIsPuck(uint8_t m){ return m==MODE_STEAM || m==MODE_LIZARD; }
  44. static inline bool modeValid(uint8_t m){ return m<=MODE_MAX; }
  45. extern uint8_t g_usbMode; // loaded from flash at boot
  46. extern bool g_xbox; // true for all non-puck presentations (cached !modeIsPuck(g_usbMode))
  47. extern uint8_t g_chordBtn[3]; // back4+B/X/Y -> these modes (A always STEAM)
  48. // Mode persistence policy: by DEFAULT every fresh power-on/reconnect lands in STEAM mode (0). An explicit
  49. // mode switch still works for the session via a ONE-SHOT bootMode (honored once, then cleared, so the next
  50. // cold boot reverts to Steam). The WebUI "persist last mode" toggle (g_persistMode) instead remembers the
  51. // last selected mode across reboots.
  52. extern bool g_persistMode; // false (default) = always boot Steam; true = boot into last mode
  53. extern uint8_t g_bootMode; // one-shot: boot into this mode once then clear (!persistMode + explicit switch)
  54. // One-shot debug CDC. Puck mode normally DROPS the CDC serial console to free the USB endpoint its wake-mouse
  55. // interface needs (so puck can wake a sleeping Windows host). Arming this keeps CDC for the NEXT boot only --
  56. // dropping the wake mouse that boot -- so someone can attach the serial debugger; the boot after reverts to
  57. // normal automatically. Mirrors the g_bootMode one-shot. Armed from the WebUSB panel or CDC 'D' command.
  58. extern bool g_debugCdcThisBoot; // decision for THIS boot: true => keep CDC, skip the wake interface
  59. void armDebugCdcNextBoot(); // persist the one-shot (caller reboots)
  60. // persisted, runtime-tunable config:
  61. extern int g_mDiv, g_mFric; // xbox/lizard mouse sensitivity divisor / friction%
  62. extern uint8_t g_abSwap; // 1 = swap A/B and X/Y (Nintendo face-button layout)
  63. extern uint8_t g_back[4]; // back paddles L4,R4,L5,R5 -> button codes (0..15 standard, 16=PS Touch Click, 17=PS5 Mute)
  64. extern uint8_t g_qamMap; // QAM (3 dots) physical button -> same code space (0 = default/unmapped)
  65. extern uint8_t g_rumbleScale; // rumble strength, percent of decoded amplitude (100 = 1x, 200 = 2x default), all modes
  66. // Switch Pro motion settings. Persisted in their OWN flash file (mode_switch_pro.cpp), NOT in Cfg -- so changing
  67. // them never resets the rest of the config. Set from the WebUSB panel.
  68. extern uint8_t g_swProRate; // Switch Pro report cadence: 0 = 66Hz (15ms, compat), 1 = 120Hz (8ms, DEFAULT), 2 = full (~250Hz)
  69. extern uint8_t g_swGyroScale10; // Switch Pro gyro sensitivity x10 (10 = 1.0x default; 5/15/20/25/30 = 0.5..3.0x)
  70. void swProSaveCfg(); // persist g_swProRate + g_swGyroScale10 to their flash file
  71. #define POLL_US_DEFAULT 4000u // 250 Hz -- matches SC2 input report rate (1000000/250 = 4000 us)
  72. #define USB_STREAM_MS 4u // host-side HID stream cadence for translated modes (~250 Hz)
  73. extern const uint32_t g_pollUs; // RF poll cadence (us). FIXED -- not configurable (see loadCfg).
  74. // loop-timing diagnostics (defined in OpenPuck.ino) -- surfaced in the WebUSB status blob to find what caps
  75. // the poll rate: avg loop period, slowest section index, and that section's avg us/iteration.
  76. extern uint16_t g_loopPeriodUs;
  77. extern uint8_t g_loopWorst;
  78. extern uint16_t g_loopWorstUs;
  79. void loadCfg();
  80. void saveCfg();
  81. // FULL factory wipe: reformat the internal LittleFS, erasing cfg.bin (modes/tunables/chords) AND bonds.bin
  82. // (paired controller). Irreversible; the caller reboots so the next boot comes up on clean defaults and the
  83. // controller must be re-paired. Gated behind explicit confirmation at every call site.
  84. void factoryErase();
  85. // One-time factory reset for the -DOPK_FACTORY_RESET recovery build: wipe ONCE on the first boot after flashing
  86. // (tracked by a git-hash tag file so it doesn't wipe on every boot), then persist normally. buildTag = OPK_GIT_HASH.
  87. void factoryResetOnce(const char* buildTag);
  88. // Mode switch (chord / WebUI): persist mode if the toggle is on, else arm a one-shot so this reboot lands in
  89. // the new mode but the next cold boot returns to Steam. Either way saveCfg + caller reboots.
  90. void saveMode(uint8_t m);