controllers.h 3.9 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394
  1. // controllers.h -- the emulated-USB-controller abstraction.
  2. //
  3. // Each USB personality (Steam puck, Xbox/XInput, Switch HORIPAD, Switch Pro, PS5 DualSense, DS4 gyro) is an
  4. // IController living in its own mode_*.cpp. Exactly ONE is active per boot, selected by g_usbMode. Methods:
  5. // begin() -- called once from setup(): set the USB VID/PID/strings and register this mode's
  6. // interface(s). Shared USB lifecycle (detach, clear/keep CDC, serial suffix, WebUSB,
  7. // attach) stays in setup(); begin() only adds what's specific to this controller.
  8. // onReport45() -- called from rf_link.cpp each time a controller input report 0x45 is decoded. The `slot`
  9. // argument is the bond slot the report arrived on (0..NSLOT-1, or -1 for the pre-bond
  10. // catch-all). PUSH-style modes (Xbox, puck/lizard) build + send their host report here;
  11. // the puck/lizard mode uses `slot` to fan out to hid[slot]. STREAM-style modes ignore
  12. // `slot`; STREAM-style modes emit at a fixed cadence from task() reading g_in[s].
  13. // task() -- called every loop(): streaming emit, handshake/subcommand draining, mode-specific upkeep.
  14. // isPuck() -- true for Steam/Lizard (keep the boot CDC composite; different USB lifecycle in setup()).
  15. //
  16. // To add a new controller: implement IController in a new mode_*.cpp, give it a singleton, and wire it into
  17. // controllerFor() in controllers.cpp.
  18. #pragma once
  19. #include <stdint.h>
  20. class IController {
  21. public:
  22. virtual ~IController()
  23. {
  24. }
  25. virtual void begin() = 0;
  26. virtual void onReport45(int slot, const uint8_t *rep, bool fresh,
  27. uint8_t bodyTlen)
  28. {
  29. (void)slot;
  30. (void)rep;
  31. (void)fresh;
  32. (void)bodyTlen;
  33. }
  34. // Other controller->host input reports decoded from the F1 reply (NOT 0x45): power/battery status report
  35. // 0x43, status event 0x44. The real puck forwards these to Steam verbatim -- that's how Steam reads battery.
  36. // rid = report id, data/n = body after the id. Default no-op (clean modes don't expose these reports).
  37. virtual void onAuxReport(int slot, uint8_t rid, const uint8_t *data,
  38. uint8_t n)
  39. {
  40. (void)slot;
  41. (void)rid;
  42. (void)data;
  43. (void)n;
  44. }
  45. virtual void task()
  46. {
  47. }
  48. // a wake gesture fired while suspended; queue any post-resume input the host needs to actually wake
  49. virtual void wakeEvent()
  50. {
  51. }
  52. virtual bool isPuck() const
  53. {
  54. return false;
  55. }
  56. // ---- Dynamic USB mounting (see usb_mount.h). Emulated modes that present only CONNECTED controllers
  57. // override these; the defaults keep the legacy "begin() mounts everything" behavior for puck/lizard
  58. // and any not-yet-converted mode. ----
  59. // true => this mode uses the dynamic mount/unmount path (usbReenumerate driven by the connectivity watcher)
  60. // rather than registering its slot interfaces in begin(). maxSlots() then caps the mounted count.
  61. virtual bool dynamicMount() const
  62. {
  63. return false;
  64. }
  65. // HID-instance budget for slot interfaces (CFG_TUD_HID minus any fixed HID like the wake mouse).
  66. virtual uint8_t maxSlots() const
  67. {
  68. return 0;
  69. }
  70. // Re-apply this mode's USB identity (VID/PID, manufacturer/product strings, bcdDevice). Called by
  71. // usbReenumerate after clearConfiguration (which resets them). begin() also calls it.
  72. virtual void usbIdentity()
  73. {
  74. }
  75. // One-time at boot: create the slot interface/HID object pool and lock their TinyUSB instance indices
  76. // (begin() each). Adds them to the throwaway descriptor; usbReenumerate then presents the live prefix.
  77. virtual void beginPool()
  78. {
  79. }
  80. // (Re)add the first k slot interfaces (a dense prefix of the pool) to the freshly-cleared config descriptor.
  81. virtual void mountSlots(uint8_t k)
  82. {
  83. (void)k;
  84. }
  85. };
  86. // The singleton for a given mode (nullptr if the mode is unknown). Defined in controllers.cpp.
  87. IController *controllerFor(uint8_t mode);
  88. // The active controller for this boot (set in setup()). rf_link/loop dispatch through it.
  89. extern IController *g_active;