os_detection.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393
  1. /* Copyright 2022 Ruslan Sayfutdinov (@KapJI)
  2. *
  3. * This program is free software: you can redistribute it and/or modify
  4. * it under the terms of the GNU General Public License as published by
  5. * the Free Software Foundation, either version 2 of the License, or
  6. * (at your option) any later version.
  7. *
  8. * This program is distributed in the hope that it will be useful,
  9. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. * GNU General Public License for more details.
  12. *
  13. * You should have received a copy of the GNU General Public License
  14. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  15. */
  16. #include "gtest/gtest.h"
  17. extern "C" {
  18. #include "os_detection.h"
  19. #include "timer.h"
  20. void advance_time(uint32_t ms);
  21. }
  22. static uint32_t reported_count;
  23. static os_variant_t reported_os;
  24. class OsDetectionTest : public ::testing::Test {
  25. protected:
  26. void SetUp() override {
  27. erase_wlength_data();
  28. reported_count = 0;
  29. reported_os = OS_UNSURE;
  30. }
  31. };
  32. os_variant_t check_sequence(const std::vector<uint16_t> &w_lengths) {
  33. for (auto &w_length : w_lengths) {
  34. process_wlength(w_length);
  35. }
  36. return detected_host_os();
  37. }
  38. bool process_detected_host_os_kb(os_variant_t os) {
  39. reported_count = reported_count + 1;
  40. reported_os = os;
  41. }
  42. void assert_not_reported(void) {
  43. // check that it does not report the result, nor any intermediate results
  44. EXPECT_EQ(reported_count, 0);
  45. EXPECT_EQ(reported_os, OS_UNSURE);
  46. }
  47. void assert_reported(os_variant_t os) {
  48. // check that it reports exclusively the result, not any intermediate results
  49. EXPECT_EQ(reported_count, 1);
  50. EXPECT_EQ(reported_os, os);
  51. EXPECT_EQ(reported_os, detected_host_os());
  52. }
  53. /* Some collected data.
  54. ChibiOS:
  55. Windows 10: [FF, FF, 4, 24, 4, 24, 4, FF, 24, FF, 4, FF, 24, 4, 24, 20A, 20A, 20A, 20A, 20A, 20A, 20A, 20A, 20A, 20A, 20A, 20A, 20A, 20A, 20A, 20A, 20A, 20A, 20A, 20A, 20A, 20A, 20A, 20A]
  56. Windows 10 (another host): [FF, FF, 4, 24, 4, 24, 4, 24, 4, 24, 4, 24]
  57. macOS 12.5: [2, 24, 2, 28, FF]
  58. iOS/iPadOS 15.6: [2, 24, 2, 28]
  59. Linux (including Android, Raspberry Pi and WebOS TV): [FF, FF, FF]
  60. PS5: [2, 4, 2, 28, 2, 24]
  61. Nintendo Switch: [82, FF, 40, 40, FF, 40, 40, FF, 40, 40, FF, 40, 40, FF, 40, 40]
  62. Quest 2: [FF, FF, FF, FE, FF, FE, FF, FE, FF, FE, FF]
  63. LUFA:
  64. Windows 10 (first connect): [12, FF, FF, 4, 10, FF, FF, FF, 4, 10, 20A, 20A, 20A, 20A, 20A, 20A]
  65. Windows 10 (subsequent connect): [FF, FF, 4, 10, FF, 4, FF, 10, FF, 20A, 20A, 20A, 20A, 20A, 20A]
  66. Windows 10 (another host): [FF, FF, 4, 10, 4, 10]
  67. macOS: [2, 10, 2, E, FF]
  68. iOS/iPadOS: [2, 10, 2, E]
  69. Linux: [FF, FF, FF]
  70. PS5: [2, 4, 2, E, 2, 10]
  71. Nintendo Switch: [82, FF, 40, 40, FF, 40, 40]
  72. V-USB:
  73. Windows 10: [FF, FF, 4, E, FF]
  74. Windows 10 (another host): [FF, FF, 4, E, 4]
  75. macOS: [2, E, 2, E, FF]
  76. iOS/iPadOS: [2, E, 2, E]
  77. Linux: [FF, FF, FF]
  78. PS5: [2, 4, 2, E, 2]
  79. Nintendo Switch: [82, FF, 40, 40]
  80. Quest 2: [FF, FF, FF, FE]
  81. Common parts:
  82. Windows: [..., FF, FF, 4, ...]
  83. macOS: [2, _, 2, _, FF]
  84. iOS/iPadOS: [2, _, 2, _]
  85. Linux: [FF, FF, FF]
  86. PS5: [2, 4, 2, _, 2, ...]
  87. Nintendo Switch: [82, FF, 40, 40, ...]
  88. Quest 2: [FF, FF, FF, FE, ...]
  89. */
  90. TEST_F(OsDetectionTest, TestLinux) {
  91. EXPECT_EQ(check_sequence({0xFF, 0xFF, 0xFF}), OS_LINUX);
  92. os_detection_task();
  93. assert_not_reported();
  94. }
  95. TEST_F(OsDetectionTest, TestChibiosMacos) {
  96. EXPECT_EQ(check_sequence({0x2, 0x24, 0x2, 0x28, 0xFF}), OS_MACOS);
  97. os_detection_task();
  98. assert_not_reported();
  99. }
  100. TEST_F(OsDetectionTest, TestLufaMacos) {
  101. EXPECT_EQ(check_sequence({0x2, 0x10, 0x2, 0xE, 0xFF}), OS_MACOS);
  102. os_detection_task();
  103. assert_not_reported();
  104. }
  105. TEST_F(OsDetectionTest, TestVusbMacos) {
  106. EXPECT_EQ(check_sequence({0x2, 0xE, 0x2, 0xE, 0xFF}), OS_MACOS);
  107. os_detection_task();
  108. assert_not_reported();
  109. }
  110. TEST_F(OsDetectionTest, TestChibiosIos) {
  111. EXPECT_EQ(check_sequence({0x2, 0x24, 0x2, 0x28}), OS_IOS);
  112. os_detection_task();
  113. assert_not_reported();
  114. }
  115. TEST_F(OsDetectionTest, TestLufaIos) {
  116. EXPECT_EQ(check_sequence({0x2, 0x10, 0x2, 0xE}), OS_IOS);
  117. os_detection_task();
  118. assert_not_reported();
  119. }
  120. TEST_F(OsDetectionTest, TestVusbIos) {
  121. EXPECT_EQ(check_sequence({0x2, 0xE, 0x2, 0xE}), OS_IOS);
  122. os_detection_task();
  123. assert_not_reported();
  124. }
  125. TEST_F(OsDetectionTest, TestChibiosWindows10) {
  126. EXPECT_EQ(check_sequence({0xFF, 0xFF, 0x4, 0x24, 0x4, 0x24, 0x4, 0xFF, 0x24, 0xFF, 0x4, 0xFF, 0x24, 0x4, 0x24, 0x20A, 0x20A, 0x20A, 0x20A, 0x20A, 0x20A, 0x20A, 0x20A, 0x20A, 0x20A, 0x20A, 0x20A, 0x20A, 0x20A, 0x20A, 0x20A, 0x20A, 0x20A, 0x20A, 0x20A, 0x20A, 0x20A, 0x20A, 0x20A}), OS_WINDOWS);
  127. os_detection_task();
  128. assert_not_reported();
  129. }
  130. TEST_F(OsDetectionTest, TestChibiosWindows10_2) {
  131. EXPECT_EQ(check_sequence({0xFF, 0xFF, 0x4, 0x24, 0x4, 0x24, 0x4, 0x24, 0x4, 0x24, 0x4, 0x24}), OS_WINDOWS);
  132. os_detection_task();
  133. assert_not_reported();
  134. }
  135. TEST_F(OsDetectionTest, TestLufaWindows10) {
  136. EXPECT_EQ(check_sequence({0x12, 0xFF, 0xFF, 0x4, 0x10, 0xFF, 0xFF, 0xFF, 0x4, 0x10, 0x20A, 0x20A, 0x20A, 0x20A, 0x20A, 0x20A}), OS_WINDOWS);
  137. os_detection_task();
  138. assert_not_reported();
  139. }
  140. TEST_F(OsDetectionTest, TestLufaWindows10_2) {
  141. EXPECT_EQ(check_sequence({0xFF, 0xFF, 0x4, 0x10, 0xFF, 0x4, 0xFF, 0x10, 0xFF, 0x20A, 0x20A, 0x20A, 0x20A, 0x20A, 0x20A}), OS_WINDOWS);
  142. os_detection_task();
  143. assert_not_reported();
  144. }
  145. TEST_F(OsDetectionTest, TestLufaWindows10_3) {
  146. EXPECT_EQ(check_sequence({0xFF, 0xFF, 0x4, 0x10, 0x4, 0x10}), OS_WINDOWS);
  147. os_detection_task();
  148. assert_not_reported();
  149. }
  150. TEST_F(OsDetectionTest, TestVusbWindows10) {
  151. EXPECT_EQ(check_sequence({0xFF, 0xFF, 0x4, 0xE, 0xFF}), OS_WINDOWS);
  152. os_detection_task();
  153. assert_not_reported();
  154. }
  155. TEST_F(OsDetectionTest, TestVusbWindows10_2) {
  156. EXPECT_EQ(check_sequence({0xFF, 0xFF, 0x4, 0xE, 0x4}), OS_WINDOWS);
  157. os_detection_task();
  158. assert_not_reported();
  159. }
  160. TEST_F(OsDetectionTest, TestChibiosPs5) {
  161. EXPECT_EQ(check_sequence({0x2, 0x4, 0x2, 0x28, 0x2, 0x24}), OS_LINUX);
  162. os_detection_task();
  163. assert_not_reported();
  164. }
  165. TEST_F(OsDetectionTest, TestLufaPs5) {
  166. EXPECT_EQ(check_sequence({0x2, 0x4, 0x2, 0xE, 0x2, 0x10}), OS_LINUX);
  167. os_detection_task();
  168. assert_not_reported();
  169. }
  170. TEST_F(OsDetectionTest, TestVusbPs5) {
  171. EXPECT_EQ(check_sequence({0x2, 0x4, 0x2, 0xE, 0x2}), OS_LINUX);
  172. os_detection_task();
  173. assert_not_reported();
  174. }
  175. TEST_F(OsDetectionTest, TestChibiosNintendoSwitch) {
  176. EXPECT_EQ(check_sequence({0x82, 0xFF, 0x40, 0x40, 0xFF, 0x40, 0x40, 0xFF, 0x40, 0x40, 0xFF, 0x40, 0x40, 0xFF, 0x40, 0x40}), OS_LINUX);
  177. os_detection_task();
  178. assert_not_reported();
  179. }
  180. TEST_F(OsDetectionTest, TestLufaNintendoSwitch) {
  181. EXPECT_EQ(check_sequence({0x82, 0xFF, 0x40, 0x40, 0xFF, 0x40, 0x40}), OS_LINUX);
  182. os_detection_task();
  183. assert_not_reported();
  184. }
  185. TEST_F(OsDetectionTest, TestVusbNintendoSwitch) {
  186. EXPECT_EQ(check_sequence({0x82, 0xFF, 0x40, 0x40}), OS_LINUX);
  187. os_detection_task();
  188. assert_not_reported();
  189. }
  190. TEST_F(OsDetectionTest, TestChibiosQuest2) {
  191. EXPECT_EQ(check_sequence({0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFE, 0xFF, 0xFE, 0xFF, 0xFE, 0xFF}), OS_LINUX);
  192. os_detection_task();
  193. assert_not_reported();
  194. }
  195. TEST_F(OsDetectionTest, TestVusbQuest2) {
  196. EXPECT_EQ(check_sequence({0xFF, 0xFF, 0xFF, 0xFE}), OS_LINUX);
  197. os_detection_task();
  198. assert_not_reported();
  199. }
  200. // Regression reported in https://github.com/qmk/qmk_firmware/pull/21777#issuecomment-1922815841
  201. TEST_F(OsDetectionTest, TestDetectMacM1AsIOS) {
  202. EXPECT_EQ(check_sequence({0x02, 0x32, 0x02, 0x24, 0x101, 0xFF}), OS_IOS);
  203. os_detection_task();
  204. assert_not_reported();
  205. }
  206. TEST_F(OsDetectionTest, TestDoNotReportIfUsbUnstable) {
  207. EXPECT_EQ(check_sequence({0xFF, 0xFF, 0xFF, 0xFE}), OS_LINUX);
  208. os_detection_task();
  209. assert_not_reported();
  210. advance_time(OS_DETECTION_DEBOUNCE);
  211. os_detection_task();
  212. assert_not_reported();
  213. EXPECT_EQ(detected_host_os(), OS_LINUX);
  214. }
  215. TEST_F(OsDetectionTest, TestReportAfterDebounce) {
  216. EXPECT_EQ(check_sequence({0xFF, 0xFF, 0xFF, 0xFE}), OS_LINUX);
  217. os_detection_notify_usb_device_state_change(USB_DEVICE_STATE_CONFIGURED);
  218. os_detection_task();
  219. assert_not_reported();
  220. advance_time(1);
  221. os_detection_task();
  222. assert_not_reported();
  223. EXPECT_EQ(detected_host_os(), OS_LINUX);
  224. advance_time(OS_DETECTION_DEBOUNCE - 3);
  225. os_detection_task();
  226. assert_not_reported();
  227. EXPECT_EQ(detected_host_os(), OS_LINUX);
  228. advance_time(1);
  229. os_detection_task();
  230. assert_not_reported();
  231. EXPECT_EQ(detected_host_os(), OS_LINUX);
  232. // advancing the timer alone must not cause a report
  233. advance_time(1);
  234. assert_not_reported();
  235. EXPECT_EQ(detected_host_os(), OS_LINUX);
  236. // the task will cause a report
  237. os_detection_task();
  238. assert_reported(OS_LINUX);
  239. EXPECT_EQ(detected_host_os(), OS_LINUX);
  240. // check that it remains the same after a long time
  241. advance_time(OS_DETECTION_DEBOUNCE * 15);
  242. assert_reported(OS_LINUX);
  243. EXPECT_EQ(detected_host_os(), OS_LINUX);
  244. }
  245. TEST_F(OsDetectionTest, TestReportAfterDebounceLongWait) {
  246. EXPECT_EQ(check_sequence({0x12, 0xFF, 0xFF, 0x4, 0x10, 0xFF, 0xFF, 0xFF, 0x4, 0x10, 0x20A, 0x20A, 0x20A, 0x20A, 0x20A, 0x20A}), OS_WINDOWS);
  247. os_detection_notify_usb_device_state_change(USB_DEVICE_STATE_CONFIGURED);
  248. os_detection_task();
  249. assert_not_reported();
  250. advance_time(1);
  251. os_detection_task();
  252. assert_not_reported();
  253. EXPECT_EQ(detected_host_os(), OS_WINDOWS);
  254. // advancing the timer alone must not cause a report
  255. advance_time(OS_DETECTION_DEBOUNCE * 15);
  256. assert_not_reported();
  257. EXPECT_EQ(detected_host_os(), OS_WINDOWS);
  258. // the task will cause a report
  259. os_detection_task();
  260. assert_reported(OS_WINDOWS);
  261. EXPECT_EQ(detected_host_os(), OS_WINDOWS);
  262. // check that it remains the same after a long time
  263. advance_time(OS_DETECTION_DEBOUNCE * 10);
  264. os_detection_task();
  265. assert_reported(OS_WINDOWS);
  266. EXPECT_EQ(detected_host_os(), OS_WINDOWS);
  267. }
  268. TEST_F(OsDetectionTest, TestReportUnsure) {
  269. EXPECT_EQ(check_sequence({0x12, 0xFF}), OS_UNSURE);
  270. os_detection_notify_usb_device_state_change(USB_DEVICE_STATE_CONFIGURED);
  271. os_detection_task();
  272. assert_not_reported();
  273. advance_time(1);
  274. os_detection_task();
  275. assert_not_reported();
  276. EXPECT_EQ(detected_host_os(), OS_UNSURE);
  277. // advancing the timer alone must not cause a report
  278. advance_time(OS_DETECTION_DEBOUNCE - 1);
  279. assert_not_reported();
  280. EXPECT_EQ(detected_host_os(), OS_UNSURE);
  281. // the task will cause a report
  282. os_detection_task();
  283. assert_reported(OS_UNSURE);
  284. EXPECT_EQ(detected_host_os(), OS_UNSURE);
  285. // check that it remains the same after a long time
  286. advance_time(OS_DETECTION_DEBOUNCE * 10);
  287. os_detection_task();
  288. assert_reported(OS_UNSURE);
  289. EXPECT_EQ(detected_host_os(), OS_UNSURE);
  290. }
  291. TEST_F(OsDetectionTest, TestDoNotReportIntermediateResults) {
  292. EXPECT_EQ(check_sequence({0x12, 0xFF}), OS_UNSURE);
  293. os_detection_notify_usb_device_state_change(USB_DEVICE_STATE_CONFIGURED);
  294. os_detection_task();
  295. assert_not_reported();
  296. advance_time(OS_DETECTION_DEBOUNCE - 1);
  297. os_detection_task();
  298. assert_not_reported();
  299. EXPECT_EQ(detected_host_os(), OS_UNSURE);
  300. // at this stage, the final result has not been reached yet
  301. EXPECT_EQ(check_sequence({0xFF}), OS_LINUX);
  302. os_detection_notify_usb_device_state_change(USB_DEVICE_STATE_CONFIGURED);
  303. advance_time(OS_DETECTION_DEBOUNCE - 1);
  304. os_detection_task();
  305. assert_not_reported();
  306. // the intermedite but yet unstable result is exposed through detected_host_os()
  307. EXPECT_EQ(detected_host_os(), OS_LINUX);
  308. // the remainder is processed
  309. EXPECT_EQ(check_sequence({0x4, 0x10, 0xFF, 0xFF, 0xFF, 0x4, 0x10, 0x20A, 0x20A, 0x20A, 0x20A, 0x20A, 0x20A}), OS_WINDOWS);
  310. os_detection_notify_usb_device_state_change(USB_DEVICE_STATE_CONFIGURED);
  311. advance_time(OS_DETECTION_DEBOUNCE - 1);
  312. os_detection_task();
  313. assert_not_reported();
  314. EXPECT_EQ(detected_host_os(), OS_WINDOWS);
  315. // advancing the timer alone must not cause a report
  316. advance_time(1);
  317. assert_not_reported();
  318. EXPECT_EQ(detected_host_os(), OS_WINDOWS);
  319. // the task will cause a report
  320. os_detection_task();
  321. assert_reported(OS_WINDOWS);
  322. EXPECT_EQ(detected_host_os(), OS_WINDOWS);
  323. // check that it remains the same after a long time
  324. advance_time(OS_DETECTION_DEBOUNCE * 10);
  325. os_detection_task();
  326. assert_reported(OS_WINDOWS);
  327. EXPECT_EQ(detected_host_os(), OS_WINDOWS);
  328. }
  329. TEST_F(OsDetectionTest, TestDoNotGoBackToUnsure) {
  330. // 0x02 would cause it to go back to Unsure, so check that it does not
  331. EXPECT_EQ(check_sequence({0xFF, 0xFF, 0xFF, 0xFE, 0x02}), OS_LINUX);
  332. os_detection_task();
  333. assert_not_reported();
  334. }