qmk_firmware

QMK firmware for my keyboards (Corne, Sweep Ferris) and trackball (Ploopy Adept)
Log | Files | Refs | Submodules | LICENSE

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