report45.cpp 2.6 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071
  1. #include "report45.h"
  2. #include "triton.h"
  3. #include <Arduino.h>
  4. #include <string.h>
  5. // Write a signed 16-bit value little-endian at rep[2+off] (the same indexing triton.h's s16off reads).
  6. static inline void put_s16(uint8_t *rep, int off, int16_t v)
  7. {
  8. rep[2 + off] = (uint8_t)(v & 0xFF);
  9. rep[2 + off + 1] = (uint8_t)((v >> 8) & 0xFF);
  10. }
  11. // Write an unsigned 16-bit value little-endian at rep[2+off] (matches u16off).
  12. static inline void put_u16(uint8_t *rep, int off, uint16_t v)
  13. {
  14. rep[2 + off] = (uint8_t)(v & 0xFF);
  15. rep[2 + off + 1] = (uint8_t)((v >> 8) & 0xFF);
  16. }
  17. // Write an unsigned 32-bit value little-endian at rep[2+off].
  18. static inline void put_u32(uint8_t *rep, int off, uint32_t v)
  19. {
  20. rep[2 + off + 0] = (uint8_t)(v & 0xFF);
  21. rep[2 + off + 1] = (uint8_t)((v >> 8) & 0xFF);
  22. rep[2 + off + 2] = (uint8_t)((v >> 16) & 0xFF);
  23. rep[2 + off + 3] = (uint8_t)((v >> 24) & 0xFF);
  24. }
  25. void buildReport45(uint8_t *out, uint8_t seq)
  26. {
  27. memset(out, 0, REPORT45_LEN);
  28. out[0] = 0x45;
  29. out[1] = seq;
  30. // buttons u32 at rep[2..5] (inverse of btnsOf)
  31. out[2] = (uint8_t)(g_in.buttons & 0xFF);
  32. out[3] = (uint8_t)((g_in.buttons >> 8) & 0xFF);
  33. out[4] = (uint8_t)((g_in.buttons >> 16) & 0xFF);
  34. out[5] = (uint8_t)((g_in.buttons >> 24) & 0xFF);
  35. // triggers: the controller's analog trigger is a u16 that trigU8 maps via >>7 (saturating). Inverse:
  36. // u16 = lt << 7 (so a full 0xFF pull -> 0x7F80 -> trigU8 -> 0xFF). offset 4 = LT, offset 6 = RT.
  37. put_u16(out, 4, (uint16_t)(g_in.lt << 7));
  38. put_u16(out, 6, (uint16_t)(g_in.rt << 7));
  39. // sticks (int16, center 0): lx@8 ly@10 rx@12 ry@14
  40. put_s16(out, 8, g_in.lx);
  41. put_s16(out, 10, g_in.ly);
  42. put_s16(out, 12, g_in.rx);
  43. put_s16(out, 14, g_in.ry);
  44. // trackpads: LPad x@16 y@18 pressure@20, RPad x@22 y@24 pressure@26 (per PROTOCOL.md report 0x45)
  45. put_s16(out, 16, g_in.lpx);
  46. put_s16(out, 18, g_in.lpy);
  47. put_u16(out, 20, g_in.lpp);
  48. put_s16(out, 22, g_in.rpx);
  49. put_s16(out, 24, g_in.rpy);
  50. put_u16(out, 26, g_in.rpp);
  51. // IMU timestamp: report[30..33] = free-running MICROSECOND counter (u32 LE), per IBEX_REIMPL_SPEC
  52. // report-0x45 layout. CRITICAL for gyro: Steam integrates angular velocity as gyro * dt where dt is
  53. // the delta of THIS timestamp between reports -- leaving it 0 makes dt=0 so the gyro never moves the
  54. // view on the host, no matter how correct the gyro values are. off 28 -> rep[30].
  55. put_u32(out, 28, micros());
  56. // IMU: accel @0x22 (offset 32), gyro @0x28 (offset 38) -- inverse of imuFrom45
  57. put_s16(out, 32, g_in.ax);
  58. put_s16(out, 34, g_in.ay);
  59. put_s16(out, 36, g_in.az);
  60. put_s16(out, 38, g_in.gx);
  61. put_s16(out, 40, g_in.gy);
  62. put_s16(out, 42, g_in.gz);
  63. }