logo

qmk_firmware

custom branch of QMK firmware git clone https://anongit.hacktivis.me/git/qmk_firmware.git

os_detection.cpp (14771B)


  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. return true;
  42. }
  43. void assert_not_reported(void) {
  44. // check that it does not report the result, nor any intermediate results
  45. EXPECT_EQ(reported_count, 0);
  46. EXPECT_EQ(reported_os, OS_UNSURE);
  47. }
  48. void assert_reported(os_variant_t os) {
  49. // check that it reports exclusively the result, not any intermediate results
  50. EXPECT_EQ(reported_count, 1);
  51. EXPECT_EQ(reported_os, os);
  52. EXPECT_EQ(reported_os, detected_host_os());
  53. }
  54. /* Some collected data.
  55. ChibiOS:
  56. 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]
  57. Windows 10 (another host): [FF, FF, 4, 24, 4, 24, 4, 24, 4, 24, 4, 24]
  58. macOS 12.5: [2, 24, 2, 28, FF]
  59. macOS 15.1.x: [ 2, 4E, 2, 1C, 2, 1A, FF, FF]
  60. macOS 15.x (another host): [ 2, 0E, 2, 1E, 2, 42, FF]
  61. macOS 15.x (periodic weirdness): [ 2, 42, 2, 1C, 2, 1A, FF, 2, 42, 2, 1C, 2, 1A, FF ]
  62. iOS/iPadOS 15.6: [2, 24, 2, 28]
  63. Linux (including Android, Raspberry Pi and WebOS TV): [FF, FF, FF]
  64. Linux (another host): [FF, FF, FF, FF, FF, FF]
  65. PS5: [2, 4, 2, 28, 2, 24]
  66. Nintendo Switch: [82, FF, 40, 40, FF, 40, 40, FF, 40, 40, FF, 40, 40, FF, 40, 40]
  67. Quest 2: [FF, FF, FF, FE, FF, FE, FF, FE, FF, FE, FF]
  68. LUFA:
  69. Windows 10 (first connect): [12, FF, FF, 4, 10, FF, FF, FF, 4, 10, 20A, 20A, 20A, 20A, 20A, 20A]
  70. Windows 10 (subsequent connect): [FF, FF, 4, 10, FF, 4, FF, 10, FF, 20A, 20A, 20A, 20A, 20A, 20A]
  71. Windows 10 (another host): [FF, FF, 4, 10, 4, 10]
  72. macOS: [2, 10, 2, E, FF]
  73. macOS 15.x: [ 2, 64, 2, 28, FF, FF]
  74. iOS/iPadOS: [2, 10, 2, E]
  75. Linux: [FF, FF, FF]
  76. PS5: [2, 4, 2, E, 2, 10]
  77. Nintendo Switch: [82, FF, 40, 40, FF, 40, 40]
  78. V-USB:
  79. Windows 10: [FF, FF, 4, E, FF]
  80. Windows 10 (another host): [FF, FF, 4, E, 4]
  81. macOS: [2, E, 2, E, FF]
  82. iOS/iPadOS: [2, E, 2, E]
  83. Linux: [FF, FF, FF]
  84. PS5: [2, 4, 2, E, 2]
  85. Nintendo Switch: [82, FF, 40, 40]
  86. Quest 2: [FF, FF, FF, FE]
  87. Common parts:
  88. Windows: [..., FF, FF, 4, ...]
  89. macOS: [2, _, 2, _, FF]
  90. iOS/iPadOS: [2, _, 2, _]
  91. Linux: [FF, FF, FF]
  92. PS5: [2, 4, 2, _, 2, ...]
  93. Nintendo Switch: [82, FF, 40, 40, ...]
  94. Quest 2: [FF, FF, FF, FE, ...]
  95. */
  96. TEST_F(OsDetectionTest, TestLinux) {
  97. EXPECT_EQ(check_sequence({0xFF, 0xFF, 0xFF}), OS_LINUX);
  98. os_detection_task();
  99. assert_not_reported();
  100. }
  101. TEST_F(OsDetectionTest, TestChibiosLinux) {
  102. EXPECT_EQ(check_sequence({0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}), OS_LINUX);
  103. os_detection_task();
  104. assert_not_reported();
  105. }
  106. TEST_F(OsDetectionTest, TestChibiosMacos) {
  107. EXPECT_EQ(check_sequence({0x2, 0x24, 0x2, 0x28, 0xFF}), OS_MACOS);
  108. os_detection_task();
  109. assert_not_reported();
  110. }
  111. TEST_F(OsDetectionTest, TestChibiosMacos2) {
  112. EXPECT_EQ(check_sequence({0x2, 0x42, 0x2, 0x1C, 0x2, 0x1A, 0xFF}), OS_MACOS);
  113. os_detection_task();
  114. assert_not_reported();
  115. }
  116. TEST_F(OsDetectionTest, TestChibiosMacos3) {
  117. EXPECT_EQ(check_sequence({0x2, 0x42, 0x2, 0x1C, 0x2, 0x1A, 0xFF, 0x2, 0x42, 0x2, 0x1C, 0x2, 0x1A, 0xFF}), OS_MACOS);
  118. os_detection_task();
  119. assert_not_reported();
  120. }
  121. // Regression reported in https://github.com/qmk/qmk_firmware/pull/21777#issuecomment-1922815841
  122. TEST_F(OsDetectionTest, TestChibiosMacM1) {
  123. EXPECT_EQ(check_sequence({0x02, 0x32, 0x02, 0x24, 0x101, 0xFF}), OS_MACOS);
  124. os_detection_task();
  125. assert_not_reported();
  126. }
  127. TEST_F(OsDetectionTest, TestChibiosMacSequoia) {
  128. EXPECT_EQ(check_sequence({0x02, 0x4E, 0x02, 0x1C, 0x02, 0x1A, 0xFF, 0xFF}), OS_MACOS);
  129. os_detection_task();
  130. assert_not_reported();
  131. }
  132. TEST_F(OsDetectionTest, TestChibiosMacSequoia2) {
  133. EXPECT_EQ(check_sequence({0x02, 0x4E, 0x02, 0x1C, 0x02, 0x1A, 0xFF, 0x02, 0x42, 0x02, 0x1C, 0x02, 0x1A, 0xFF}), OS_MACOS);
  134. os_detection_task();
  135. assert_not_reported();
  136. }
  137. TEST_F(OsDetectionTest, TestChibiosMacSequoia3) {
  138. EXPECT_EQ(check_sequence({0x02, 0x0E, 0x02, 0x1E, 0x02, 0x42, 0xFF}), OS_MACOS);
  139. os_detection_task();
  140. assert_not_reported();
  141. }
  142. TEST_F(OsDetectionTest, TestLufaMacos) {
  143. EXPECT_EQ(check_sequence({0x2, 0x10, 0x2, 0xE, 0xFF}), OS_MACOS);
  144. os_detection_task();
  145. assert_not_reported();
  146. }
  147. TEST_F(OsDetectionTest, TestDetectLufaMacSequoia2) {
  148. EXPECT_EQ(check_sequence({0x02, 0x64, 0x02, 0x28, 0xFF, 0xFF}), OS_MACOS);
  149. os_detection_task();
  150. assert_not_reported();
  151. }
  152. TEST_F(OsDetectionTest, TestVusbMacos) {
  153. EXPECT_EQ(check_sequence({0x2, 0xE, 0x2, 0xE, 0xFF}), OS_MACOS);
  154. os_detection_task();
  155. assert_not_reported();
  156. }
  157. TEST_F(OsDetectionTest, TestChibiosIos) {
  158. EXPECT_EQ(check_sequence({0x2, 0x24, 0x2, 0x28}), OS_IOS);
  159. os_detection_task();
  160. assert_not_reported();
  161. }
  162. TEST_F(OsDetectionTest, TestLufaIos) {
  163. EXPECT_EQ(check_sequence({0x2, 0x10, 0x2, 0xE}), OS_IOS);
  164. os_detection_task();
  165. assert_not_reported();
  166. }
  167. TEST_F(OsDetectionTest, TestVusbIos) {
  168. EXPECT_EQ(check_sequence({0x2, 0xE, 0x2, 0xE}), OS_IOS);
  169. os_detection_task();
  170. assert_not_reported();
  171. }
  172. TEST_F(OsDetectionTest, TestChibiosWindows10) {
  173. 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);
  174. os_detection_task();
  175. assert_not_reported();
  176. }
  177. TEST_F(OsDetectionTest, TestChibiosWindows10_2) {
  178. EXPECT_EQ(check_sequence({0xFF, 0xFF, 0x4, 0x24, 0x4, 0x24, 0x4, 0x24, 0x4, 0x24, 0x4, 0x24}), OS_WINDOWS);
  179. os_detection_task();
  180. assert_not_reported();
  181. }
  182. TEST_F(OsDetectionTest, TestLufaWindows10) {
  183. EXPECT_EQ(check_sequence({0x12, 0xFF, 0xFF, 0x4, 0x10, 0xFF, 0xFF, 0xFF, 0x4, 0x10, 0x20A, 0x20A, 0x20A, 0x20A, 0x20A, 0x20A}), OS_WINDOWS);
  184. os_detection_task();
  185. assert_not_reported();
  186. }
  187. TEST_F(OsDetectionTest, TestLufaWindows10_2) {
  188. EXPECT_EQ(check_sequence({0xFF, 0xFF, 0x4, 0x10, 0xFF, 0x4, 0xFF, 0x10, 0xFF, 0x20A, 0x20A, 0x20A, 0x20A, 0x20A, 0x20A}), OS_WINDOWS);
  189. os_detection_task();
  190. assert_not_reported();
  191. }
  192. TEST_F(OsDetectionTest, TestLufaWindows10_3) {
  193. EXPECT_EQ(check_sequence({0xFF, 0xFF, 0x4, 0x10, 0x4, 0x10}), OS_WINDOWS);
  194. os_detection_task();
  195. assert_not_reported();
  196. }
  197. TEST_F(OsDetectionTest, TestVusbWindows10) {
  198. EXPECT_EQ(check_sequence({0xFF, 0xFF, 0x4, 0xE, 0xFF}), OS_WINDOWS);
  199. os_detection_task();
  200. assert_not_reported();
  201. }
  202. TEST_F(OsDetectionTest, TestVusbWindows10_2) {
  203. EXPECT_EQ(check_sequence({0xFF, 0xFF, 0x4, 0xE, 0x4}), OS_WINDOWS);
  204. os_detection_task();
  205. assert_not_reported();
  206. }
  207. TEST_F(OsDetectionTest, TestChibiosPs5) {
  208. EXPECT_EQ(check_sequence({0x2, 0x4, 0x2, 0x28, 0x2, 0x24}), OS_LINUX);
  209. os_detection_task();
  210. assert_not_reported();
  211. }
  212. TEST_F(OsDetectionTest, TestLufaPs5) {
  213. EXPECT_EQ(check_sequence({0x2, 0x4, 0x2, 0xE, 0x2, 0x10}), OS_LINUX);
  214. os_detection_task();
  215. assert_not_reported();
  216. }
  217. TEST_F(OsDetectionTest, TestVusbPs5) {
  218. EXPECT_EQ(check_sequence({0x2, 0x4, 0x2, 0xE, 0x2}), OS_LINUX);
  219. os_detection_task();
  220. assert_not_reported();
  221. }
  222. TEST_F(OsDetectionTest, TestChibiosNintendoSwitch) {
  223. EXPECT_EQ(check_sequence({0x82, 0xFF, 0x40, 0x40, 0xFF, 0x40, 0x40, 0xFF, 0x40, 0x40, 0xFF, 0x40, 0x40, 0xFF, 0x40, 0x40}), OS_LINUX);
  224. os_detection_task();
  225. assert_not_reported();
  226. }
  227. TEST_F(OsDetectionTest, TestLufaNintendoSwitch) {
  228. EXPECT_EQ(check_sequence({0x82, 0xFF, 0x40, 0x40, 0xFF, 0x40, 0x40}), OS_LINUX);
  229. os_detection_task();
  230. assert_not_reported();
  231. }
  232. TEST_F(OsDetectionTest, TestVusbNintendoSwitch) {
  233. EXPECT_EQ(check_sequence({0x82, 0xFF, 0x40, 0x40}), OS_LINUX);
  234. os_detection_task();
  235. assert_not_reported();
  236. }
  237. TEST_F(OsDetectionTest, TestChibiosQuest2) {
  238. EXPECT_EQ(check_sequence({0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFE, 0xFF, 0xFE, 0xFF, 0xFE, 0xFF}), OS_LINUX);
  239. os_detection_task();
  240. assert_not_reported();
  241. }
  242. TEST_F(OsDetectionTest, TestVusbQuest2) {
  243. EXPECT_EQ(check_sequence({0xFF, 0xFF, 0xFF, 0xFE}), OS_LINUX);
  244. os_detection_task();
  245. assert_not_reported();
  246. }
  247. TEST_F(OsDetectionTest, TestDoNotReportIfUsbUnstable) {
  248. EXPECT_EQ(check_sequence({0xFF, 0xFF, 0xFF, 0xFE}), OS_LINUX);
  249. os_detection_task();
  250. assert_not_reported();
  251. advance_time(OS_DETECTION_DEBOUNCE);
  252. os_detection_task();
  253. assert_not_reported();
  254. EXPECT_EQ(detected_host_os(), OS_LINUX);
  255. }
  256. static struct usb_device_state usb_device_state_configured = {.configure_state = USB_DEVICE_STATE_CONFIGURED};
  257. TEST_F(OsDetectionTest, TestReportAfterDebounce) {
  258. EXPECT_EQ(check_sequence({0xFF, 0xFF, 0xFF, 0xFE}), OS_LINUX);
  259. os_detection_notify_usb_device_state_change(usb_device_state_configured);
  260. os_detection_task();
  261. assert_not_reported();
  262. advance_time(1);
  263. os_detection_task();
  264. assert_not_reported();
  265. EXPECT_EQ(detected_host_os(), OS_LINUX);
  266. advance_time(OS_DETECTION_DEBOUNCE - 3);
  267. os_detection_task();
  268. assert_not_reported();
  269. EXPECT_EQ(detected_host_os(), OS_LINUX);
  270. advance_time(1);
  271. os_detection_task();
  272. assert_not_reported();
  273. EXPECT_EQ(detected_host_os(), OS_LINUX);
  274. // advancing the timer alone must not cause a report
  275. advance_time(1);
  276. assert_not_reported();
  277. EXPECT_EQ(detected_host_os(), OS_LINUX);
  278. // the task will cause a report
  279. os_detection_task();
  280. assert_reported(OS_LINUX);
  281. EXPECT_EQ(detected_host_os(), OS_LINUX);
  282. // check that it remains the same after a long time
  283. advance_time(OS_DETECTION_DEBOUNCE * 15);
  284. assert_reported(OS_LINUX);
  285. EXPECT_EQ(detected_host_os(), OS_LINUX);
  286. }
  287. TEST_F(OsDetectionTest, TestReportAfterDebounceLongWait) {
  288. EXPECT_EQ(check_sequence({0x12, 0xFF, 0xFF, 0x4, 0x10, 0xFF, 0xFF, 0xFF, 0x4, 0x10, 0x20A, 0x20A, 0x20A, 0x20A, 0x20A, 0x20A}), OS_WINDOWS);
  289. os_detection_notify_usb_device_state_change(usb_device_state_configured);
  290. os_detection_task();
  291. assert_not_reported();
  292. advance_time(1);
  293. os_detection_task();
  294. assert_not_reported();
  295. EXPECT_EQ(detected_host_os(), OS_WINDOWS);
  296. // advancing the timer alone must not cause a report
  297. advance_time(OS_DETECTION_DEBOUNCE * 15);
  298. assert_not_reported();
  299. EXPECT_EQ(detected_host_os(), OS_WINDOWS);
  300. // the task will cause a report
  301. os_detection_task();
  302. assert_reported(OS_WINDOWS);
  303. EXPECT_EQ(detected_host_os(), OS_WINDOWS);
  304. // check that it remains the same after a long time
  305. advance_time(OS_DETECTION_DEBOUNCE * 10);
  306. os_detection_task();
  307. assert_reported(OS_WINDOWS);
  308. EXPECT_EQ(detected_host_os(), OS_WINDOWS);
  309. }
  310. TEST_F(OsDetectionTest, TestReportUnsure) {
  311. EXPECT_EQ(check_sequence({0x12, 0xFF}), OS_UNSURE);
  312. os_detection_notify_usb_device_state_change(usb_device_state_configured);
  313. os_detection_task();
  314. assert_not_reported();
  315. advance_time(1);
  316. os_detection_task();
  317. assert_not_reported();
  318. EXPECT_EQ(detected_host_os(), OS_UNSURE);
  319. // advancing the timer alone must not cause a report
  320. advance_time(OS_DETECTION_DEBOUNCE - 1);
  321. assert_not_reported();
  322. EXPECT_EQ(detected_host_os(), OS_UNSURE);
  323. // the task will cause a report
  324. os_detection_task();
  325. assert_reported(OS_UNSURE);
  326. EXPECT_EQ(detected_host_os(), OS_UNSURE);
  327. // check that it remains the same after a long time
  328. advance_time(OS_DETECTION_DEBOUNCE * 10);
  329. os_detection_task();
  330. assert_reported(OS_UNSURE);
  331. EXPECT_EQ(detected_host_os(), OS_UNSURE);
  332. }
  333. TEST_F(OsDetectionTest, TestDoNotReportIntermediateResults) {
  334. EXPECT_EQ(check_sequence({0x12, 0xFF}), OS_UNSURE);
  335. os_detection_notify_usb_device_state_change(usb_device_state_configured);
  336. os_detection_task();
  337. assert_not_reported();
  338. advance_time(OS_DETECTION_DEBOUNCE - 1);
  339. os_detection_task();
  340. assert_not_reported();
  341. EXPECT_EQ(detected_host_os(), OS_UNSURE);
  342. // at this stage, the final result has not been reached yet
  343. EXPECT_EQ(check_sequence({0xFF}), OS_LINUX);
  344. os_detection_notify_usb_device_state_change(usb_device_state_configured);
  345. advance_time(OS_DETECTION_DEBOUNCE - 1);
  346. os_detection_task();
  347. assert_not_reported();
  348. // the intermedite but yet unstable result is exposed through detected_host_os()
  349. EXPECT_EQ(detected_host_os(), OS_LINUX);
  350. // the remainder is processed
  351. EXPECT_EQ(check_sequence({0x4, 0x10, 0xFF, 0xFF, 0xFF, 0x4, 0x10, 0x20A, 0x20A, 0x20A, 0x20A, 0x20A, 0x20A}), OS_WINDOWS);
  352. os_detection_notify_usb_device_state_change(usb_device_state_configured);
  353. advance_time(OS_DETECTION_DEBOUNCE - 1);
  354. os_detection_task();
  355. assert_not_reported();
  356. EXPECT_EQ(detected_host_os(), OS_WINDOWS);
  357. // advancing the timer alone must not cause a report
  358. advance_time(1);
  359. assert_not_reported();
  360. EXPECT_EQ(detected_host_os(), OS_WINDOWS);
  361. // the task will cause a report
  362. os_detection_task();
  363. assert_reported(OS_WINDOWS);
  364. EXPECT_EQ(detected_host_os(), OS_WINDOWS);
  365. // check that it remains the same after a long time
  366. advance_time(OS_DETECTION_DEBOUNCE * 10);
  367. os_detection_task();
  368. assert_reported(OS_WINDOWS);
  369. EXPECT_EQ(detected_host_os(), OS_WINDOWS);
  370. }
  371. TEST_F(OsDetectionTest, TestDoNotGoBackToUnsure) {
  372. // 0x02 would cause it to go back to Unsure, so check that it does not
  373. EXPECT_EQ(check_sequence({0xFF, 0xFF, 0xFF, 0xFE, 0x02}), OS_LINUX);
  374. os_detection_task();
  375. assert_not_reported();
  376. }