triton.h 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106
  1. // triton.h -- the controller's native input as it comes off the RF link, and the decoders for it.
  2. //
  3. // "Triton" is the Steam Controller 2 controller. Its HID input report 0x45 is what the puck relays; rf_link.cpp
  4. // decodes one into the shared g_in struct each fresh frame, and every USB personality reads g_in to build its
  5. // own host report. report 0x45 layout:
  6. // [0]=0x45 [1]=seq [2..5]=buttons u32; analog offsets below are from the buttons low byte (rep[2]).
  7. #pragma once
  8. #include <stdint.h>
  9. #define OPK_TRITON_REPORT_STATE_TIMESTAMP 0x47u
  10. // ---- Triton button masks (the 32-bit field at rep[2..5]) ----
  11. #define TB_A 0x1u
  12. #define TB_B 0x2u
  13. #define TB_X 0x4u
  14. #define TB_Y 0x8u
  15. #define TB_QAM 0x10u
  16. #define TB_R3 0x20u
  17. // TB_VIEW / TB_MENU are named BACKWARDS with respect to the physical buttons: TB_VIEW is the Start-side
  18. // button (Xbox Start / Switch +, Options on PlayStation) and TB_MENU is the Select-side one (Xbox Back /
  19. // Switch -, Create/Share). Every hardware-verified mode maps them that way (mode_xinput, mode_switch_pro,
  20. // psShouldersByte); reading the names literally swaps Start and Select on the host.
  21. #define TB_VIEW 0x40u
  22. #define TB_R4 0x80u
  23. #define TB_R5 0x100u
  24. #define TB_RB 0x200u
  25. #define TB_DDN 0x400u
  26. #define TB_DRT 0x800u
  27. #define TB_DLF 0x1000u
  28. #define TB_DUP 0x2000u
  29. #define TB_MENU 0x4000u
  30. #define TB_L3 0x8000u
  31. #define TB_STEAM 0x10000u
  32. #define TB_L4 0x20000u
  33. #define TB_L5 0x40000u
  34. #define TB_LB 0x80000u
  35. #define TB_RPADT 0x200000u
  36. #define TB_RPADC 0x400000u
  37. #define TB_LPADT 0x2000000u
  38. #define TB_LPADC 0x4000000u
  39. // Trigger full-pull / click bits (the controller sets these at a full ZL/ZR pull; also the target of a back-
  40. // paddle / QAM remap to LT/RT). psShouldersByte / the Switch builders already read these as L2/R2 / ZL/ZR.
  41. #define TB_R2 0x800000u
  42. #define TB_L2 0x8000000u
  43. // Virtual PS targets, settable ONLY via a back-paddle/QAM remap (psOrBackCode / tritonFromCode), never by the
  44. // controller itself. They live on bits 30/31 -- the only bits the SC2 0x45 report does NOT use (see PROTOCOL.md
  45. // §8.1; bits 0..29 are all real). They originally aliased 0x00100000 (right stick touch) and 0x01000000 (left
  46. // stick touch), so merely RESTING a thumb on a capacitive stick fired the DualSense trackpad-click / mute.
  47. #define TB_TOUCH 0x40000000u // PS touchpad click
  48. #define TB_MUTE 0x80000000u // PS5 mute
  49. // all four back paddles held -> mode-switch chord guard
  50. #define CHORD_BACK4 (TB_R4 | TB_L4 | TB_R5 | TB_L5)
  51. // analog-trigger fraction (of 0xFF) at which digital ZL/ZR (Switch) etc. trip
  52. #define SW_TRIG_ON 40
  53. // ---- report 0x45 field decoders (offsets relative to rep[2], the buttons low byte) ----
  54. static inline int s16off(const uint8_t *r, int off)
  55. {
  56. int v = r[2 + off] | (r[2 + off + 1] << 8);
  57. return (v & 0x8000) ? v - 0x10000 : v;
  58. }
  59. static inline int u16off(const uint8_t *r, int off)
  60. {
  61. return r[2 + off] | (r[2 + off + 1] << 8);
  62. }
  63. // Controller trigger u16 tops out near half-scale (~0x8000) at a full pull, so a straight >>8 reads only ~0x80
  64. // (host sees a half-pressed trigger). Scale x2 (>>7) and saturate so a full pull maps to 0xFF.
  65. static inline uint8_t trigU8(int u16v)
  66. {
  67. int v = u16v >> 7;
  68. return (uint8_t)(v > 255 ? 255 : v);
  69. }
  70. static inline uint32_t btnsOf(const uint8_t *r)
  71. {
  72. return (uint32_t)r[2] | ((uint32_t)r[3] << 8) | ((uint32_t)r[4] << 16) |
  73. ((uint32_t)r[5] << 24);
  74. }
  75. // report 0x45 IMU offsets (PROTOCOL.md §8): accel @0x22, gyro @0x28 from report start.
  76. void imuFrom45(const uint8_t *r, int16_t *ax, int16_t *ay, int16_t *az,
  77. int16_t *gx, int16_t *gy, int16_t *gz);
  78. // Convert Triton report 0x47's wrapping 16-bit 32-us IMU clock to the
  79. // same monotonic microsecond domain used by PuckInput::imuTimestampUs.
  80. uint32_t tritonTimestamp47Us(uint8_t slot, uint16_t timestamp32us);
  81. void tritonTimestamp47Reset(uint8_t slot);
  82. // ---- shared decoded input (filled by rf_link.cpp once per fresh report 0x45, read by every mode) ----
  83. // One PuckInput per bond slot: each controller in a multi-slot puck has its own decoded input. The stream
  84. // modes (Switch, PS5, DS4) read g_in[s] for each active slot in their task() loop; the puck/lizard mode reads
  85. // g_in[slot] inside onReport45/onAuxReport to forward to hid[slot].
  86. struct PuckInput {
  87. // raw Triton buttons (TB_*); per-mode builders apply their own chord masking
  88. uint32_t buttons;
  89. int16_t lx, ly, rx, ry; // sticks (int16, center 0)
  90. uint8_t lt, rt; // triggers scaled 0..255 (trigU8)
  91. int16_t lpx, lpy, rpx, rpy; // left / right trackpad coords (int16)
  92. int16_t ax, ay, az; // accelerometer
  93. int16_t gx, gy, gz; // gyroscope
  94. // Triton 0x42/0x45 IMU source clock, microseconds
  95. uint32_t imuTimestampUs;
  96. };
  97. #include "bonds.h" // NSLOT
  98. extern PuckInput g_in[NSLOT];