mode_test.cpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576
  1. #include "mode_xinput.h"
  2. #include "config.h"
  3. #include "gamepad_util.h"
  4. #include "haptics.h"
  5. #include "usb_app_drivers.h"
  6. #include "usb_tx.h"
  7. #include "xinput_auth.h"
  8. #include "xinput_descriptors.h"
  9. #include <Arduino.h>
  10. #include <algorithm>
  11. #include <array>
  12. #include <cstdio>
  13. #include <cstdlib>
  14. #include <cstring>
  15. #include <string>
  16. #include <vector>
  17. #define CHECK(condition) check(bool(condition), #condition, __LINE__)
  18. static void check(bool condition, const char *expression, int line)
  19. {
  20. if (!condition) {
  21. fprintf(stderr, "%s:%d: %s\n", __FILE__, line, expression);
  22. abort();
  23. }
  24. }
  25. using Bytes = std::vector<uint8_t>;
  26. Adafruit_USBD_Device TinyUSBDevice;
  27. uint8_t g_usbMode = MODE_XBOX;
  28. uint8_t g_abSwap, g_back[4], g_qamMap, g_rumble = 1;
  29. Slot g_slot[NSLOT];
  30. unsigned long g_connReplyMs[NSLOT];
  31. static unsigned long now = 1000;
  32. static uint32_t interruptMask;
  33. static bool mounted = true;
  34. static tusb_desc_device_t device;
  35. static std::string manufacturer, product, serial, interfaceString;
  36. static uint8_t attributes, interfaceCount, endpointCount[2];
  37. static uint16_t maxPower;
  38. static unsigned additions, registrations;
  39. static Adafruit_USBD_Interface *registeredInterface;
  40. static usbTxDrainFn drain;
  41. static Bytes configuration;
  42. struct Endpoint {
  43. bool opened = false, busy = false, claimed = false;
  44. uint8_t *buffer = nullptr;
  45. uint16_t length = 0;
  46. };
  47. static Endpoint endpoints[256];
  48. static std::vector<uint8_t> opened, closed;
  49. static std::vector<Bytes> reports;
  50. static uint8_t failOpen;
  51. static bool failTransfer;
  52. struct Rumble {
  53. uint16_t low, high;
  54. uint8_t slot;
  55. };
  56. static std::vector<Rumble> rumbles;
  57. static std::array<int16_t, 4> padCoordinates;
  58. unsigned long millis()
  59. {
  60. return now;
  61. }
  62. uint32_t __get_PRIMASK()
  63. {
  64. return interruptMask;
  65. }
  66. void __disable_irq()
  67. {
  68. interruptMask = 1;
  69. }
  70. void __set_PRIMASK(uint32_t mask)
  71. {
  72. CHECK(mask <= 1);
  73. interruptMask = mask;
  74. }
  75. bool tud_mounted()
  76. {
  77. return mounted;
  78. }
  79. const uint8_t *tud_descriptor_device_cb()
  80. {
  81. return reinterpret_cast<const uint8_t *>(&device);
  82. }
  83. void Adafruit_USBD_Interface::setStringDescriptor(const char *str)
  84. {
  85. interfaceString = str;
  86. _strid = 4;
  87. }
  88. uint8_t Adafruit_USBD_Device::allocInterface(uint8_t count)
  89. {
  90. uint8_t first = interfaceCount;
  91. interfaceCount += count;
  92. return first;
  93. }
  94. uint8_t Adafruit_USBD_Device::allocEndpoint(uint8_t direction)
  95. {
  96. CHECK(direction <= 1);
  97. return ++endpointCount[direction] | (direction ? 0x80 : 0);
  98. }
  99. bool Adafruit_USBD_Device::addInterface(Adafruit_USBD_Interface &interface)
  100. {
  101. additions++;
  102. registeredInterface = &interface;
  103. uint16_t length = interface.getInterfaceDescriptor(0, nullptr, 0);
  104. CHECK(length == 144);
  105. configuration.resize(length);
  106. CHECK(interface.getInterfaceDescriptor(0, configuration.data(),
  107. length) == length);
  108. return true;
  109. }
  110. void Adafruit_USBD_Device::setID(uint16_t vendor, uint16_t productID)
  111. {
  112. device.idVendor = vendor;
  113. device.idProduct = productID;
  114. }
  115. void Adafruit_USBD_Device::setVersion(uint16_t version)
  116. {
  117. device.bcdUSB = version;
  118. }
  119. void Adafruit_USBD_Device::setDeviceVersion(uint16_t version)
  120. {
  121. device.bcdDevice = version;
  122. }
  123. void Adafruit_USBD_Device::setManufacturerDescriptor(const char *str)
  124. {
  125. manufacturer = str;
  126. }
  127. void Adafruit_USBD_Device::setProductDescriptor(const char *str)
  128. {
  129. product = str;
  130. }
  131. void Adafruit_USBD_Device::setSerialDescriptor(const char *str)
  132. {
  133. serial = str;
  134. }
  135. void Adafruit_USBD_Device::setConfigurationAttribute(uint8_t value)
  136. {
  137. attributes = value;
  138. }
  139. void Adafruit_USBD_Device::setConfigurationMaxPower(uint16_t value)
  140. {
  141. maxPower = value;
  142. }
  143. void usbTxRegisterDrain(usbTxDrainFn fn)
  144. {
  145. registrations++;
  146. drain = fn;
  147. }
  148. void xinputAuthYield()
  149. {
  150. CHECK(interruptMask == 0);
  151. }
  152. bool hapticSteamRumble(uint16_t low, uint16_t high, uint8_t slot)
  153. {
  154. CHECK(interruptMask == 0 && slot < NSLOT);
  155. rumbles.push_back({ low, high, slot });
  156. return true;
  157. }
  158. void padStickBlend(uint32_t, int16_t lpx, int16_t lpy, int16_t rpx, int16_t rpy,
  159. int16_t *, int16_t *, int16_t *, int16_t *)
  160. {
  161. // Record the caller's reads; shared trackpad blending is not under test.
  162. padCoordinates = { lpx, lpy, rpx, rpy };
  163. }
  164. extern "C" bool usbd_edpt_open(uint8_t rhport,
  165. const tusb_desc_endpoint_t *descriptor)
  166. {
  167. CHECK(rhport == 0 && descriptor != nullptr);
  168. uint8_t ep = descriptor->bEndpointAddress;
  169. CHECK(!endpoints[ep].opened);
  170. if (ep == failOpen)
  171. return false;
  172. CHECK(descriptor->wMaxPacketSize == 32);
  173. endpoints[ep].opened = true;
  174. opened.push_back(ep);
  175. return true;
  176. }
  177. extern "C" void usbd_edpt_close(uint8_t rhport, uint8_t ep)
  178. {
  179. CHECK(rhport == 0 && endpoints[ep].opened);
  180. endpoints[ep] = {};
  181. closed.push_back(ep);
  182. }
  183. extern "C" bool usbd_edpt_xfer(uint8_t rhport, uint8_t ep, uint8_t *buffer,
  184. uint16_t length)
  185. {
  186. CHECK(rhport == 0 && buffer != nullptr);
  187. auto &endpoint = endpoints[ep];
  188. CHECK(endpoint.opened && !endpoint.busy);
  189. CHECK((ep == 0x81 && length == 20) || (ep == 2 && length == 32));
  190. if (failTransfer) {
  191. failTransfer = false;
  192. return false;
  193. }
  194. endpoint.busy = true;
  195. endpoint.claimed = false;
  196. endpoint.buffer = buffer;
  197. endpoint.length = length;
  198. if (ep == 0x81)
  199. reports.emplace_back(buffer, buffer + length);
  200. return true;
  201. }
  202. extern "C" bool usbd_edpt_busy(uint8_t rhport, uint8_t ep)
  203. {
  204. CHECK(rhport == 0);
  205. return endpoints[ep].busy;
  206. }
  207. extern "C" bool usbd_edpt_claim(uint8_t rhport, uint8_t ep)
  208. {
  209. CHECK(rhport == 0);
  210. auto &endpoint = endpoints[ep];
  211. if (endpoint.busy || endpoint.claimed)
  212. return false;
  213. endpoint.claimed = true;
  214. return true;
  215. }
  216. extern "C" bool usbd_edpt_release(uint8_t rhport, uint8_t ep)
  217. {
  218. CHECK(rhport == 0 && endpoints[ep].claimed);
  219. endpoints[ep].claimed = false;
  220. return true;
  221. }
  222. static uint16_t openInterface(const Bytes &body, size_t offset, uint16_t length)
  223. {
  224. return xinputClassDriver()->open(
  225. 0,
  226. reinterpret_cast<const tusb_desc_interface_t *>(body.data() +
  227. offset),
  228. length);
  229. }
  230. static void resetUSB()
  231. {
  232. for (auto &endpoint : endpoints)
  233. endpoint = {};
  234. xinputClassDriver()->reset(0);
  235. g_xboxCtl.task();
  236. opened.clear();
  237. closed.clear();
  238. reports.clear();
  239. rumbles.clear();
  240. }
  241. static void enumerate()
  242. {
  243. static const uint16_t starts[] = { 0, 40, 104, 129, 144 };
  244. for (unsigned i = 0; i < 4; i++) {
  245. uint16_t length = starts[i + 1] - starts[i];
  246. CHECK(openInterface(configuration, starts[i], length) ==
  247. length);
  248. CHECK(openInterface(configuration, starts[i], length) == 0);
  249. }
  250. CHECK(opened == Bytes({ 0x81, 0x02 }));
  251. CHECK(endpoints[2].busy && endpoints[2].length == 32);
  252. }
  253. static void completeInput(xfer_result_t result = XFER_RESULT_SUCCESS)
  254. {
  255. CHECK(endpoints[0x81].busy);
  256. endpoints[0x81].busy = false;
  257. CHECK(xinputClassDriver()->xfer_cb(0, 0x81, result, 20));
  258. }
  259. static void output(const Bytes &packet, uint32_t actual,
  260. xfer_result_t result = XFER_RESULT_SUCCESS)
  261. {
  262. auto &ep = endpoints[2];
  263. CHECK(ep.busy);
  264. CHECK(packet.size() <= ep.length);
  265. // Keep the old tail, as DMA does, so short rumble cannot use stale bytes.
  266. if (!packet.empty())
  267. memcpy(ep.buffer, packet.data(), packet.size());
  268. ep.busy = false;
  269. CHECK(xinputClassDriver()->xfer_cb(0, 2, result, actual));
  270. }
  271. static Bytes neutral()
  272. {
  273. Bytes report(20);
  274. report[1] = 20;
  275. return report;
  276. }
  277. static void enumerationTests()
  278. {
  279. static_assert(sizeof(tusb_desc_interface_t) == 9, "Interface size");
  280. static_assert(sizeof(tusb_desc_endpoint_t) == 7, "Endpoint size");
  281. static_assert(sizeof(tusb_desc_device_t) == 18, "Device size");
  282. xinputClassDriver()->init();
  283. g_xboxCtl.begin();
  284. CHECK(!g_xboxCtl.dynamicMount());
  285. CHECK(additions == 1 && registrations == 1 && drain != nullptr);
  286. CHECK(device.idVendor == 0x045E && device.idProduct == 0x028E);
  287. CHECK(device.bcdUSB == 0x0200 && device.bcdDevice == 0x0114);
  288. CHECK(device.bDeviceClass == 0xFF && device.bDeviceSubClass == 0xFF);
  289. CHECK(device.bDeviceProtocol == 0xFF);
  290. CHECK(manufacturer == "\xc2\xa9Microsoft Corporation");
  291. CHECK(product == "Controller" && serial == "012345ABCDEF");
  292. CHECK(attributes == 0xA0 && maxPower == 500);
  293. CHECK(interfaceString == XINPUT_SECURITY_STRING);
  294. CHECK(interfaceCount == 4 && endpointCount[0] == 6 &&
  295. endpointCount[1] == 6);
  296. CHECK(configuration ==
  297. Bytes(XINPUT_CONFIG_BODY,
  298. XINPUT_CONFIG_BODY + sizeof XINPUT_CONFIG_BODY));
  299. Bytes guard(160, 0xA5);
  300. for (unsigned length = 0; length < 144; length++)
  301. CHECK(registeredInterface->getInterfaceDescriptor(
  302. 0, guard.data(), length) == 0);
  303. CHECK(registeredInterface->getInterfaceDescriptor(1, guard.data(),
  304. 160) == 0);
  305. CHECK(std::all_of(guard.begin(), guard.end(),
  306. [](uint8_t b) { return b == 0xA5; }));
  307. CHECK(interfaceCount == 4 && endpointCount[0] == 6 &&
  308. endpointCount[1] == 6);
  309. CHECK(xinputClassDriver()->open(0, nullptr, 144) == 0);
  310. static const uint16_t starts[] = { 0, 40, 104, 129, 144 };
  311. for (unsigned i = 0; i < 4; i++) {
  312. uint16_t length = starts[i + 1] - starts[i];
  313. for (uint16_t shortLength = 0; shortLength < length;
  314. shortLength++)
  315. CHECK(openInterface(configuration, starts[i],
  316. shortLength) == 0);
  317. for (size_t byte = starts[i]; byte < starts[i + 1]; byte++) {
  318. if (byte == XINPUT_SECURITY_STRING_OFFSET)
  319. continue;
  320. Bytes corrupt = configuration;
  321. corrupt[byte] ^= 0x80;
  322. CHECK(openInterface(corrupt, starts[i], length) == 0);
  323. }
  324. }
  325. CHECK(opened.empty());
  326. failOpen = 0x81;
  327. CHECK(openInterface(configuration, 0, 40) == 0);
  328. CHECK(opened.empty());
  329. failOpen = 2;
  330. CHECK(openInterface(configuration, 0, 40) == 0);
  331. CHECK(opened == Bytes({ 0x81 }) && closed == Bytes({ 0x81 }));
  332. failOpen = 0;
  333. resetUSB();
  334. enumerate();
  335. drain();
  336. CHECK(reports.size() == 1 && reports.back() == neutral());
  337. completeInput();
  338. for (unsigned i = 0; i < 3; i++) {
  339. g_xboxCtl.task();
  340. drain();
  341. }
  342. CHECK(reports.size() == 1 && additions == 1);
  343. CHECK(!xinputClassDriver()->xfer_cb(1, 2, XFER_RESULT_SUCCESS, 8));
  344. CHECK(!xinputClassDriver()->xfer_cb(0, 0x83, XFER_RESULT_SUCCESS, 8));
  345. puts("PASS actual mode: static identity, descriptor builder/parser, "
  346. "endpoint reservations, accessory claims, neutral without RF");
  347. }
  348. static Bytes rfReport(uint8_t id = 0x45)
  349. {
  350. Bytes report(28);
  351. report[0] = id;
  352. uint32_t buttons = TB_A | TB_VIEW | TB_MENU | TB_DUP | TB_L2;
  353. for (unsigned i = 0; i < 4; i++)
  354. report[2 + i] = buttons >> (i * 8);
  355. le16(report.data() + 8, 0x4000);
  356. le16(report.data() + 10, -32768);
  357. le16(report.data() + 12, 32767);
  358. le16(report.data() + 14, -1);
  359. le16(report.data() + 16, 1234);
  360. le16(report.data() + 18, 101);
  361. le16(report.data() + 20, -102);
  362. le16(report.data() + 24, 103);
  363. le16(report.data() + 26, -104);
  364. return report;
  365. }
  366. static void rfTests()
  367. {
  368. g_slot[0].used = g_slot[1].used = true;
  369. g_connReplyMs[0] = g_connReplyMs[1] = now;
  370. auto report = rfReport();
  371. for (unsigned length = 0; length < 26; length++) {
  372. // Report includes ID and sequence before the body. Exact allocations
  373. // let ASan detect reads beyond the advertised body, if enabled.
  374. Bytes shortReport(report.begin(), report.begin() + length + 2);
  375. g_xboxCtl.onReport45(0, shortReport.data(), true, length);
  376. }
  377. g_xboxCtl.onReport45(0, nullptr, true, 26);
  378. for (int slot : { -1, NSLOT, 255 })
  379. g_xboxCtl.onReport45(slot, report.data(), true, 26);
  380. for (uint8_t id : { 0, 0x43, 0x44, 0x47, 0xFF }) {
  381. auto bad = rfReport(id);
  382. g_xboxCtl.onReport45(0, bad.data(), true, 26);
  383. }
  384. g_xboxCtl.onReport45(0, report.data(), false, 26);
  385. drain();
  386. CHECK(reports.size() == 1);
  387. g_connReplyMs[0] = now - 300;
  388. g_xboxCtl.onReport45(0, report.data(), true, 26);
  389. drain();
  390. CHECK(reports.size() == 1);
  391. g_connReplyMs[0] = now - 299;
  392. g_xboxCtl.onReport45(0, report.data(), true, 26);
  393. drain();
  394. Bytes expected = { 0, 20, 0x31, 0x10, 0xFF, 0x80, 0,
  395. 0x80, 0xFF, 0x7F, 0xFF, 0xFF, 0xD2, 4,
  396. 0, 0, 0, 0, 0, 0 };
  397. CHECK(reports.size() == 2 && reports.back() == expected);
  398. CHECK((padCoordinates ==
  399. std::array<int16_t, 4>{ 101, -102, 103, -104 }));
  400. completeInput();
  401. g_xboxCtl.onReport45(1, report.data(), true, 26);
  402. drain();
  403. CHECK(reports.size() == 2);
  404. Bytes synthetic(28);
  405. synthetic[0] = 0x45;
  406. g_xboxCtl.onReport45(0, synthetic.data(), false, 26);
  407. drain();
  408. CHECK(reports.size() == 3 && reports.back() == neutral());
  409. completeInput();
  410. report[0] = 0x42;
  411. g_xboxCtl.onReport45(0, report.data(), true, 26);
  412. drain();
  413. CHECK(reports.size() == 4 && reports.back() == expected);
  414. completeInput();
  415. g_connReplyMs[0] = now - 1200;
  416. g_xboxCtl.task();
  417. drain();
  418. CHECK(reports.size() == 4);
  419. now++;
  420. g_xboxCtl.task();
  421. drain();
  422. CHECK(reports.size() == 5 && reports.back() == neutral());
  423. CHECK(rumbles.size() == 1 && rumbles.back().slot == 0);
  424. CHECK(rumbles.back().low == 0 && rumbles.back().high == 0);
  425. completeInput();
  426. g_connReplyMs[1] = now;
  427. g_xboxCtl.onReport45(1, report.data(), false, 26);
  428. drain();
  429. CHECK(reports.size() == 5);
  430. g_xboxCtl.onReport45(1, report.data(), true, 26);
  431. drain();
  432. CHECK(reports.size() == 6 && reports.back() == expected);
  433. completeInput();
  434. CHECK(additions == 1 && registrations == 1 && opened.size() == 2);
  435. puts("PASS actual mode: bodyTlen 0..25, exact 26-byte body, RF selection, "
  436. "synthetic neutral, disconnect and replacement without enumeration");
  437. }
  438. static void rumbleTests()
  439. {
  440. rumbles.clear();
  441. Bytes valid = { 0, 8, 0, 0x12, 0xFE, 0, 0, 0 };
  442. output(valid, 8);
  443. g_xboxCtl.task();
  444. CHECK(rumbles.size() == 1 && rumbles.back().slot == 1);
  445. CHECK(rumbles.back().low == 0x1212 && rumbles.back().high == 0xFEFE);
  446. for (uint32_t length : { 0u, 1u, 2u, 3u, 4u, 5u, 6u, 7u, 9u, 20u, 32u,
  447. 33u, 65536u, UINT32_MAX }) {
  448. Bytes packet = valid;
  449. packet.resize(std::min<uint32_t>(length, 32));
  450. output(packet, length);
  451. g_xboxCtl.task();
  452. CHECK(rumbles.size() == 1 && endpoints[2].busy);
  453. }
  454. for (unsigned byte : { 0, 1, 2, 5, 6, 7 }) {
  455. Bytes malformed = valid;
  456. malformed[byte] ^= 1;
  457. output(malformed, 8);
  458. g_xboxCtl.task();
  459. CHECK(rumbles.size() == 1);
  460. }
  461. for (auto result : { XFER_RESULT_FAILED, XFER_RESULT_STALLED,
  462. XFER_RESULT_TIMEOUT, XFER_RESULT_INVALID }) {
  463. output(valid, 8, result);
  464. g_xboxCtl.task();
  465. CHECK(rumbles.size() == 1);
  466. }
  467. for (unsigned led = 0; led <= 255; led++) {
  468. output({ 1, 3, uint8_t(led) }, 3);
  469. g_xboxCtl.task();
  470. CHECK(rumbles.size() == 1);
  471. }
  472. g_rumble = 0;
  473. output(valid, 8);
  474. g_xboxCtl.task();
  475. CHECK(rumbles.size() == 2 && rumbles.back().low == 0 &&
  476. rumbles.back().high == 0);
  477. g_rumble = 1;
  478. output(valid, 8);
  479. g_xboxCtl.task();
  480. now += 2500;
  481. g_connReplyMs[1] = now;
  482. g_xboxCtl.task();
  483. CHECK(rumbles.size() == 3);
  484. now++;
  485. g_connReplyMs[1] = now;
  486. g_xboxCtl.task();
  487. CHECK(rumbles.size() == 4 && rumbles.back().low == 0 &&
  488. rumbles.back().high == 0);
  489. g_xboxCtl.task();
  490. CHECK(rumbles.size() == 4);
  491. failTransfer = true;
  492. output({}, 0);
  493. CHECK(!endpoints[2].busy);
  494. drain();
  495. CHECK(endpoints[2].busy);
  496. output(valid, 8);
  497. g_slot[1].used = false;
  498. g_xboxCtl.task();
  499. CHECK(rumbles.size() == 5 && rumbles.back().slot == 1);
  500. CHECK(rumbles.back().low == 0 && rumbles.back().high == 0);
  501. failTransfer = true;
  502. drain();
  503. CHECK(!endpoints[0x81].busy);
  504. drain();
  505. CHECK(reports.back() == neutral());
  506. completeInput(XFER_RESULT_FAILED);
  507. mounted = false;
  508. size_t before = reports.size();
  509. drain();
  510. CHECK(reports.size() == before);
  511. mounted = true;
  512. drain();
  513. CHECK(reports.size() == before + 1 && reports.back() == neutral());
  514. completeInput();
  515. output(valid, 8);
  516. g_xboxCtl.task();
  517. CHECK(rumbles.size() == 5);
  518. CHECK(additions == 1 && registrations == 1);
  519. puts("PASS actual mode: rumble routing, malformed/stale/failed OUT, LED "
  520. "isolation, disable/watchdog/disconnect stops, endpoint retries");
  521. }
  522. void modeTests()
  523. {
  524. enumerationTests();
  525. rfTests();
  526. rumbleTests();
  527. resetUSB();
  528. CHECK(xinputClassDriver()->deinit());
  529. CHECK(interruptMask == 0);
  530. }