acid-drop

- Hacking the planet from a LilyGo T-Deck using custom firmware
git clone git://git.acid.vegas/acid-drop.git
Log | Files | Refs | Archive | README | LICENSE

AceButtonTest.ino (58698B)

      1 #line 2 "AceButtonTest.ino"
      2 /*
      3 MIT License
      4 
      5 Copyright (c) 2018 Brian T. Park
      6 
      7 Permission is hereby granted, free of charge, to any person obtaining a copy
      8 of this software and associated documentation files (the "Software"), to deal
      9 in the Software without restriction, including without limitation the rights
     10 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
     11 copies of the Software, and to permit persons to whom the Software is
     12 furnished to do so, subject to the following conditions:
     13 
     14 The above copyright notice and this permission notice shall be included in all
     15 copies or substantial portions of the Software.
     16 
     17 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     18 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     19 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
     20 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     21 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
     22 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
     23 SOFTWARE.
     24 */
     25 
     26 /*
     27  * Using Multiple Cpp Files:
     28  *
     29  * I tried to spread the tests of this .ino file into 6 .cpp files (and one
     30  * .h file), matching the 6 logical sections indicated below. Unfortunately,
     31  * on the AVR platform (Arduino Nano), the flash memory consumption increased
     32  * from 26768 (87%) to 28630 (93%), a difference of 1862 bytes. Since an Arduino
     33  * Nano has only 32720 bytes in flash, the difference of 1862 bytes (5.7%) is
     34  * signficant. I'm not sure where the flash consumption is coming from. Maybe
     35  * the compiler is includeing debugging information to the 6 additional .cpp
     36  * file names, or maybe the compiler/linker is using 4-bytes references to
     37  * various global variables instead of 2-bytes? For now, let's leave all the
     38  * tests in this single .ino file. I also noticed that changing from "const int
     39  * PIN = 13" to "#define PIN 13" (and the same with BUTTON_ID) in the .h header
     40  * file, the #define saved 210 bytes.
     41  *
     42  * On the Teensy-ARM platform (Teensy LC), using 6 separate .cpp files instead
     43  * of one giant .ino file caused the flash memory to *decrease* from 31408 to
     44  * 31204 bytes(!). And on the ARM platform, there was no difference in flash
     45  * memory size between "const int PIN = 13" and "#define PIN 13".
     46  *
     47  * Conclusion, this seems to be a problem with the avr-gcc compiler, or a
     48  * suboptimal compiler flags set by the Arduino IDE.
     49  */
     50 
     51 #define USE_AUNIT 1
     52 
     53 #if USE_AUNIT == 1
     54 #include <AUnit.h>
     55 #else
     56 #include <ArduinoUnit.h>
     57 #endif
     58 
     59 #include <AceButton.h>
     60 #include <ace_button/testing/TestableButtonConfig.h>
     61 #include <ace_button/testing/EventTracker.h>
     62 #include <ace_button/testing/TestHelper.h>
     63 
     64 using namespace ace_button;
     65 using namespace ace_button::testing;
     66 
     67 const uint8_t PIN = 13;
     68 const uint8_t BUTTON_ID = 1;
     69 
     70 ButtonConfig buttonConfig;
     71 
     72 TestableButtonConfig testableConfig;
     73 AceButton button(&testableConfig);
     74 EventTracker eventTracker;
     75 TestHelper helper(&testableConfig, &button, &eventTracker);
     76 
     77 // The event handler takes the arguments sent with the event and stored them
     78 // into the EventTracker circular buffer.
     79 void handleEvent(AceButton* /* button */, uint8_t eventType,
     80     uint8_t buttonState) {
     81   eventTracker.addEvent(eventType, buttonState);
     82 }
     83 
     84 void setup() {
     85   delay(1000); // Wait for stability on some boards, otherwise garage on Serial
     86   Serial.begin(115200); // ESP8266 default 74880 not supported on Linux
     87   while (!Serial); // for the Arduino Leonardo/Micro only
     88 
     89   testableConfig.setEventHandler(handleEvent);
     90 
     91   // The default was 50 ms (not the current 20 ms) when these tests were written
     92   // and some of the timing delays are hardcoded to assume that, so we have to
     93   // revert back to the old value.
     94   testableConfig.setDebounceDelay(50);
     95 
     96   Serial.print(F("sizeof(AceButton): "));
     97   Serial.println(sizeof(AceButton));
     98   Serial.print(F("sizeof(ButtonConfig): "));
     99   Serial.println(sizeof(ButtonConfig));
    100   Serial.print(F("sizeof(TestableButtonConfig): "));
    101   Serial.println(sizeof(TestableButtonConfig));
    102 
    103   /*
    104   aunit::TestRunner::exclude("*");
    105   aunit::TestRunner::include("suppress_click_before_double_click");
    106   */
    107 }
    108 
    109 void loop() {
    110 #if USE_AUNIT == 1
    111   aunit::TestRunner::run();
    112 #else
    113   Test::run();
    114 #endif
    115 }
    116 
    117 // ------------------------------------------------------------------
    118 // Basic tests
    119 // ------------------------------------------------------------------
    120 
    121 // Test that the pin is properly set and retrieved.
    122 test(pin) {
    123   const uint8_t DEFAULT_RELEASED_STATE = HIGH;
    124 
    125   helper.init(PIN, DEFAULT_RELEASED_STATE, BUTTON_ID);
    126   assertEqual(PIN, button.getPin());
    127 }
    128 
    129 // Test that the custom id is properly set and retrieved.
    130 test(custom_id) {
    131   const uint8_t DEFAULT_RELEASED_STATE = HIGH;
    132 
    133   // reset the button
    134   helper.init(PIN, DEFAULT_RELEASED_STATE, BUTTON_ID);
    135   assertEqual(BUTTON_ID, button.getId());
    136 }
    137 
    138 // Test that the getLastButtonPressed() returns BUTTON_STATE_UKNOWN initially.
    139 test(button_state_unknown) {
    140   const uint8_t DEFAULT_RELEASED_STATE = HIGH;
    141 
    142   // reset the button
    143   helper.init(PIN, DEFAULT_RELEASED_STATE, BUTTON_ID);
    144 
    145   uint8_t expected = AceButton::kButtonStateUnknown;
    146   assertEqual(expected, button.getLastButtonState());
    147 }
    148 
    149 test(feature_flags_off_by_default) {
    150   assertFalse(buttonConfig.isFeature(ButtonConfig::kFeatureClick));
    151   assertFalse(buttonConfig.isFeature(ButtonConfig::kFeatureDoubleClick));
    152   assertFalse(buttonConfig.isFeature(ButtonConfig::kFeatureLongPress));
    153   assertFalse(buttonConfig.isFeature(ButtonConfig::kFeatureRepeatPress));
    154 
    155   assertFalse(buttonConfig.isFeature(
    156       ButtonConfig::kFeatureSuppressAfterClick));
    157   assertFalse(buttonConfig.isFeature(
    158       ButtonConfig::kFeatureSuppressAfterDoubleClick));
    159   assertFalse(buttonConfig.isFeature(
    160       ButtonConfig::kFeatureSuppressAfterLongPress));
    161   assertFalse(buttonConfig.isFeature(
    162       ButtonConfig::kFeatureSuppressAfterRepeatPress));
    163 }
    164 
    165 // Test that the button transitions out of the kButtonStateUnknown after
    166 // getDebounceDelay() time.
    167 test(init_while_released) {
    168   uint8_t expected;
    169   const uint8_t DEFAULT_RELEASED_STATE = HIGH;
    170 
    171   // reset the button
    172   helper.init(PIN, DEFAULT_RELEASED_STATE, BUTTON_ID);
    173 
    174   // button is released when the board is rebooted, should trigger an immediate
    175   // debouncing
    176   helper.releaseButton(0);
    177   assertEqual(0, eventTracker.getNumEvents());
    178   expected = AceButton::kButtonStateUnknown;
    179   assertEqual(expected, button.getLastButtonState());
    180 
    181   // button is bouncing pressed/released, but must wait to debounce
    182   helper.pressButton(40);
    183   assertEqual(0, eventTracker.getNumEvents());
    184   expected = AceButton::kButtonStateUnknown;
    185   assertEqual(expected, button.getLastButtonState());
    186 
    187   // button is bouncing pressed/released, but must wait to debounce
    188   helper.releaseButton(45);
    189   assertEqual(0, eventTracker.getNumEvents());
    190   expected = AceButton::kButtonStateUnknown;
    191   assertEqual(expected, button.getLastButtonState());
    192 
    193   // finally button is known to be released, this doesn't not trigger event
    194   helper.releaseButton(60);
    195   assertEqual(0, eventTracker.getNumEvents());
    196   assertEqual(HIGH, button.getLastButtonState());
    197 }
    198 
    199 // Test that the button transitions out of the kButtonStateUnknown when
    200 // rebooted with the button pressed.
    201 test(init_while_pressed) {
    202   const uint8_t DEFAULT_RELEASED_STATE = HIGH;
    203   // reset the button
    204   helper.init(PIN, DEFAULT_RELEASED_STATE, BUTTON_ID);
    205   uint8_t expected;
    206 
    207   // button is pressed when the board is rebooted, should trigger an immediate
    208   // debouncing
    209   helper.pressButton(0);
    210   assertEqual(0, eventTracker.getNumEvents());
    211   expected = AceButton::kButtonStateUnknown;
    212   assertEqual(expected, button.getLastButtonState());
    213 
    214   // button is bouncing pressed/released, but must wait to debounce
    215   helper.releaseButton(40);
    216   assertEqual(0, eventTracker.getNumEvents());
    217   expected = AceButton::kButtonStateUnknown;
    218   assertEqual(expected, button.getLastButtonState());
    219 
    220   // button is bouncing pressed/released, but must wait to debounce
    221   helper.pressButton(45);
    222   assertEqual(0, eventTracker.getNumEvents());
    223   expected = AceButton::kButtonStateUnknown;
    224   assertEqual(expected, button.getLastButtonState());
    225 
    226   // finally button is known to be released, this doesn't not trigger event
    227   helper.pressButton(60);
    228   assertEqual(0, eventTracker.getNumEvents());
    229   assertEqual(LOW, button.getLastButtonState());
    230 }
    231 
    232 // Test that the TestableButtonConfig overrides the corresponding
    233 // parameters on AceButton properly.
    234 test(testable_config) {
    235   testableConfig.setClock(0);
    236   assertEqual(0UL, button.getButtonConfig()->getClock());
    237 
    238   testableConfig.setClock(40);
    239   assertEqual(40UL, button.getButtonConfig()->getClock());
    240 
    241   testableConfig.setButtonState(HIGH);
    242   assertEqual(HIGH, button.getButtonConfig()->readButton(0));
    243 
    244   testableConfig.setButtonState(LOW);
    245   assertEqual(LOW, button.getButtonConfig()->readButton(0));
    246 }
    247 
    248 // Test that the ButtonConfig parameters are mutable, just like the
    249 // original AdjustableButtonConfig.
    250 test(adjustable_config) {
    251   buttonConfig.setDebounceDelay(1);
    252   assertEqual((uint16_t)1, buttonConfig.getDebounceDelay());
    253 
    254   buttonConfig.setClickDelay(2);
    255   assertEqual((uint16_t)2, buttonConfig.getClickDelay());
    256 
    257   buttonConfig.setDoubleClickDelay(3);
    258   assertEqual((uint16_t)3, buttonConfig.getDoubleClickDelay());
    259 
    260   buttonConfig.setLongPressDelay(4);
    261   assertEqual((uint16_t)4, buttonConfig.getLongPressDelay());
    262 
    263   buttonConfig.setRepeatPressDelay(5);
    264   assertEqual((uint16_t)5, buttonConfig.getRepeatPressDelay());
    265 
    266   buttonConfig.setRepeatPressInterval(6);
    267   assertEqual((uint16_t)6, buttonConfig.getRepeatPressInterval());
    268 }
    269 
    270 // Detect if a button is pressed while the device is booted.
    271 test(is_released_raw) {
    272   const uint8_t DEFAULT_RELEASED_STATE = HIGH;
    273   button.init(PIN, DEFAULT_RELEASED_STATE, BUTTON_ID);
    274   testableConfig.init();
    275 
    276   testableConfig.setButtonState(HIGH);
    277   assertFalse(button.isPressedRaw());
    278 
    279   testableConfig.setButtonState(LOW);
    280   assertTrue(button.isPressedRaw());
    281 }
    282 
    283 // ------------------------------------------------------------------
    284 // Press and Release tests
    285 // ------------------------------------------------------------------
    286 
    287 // We assume this will be the common case because of the Aruino boards provide
    288 // internal pullup resistors on the digital input pins.
    289 test(press_and_release_pullup) {
    290   const uint8_t DEFAULT_RELEASED_STATE = HIGH;
    291   uint8_t expected;
    292 
    293   // reset the button
    294   helper.init(PIN, DEFAULT_RELEASED_STATE, BUTTON_ID);
    295 
    296   // initial button state
    297   helper.releaseButton(0);
    298   assertEqual(0, eventTracker.getNumEvents());
    299 
    300   // must wait until the initial debouncing
    301   helper.releaseButton(50);
    302   assertEqual(0, eventTracker.getNumEvents());
    303 
    304   // button pressed, but must wait to debounce
    305   helper.pressButton(100);
    306   assertEqual(0, eventTracker.getNumEvents());
    307 
    308   // still in debouncing period, so no event yet
    309   helper.releaseButton(110);
    310   assertEqual(0, eventTracker.getNumEvents());
    311 
    312   // after more than 50 ms, we should get an event
    313   helper.pressButton(190);
    314   assertEqual(1, eventTracker.getNumEvents());
    315   expected = AceButton::kEventPressed;
    316   assertEqual(expected, eventTracker.getRecord(0).getEventType());
    317   assertEqual(LOW, eventTracker.getRecord(0).getButtonState());
    318 
    319   // release the button
    320   helper.releaseButton(1000);
    321   assertEqual(0, eventTracker.getNumEvents());
    322 
    323   // wait more than 50 ms
    324   helper.releaseButton(1060);
    325   assertEqual(1, eventTracker.getNumEvents());
    326   expected = AceButton::kEventReleased;
    327   assertEqual(expected, eventTracker.getRecord(0).getEventType());
    328   assertEqual(HIGH, eventTracker.getRecord(0).getButtonState());
    329 }
    330 
    331 // Do the same test as press_and_release_pullup, but using
    332 // the logic levels of an external pulldown resistor.
    333 test(press_and_release_pulldown) {
    334   const uint8_t DEFAULT_RELEASED_STATE = LOW;
    335   uint8_t expected;
    336 
    337   // reset the button
    338   helper.init(PIN, DEFAULT_RELEASED_STATE, BUTTON_ID);
    339 
    340   // initial button state
    341   helper.releaseButton(0);
    342   assertEqual(0, eventTracker.getNumEvents());
    343 
    344   // must wait until the initial debouncing
    345   helper.releaseButton(50);
    346   assertEqual(0, eventTracker.getNumEvents());
    347 
    348   // button pressed, but must wait to debounce
    349   helper.pressButton(100);
    350   assertEqual(0, eventTracker.getNumEvents());
    351 
    352   // still in debouncing period, so no event yet
    353   helper.pressButton(110);
    354   assertEqual(0, eventTracker.getNumEvents());
    355 
    356   // after more than 50 ms, we should get an event
    357   helper.pressButton(190);
    358   assertEqual(1, eventTracker.getNumEvents());
    359   expected = AceButton::kEventPressed;
    360   assertEqual(expected, eventTracker.getRecord(0).getEventType());
    361 
    362   // release the button
    363   helper.releaseButton(1000);
    364   assertEqual(0, eventTracker.getNumEvents());
    365 
    366   // wait more than 50 ms
    367   helper.releaseButton(1060);
    368   assertEqual(1, eventTracker.getNumEvents());
    369   expected = AceButton::kEventReleased;
    370   assertEqual(expected, eventTracker.getRecord(0).getEventType());
    371   assertEqual(LOW, eventTracker.getRecord(0).getButtonState());
    372 }
    373 
    374 // The AceButton class uses 16-bit timer variables for memory efficiency.
    375 // Verify that we can rollover those variables without affecting the logic.
    376 test(clock_rollover) {
    377   const uint8_t DEFAULT_RELEASED_STATE = HIGH;
    378   const unsigned long BASE_TIME = 65500; // rolls over in 36 milliseconds
    379   uint8_t expected;
    380 
    381   // reset the button
    382   helper.init(PIN, DEFAULT_RELEASED_STATE, BUTTON_ID);
    383 
    384   // initial button state
    385   helper.releaseButton(BASE_TIME + 0);
    386   assertEqual(0, eventTracker.getNumEvents());
    387 
    388   // initialization phase, so no event yet
    389   helper.releaseButton(BASE_TIME + 60);
    390   assertEqual(0, eventTracker.getNumEvents());
    391 
    392   // press after the initialization phase, no event, must wait for debouncing
    393   helper.pressButton(BASE_TIME + 100);
    394   assertEqual(0, eventTracker.getNumEvents());
    395 
    396   // after more than 50 ms, we should get an event
    397   helper.pressButton(BASE_TIME + 190);
    398   assertEqual(1, eventTracker.getNumEvents());
    399   expected = AceButton::kEventPressed;
    400   assertEqual(expected, eventTracker.getRecord(0).getEventType());
    401   assertEqual(LOW, eventTracker.getRecord(0).getButtonState());
    402 
    403   // release the button
    404   helper.releaseButton(BASE_TIME + 1000);
    405   assertEqual(0, eventTracker.getNumEvents());
    406 
    407   // wait more than 50 ms
    408   helper.releaseButton(BASE_TIME + 1060);
    409   assertEqual(1, eventTracker.getNumEvents());
    410   expected = AceButton::kEventReleased;
    411   assertEqual(expected, eventTracker.getRecord(0).getEventType());
    412   assertEqual(HIGH, eventTracker.getRecord(0).getButtonState());
    413 }
    414 
    415 // ------------------------------------------------------------------
    416 // Click tests
    417 // ------------------------------------------------------------------
    418 
    419 // Test a single click.
    420 test(click_without_suppression) {
    421   const uint8_t DEFAULT_RELEASED_STATE = HIGH;
    422   const unsigned long BASE_TIME = 65500;
    423   uint8_t expected;
    424 
    425   // reset the button
    426   helper.init(PIN, DEFAULT_RELEASED_STATE, BUTTON_ID);
    427   testableConfig.setFeature(ButtonConfig::kFeatureClick);
    428 
    429   // initial button state
    430   helper.releaseButton(BASE_TIME + 0);
    431   assertEqual(0, eventTracker.getNumEvents());
    432 
    433   // initilization phase
    434   helper.releaseButton(BASE_TIME + 50);
    435   assertEqual(0, eventTracker.getNumEvents());
    436 
    437   // button pressed, but must wait to debounce
    438   helper.pressButton(BASE_TIME + 140);
    439   assertEqual(0, eventTracker.getNumEvents());
    440 
    441   // after 50 ms or more, we should get an event
    442   helper.pressButton(BASE_TIME + 190);
    443   assertEqual(1, eventTracker.getNumEvents());
    444   expected = AceButton::kEventPressed;
    445   assertEqual(expected, eventTracker.getRecord(0).getEventType());
    446   assertEqual(LOW, eventTracker.getRecord(0).getButtonState());
    447 
    448   // release the button within 200 ms for a click
    449   helper.releaseButton(BASE_TIME + 300);
    450   assertEqual(0, eventTracker.getNumEvents());
    451 
    452   // Wait another 50 ms to get event
    453   helper.releaseButton(BASE_TIME + 350);
    454   assertEqual(2, eventTracker.getNumEvents());
    455   expected = AceButton::kEventClicked;
    456   assertEqual(expected, eventTracker.getRecord(0).getEventType());
    457   assertEqual(HIGH, eventTracker.getRecord(0).getButtonState());
    458   expected = AceButton::kEventReleased;
    459   assertEqual(expected, eventTracker.getRecord(1).getEventType());
    460   assertEqual(HIGH, eventTracker.getRecord(1).getButtonState());
    461 }
    462 
    463 // Test a single click.
    464 test(click_with_suppression) {
    465   const uint8_t DEFAULT_RELEASED_STATE = HIGH;
    466   const unsigned long BASE_TIME = 65500;
    467   uint8_t expected;
    468 
    469   // reset the button
    470   helper.init(PIN, DEFAULT_RELEASED_STATE, BUTTON_ID);
    471   testableConfig.setFeature(ButtonConfig::kFeatureClick);
    472   testableConfig.setFeature(ButtonConfig::kFeatureSuppressAfterClick);
    473 
    474   // initial button state
    475   helper.releaseButton(BASE_TIME + 0);
    476   assertEqual(0, eventTracker.getNumEvents());
    477 
    478   // initilization phase
    479   helper.releaseButton(BASE_TIME + 50);
    480   assertEqual(0, eventTracker.getNumEvents());
    481 
    482   // button pressed, but must wait to debounce
    483   helper.pressButton(BASE_TIME + 140);
    484   assertEqual(0, eventTracker.getNumEvents());
    485 
    486   // after 50 ms or more, we should get an event
    487   helper.pressButton(BASE_TIME + 190);
    488   assertEqual(1, eventTracker.getNumEvents());
    489   expected = AceButton::kEventPressed;
    490   assertEqual(expected, eventTracker.getRecord(0).getEventType());
    491   assertEqual(LOW, eventTracker.getRecord(0).getButtonState());
    492 
    493   // release the button within 200 ms for a click
    494   helper.releaseButton(BASE_TIME + 300);
    495   assertEqual(0, eventTracker.getNumEvents());
    496 
    497   // Wait another 50 ms to get event
    498   helper.releaseButton(BASE_TIME + 350);
    499   assertEqual(1, eventTracker.getNumEvents());
    500   expected = AceButton::kEventClicked;
    501   assertEqual(expected, eventTracker.getRecord(0).getEventType());
    502   assertEqual(HIGH, eventTracker.getRecord(0).getButtonState());
    503 }
    504 
    505 // Test that no click generated with isFeature() flag off.
    506 test(no_click_without_feature_flag) {
    507   const uint8_t DEFAULT_RELEASED_STATE = HIGH;
    508   const unsigned long BASE_TIME = 65500;
    509   uint8_t expected;
    510 
    511   // reset the button
    512   // make sure isFeatureClick flag is cleared
    513   helper.init(PIN, DEFAULT_RELEASED_STATE, BUTTON_ID);
    514   testableConfig.clearFeature(ButtonConfig::kFeatureClick);
    515 
    516   // initial button state
    517   helper.releaseButton(BASE_TIME + 0);
    518   assertEqual(0, eventTracker.getNumEvents());
    519 
    520   // initilization phase
    521   helper.releaseButton(BASE_TIME + 50);
    522   assertEqual(0, eventTracker.getNumEvents());
    523 
    524   // button pressed, but must wait to debounce
    525   helper.pressButton(BASE_TIME + 140);
    526   assertEqual(0, eventTracker.getNumEvents());
    527 
    528   // after 50 ms or more, we should get an event
    529   helper.pressButton(BASE_TIME + 190);
    530   assertEqual(1, eventTracker.getNumEvents());
    531   expected = AceButton::kEventPressed;
    532   assertEqual(expected, eventTracker.getRecord(0).getEventType());
    533   assertEqual(LOW, eventTracker.getRecord(0).getButtonState());
    534 
    535   // release the button within 200 ms for a click
    536   helper.releaseButton(BASE_TIME + 300);
    537   assertEqual(0, eventTracker.getNumEvents());
    538 
    539   // Wait another 50 ms to get event. Only a Released event should be generated.
    540   helper.releaseButton(BASE_TIME + 350);
    541   assertEqual(1, eventTracker.getNumEvents());
    542   expected = AceButton::kEventReleased;
    543   assertEqual(expected, eventTracker.getRecord(0).getEventType());
    544   assertEqual(HIGH, eventTracker.getRecord(0).getButtonState());
    545 }
    546 
    547 // ------------------------------------------------------------------
    548 // DoubleClick tests
    549 // ------------------------------------------------------------------
    550 
    551 // Test a double click. Verify also that a triple-click does not generate a
    552 // spurious second double click. It should generate only the following:
    553 //  Pressed, Clicked, Pressed, DoubleClicked, Pressed, Clicked
    554 // because we have suppressed the Released events.
    555 test(double_click_suppressed) {
    556   const uint8_t DEFAULT_RELEASED_STATE = HIGH;
    557   const unsigned long BASE_TIME = 65500;
    558   uint8_t expected;
    559 
    560   // reset the button
    561   helper.init(PIN, DEFAULT_RELEASED_STATE, BUTTON_ID);
    562   testableConfig.setFeature(ButtonConfig::kFeatureDoubleClick);
    563   testableConfig.setFeature(ButtonConfig::kFeatureSuppressAfterClick);
    564   testableConfig.setFeature(ButtonConfig::kFeatureSuppressAfterDoubleClick);
    565 
    566   // initial button state
    567   helper.releaseButton(BASE_TIME + 0);
    568   assertEqual(0, eventTracker.getNumEvents());
    569 
    570   // initilization phase
    571   helper.releaseButton(BASE_TIME + 50);
    572   assertEqual(0, eventTracker.getNumEvents());
    573 
    574   // button pressed, but must wait to debounce
    575   helper.pressButton(BASE_TIME + 140);
    576   assertEqual(0, eventTracker.getNumEvents());
    577 
    578   // generate first click
    579 
    580   // after 50 ms or more, we should get an event
    581   helper.pressButton(BASE_TIME + 190);
    582   assertEqual(1, eventTracker.getNumEvents());
    583   expected = AceButton::kEventPressed;
    584   assertEqual(expected, eventTracker.getRecord(0).getEventType());
    585   assertEqual(LOW, eventTracker.getRecord(0).getButtonState());
    586 
    587   // release the button within 200 ms for a click, but must wait for debounce
    588   helper.releaseButton(BASE_TIME + 300);
    589   assertEqual(0, eventTracker.getNumEvents());
    590 
    591   // Wait another 50 ms for debounce.
    592   helper.releaseButton(BASE_TIME + 350);
    593   assertEqual(1, eventTracker.getNumEvents());
    594   expected = AceButton::kEventClicked;
    595   assertEqual(expected, eventTracker.getRecord(0).getEventType());
    596   assertEqual(HIGH, eventTracker.getRecord(0).getButtonState());
    597 
    598   // generate generate second click within 400 ms of the CLICK event (which
    599   // occurred at +350 ms) for a double click
    600 
    601   // button pressed, but must wait to debounce
    602   helper.pressButton(BASE_TIME + 500);
    603   assertEqual(0, eventTracker.getNumEvents());
    604 
    605   // after 50 ms or more, we should get an event
    606   helper.pressButton(BASE_TIME + 550);
    607   assertEqual(1, eventTracker.getNumEvents());
    608   expected = AceButton::kEventPressed;
    609   assertEqual(expected, eventTracker.getRecord(0).getEventType());
    610   assertEqual(LOW, eventTracker.getRecord(0).getButtonState());
    611 
    612   // release the button within 200 ms for a click, but must wait for debounce
    613   helper.releaseButton(BASE_TIME + 650);
    614   assertEqual(0, eventTracker.getNumEvents());
    615 
    616   // Wait another 50 ms for debounce. Should get a double-click.
    617   helper.releaseButton(BASE_TIME + 700);
    618   assertEqual(1, eventTracker.getNumEvents());
    619   expected = AceButton::kEventDoubleClicked;
    620   assertEqual(expected, eventTracker.getRecord(0).getEventType());
    621   assertEqual(HIGH, eventTracker.getRecord(0).getButtonState());
    622 
    623   // generate third click within 400 ms of the DoubleClicked event (which
    624   // occurred at +700 ms)
    625 
    626   // button pressed, but must wait to debounce
    627   helper.pressButton(BASE_TIME + 900);
    628   assertEqual(0, eventTracker.getNumEvents());
    629 
    630   // after 50 ms or more, we should get an event,
    631   helper.pressButton(BASE_TIME + 950);
    632   assertEqual(1, eventTracker.getNumEvents());
    633   expected = AceButton::kEventPressed;
    634   assertEqual(expected, eventTracker.getRecord(0).getEventType());
    635   assertEqual(LOW, eventTracker.getRecord(0).getButtonState());
    636 
    637   // release the button within 200 ms for a click, but must wait for debounce
    638   helper.releaseButton(BASE_TIME + 1050);
    639   assertEqual(0, eventTracker.getNumEvents());
    640 
    641   // Wait another 50 ms for debounce.
    642   // Verify that we get only 1 Clicked event not another DoubleClicked.
    643   helper.releaseButton(BASE_TIME + 1100);
    644   assertEqual(1, eventTracker.getNumEvents());
    645   expected = AceButton::kEventClicked;
    646   assertEqual(expected, eventTracker.getRecord(0).getEventType());
    647   assertEqual(HIGH, eventTracker.getRecord(0).getButtonState());
    648 }
    649 
    650 // Test a double click without kFeatureSuppressAfterDoubleClick.
    651 // Three rapid clicks should generate the following:
    652 //    Pressed, Released, Clicked, Pressed, Released, DoubleClicked, Pressed,
    653 //    Released, Clicked.
    654 test(double_click_not_suppressed) {
    655   const uint8_t DEFAULT_RELEASED_STATE = HIGH;
    656   const unsigned long BASE_TIME = 65500;
    657   uint8_t expected;
    658 
    659   // reset the button
    660   helper.init(PIN, DEFAULT_RELEASED_STATE, BUTTON_ID);
    661   testableConfig.setFeature(ButtonConfig::kFeatureDoubleClick);
    662 
    663   // initial button state
    664   helper.releaseButton(BASE_TIME + 0);
    665   assertEqual(0, eventTracker.getNumEvents());
    666 
    667   // initilization phase
    668   helper.releaseButton(BASE_TIME + 50);
    669   assertEqual(0, eventTracker.getNumEvents());
    670 
    671   // generate first click
    672 
    673   // button pressed, but must wait to debounce
    674   helper.pressButton(BASE_TIME + 140);
    675   assertEqual(0, eventTracker.getNumEvents());
    676 
    677   // after 50 ms or more, we should get an event
    678   helper.pressButton(BASE_TIME + 190);
    679   assertEqual(1, eventTracker.getNumEvents());
    680   expected = AceButton::kEventPressed;
    681   assertEqual(expected, eventTracker.getRecord(0).getEventType());
    682   assertEqual(LOW, eventTracker.getRecord(0).getButtonState());
    683 
    684   // release the button within 200 ms for a click, but must wait for debounce
    685   helper.releaseButton(BASE_TIME + 300);
    686   assertEqual(0, eventTracker.getNumEvents());
    687 
    688   // Wait another 50 ms for debounce.
    689   helper.releaseButton(BASE_TIME + 350);
    690   assertEqual(2, eventTracker.getNumEvents());
    691   expected = AceButton::kEventClicked;
    692   assertEqual(expected, eventTracker.getRecord(0).getEventType());
    693   assertEqual(HIGH, eventTracker.getRecord(0).getButtonState());
    694   expected = AceButton::kEventReleased;
    695   assertEqual(expected, eventTracker.getRecord(1).getEventType());
    696   assertEqual(HIGH, eventTracker.getRecord(1).getButtonState());
    697 
    698   // generate second click within 400 ms of the Clicked event (which
    699   // occurred at +350 ms) for a double click
    700 
    701   // button pressed, but must wait to debounce
    702   helper.pressButton(BASE_TIME + 500);
    703   assertEqual(0, eventTracker.getNumEvents());
    704 
    705   // after 50 ms or more, we should get an event
    706   helper.pressButton(BASE_TIME + 550);
    707   assertEqual(1, eventTracker.getNumEvents());
    708   expected = AceButton::kEventPressed;
    709   assertEqual(expected, eventTracker.getRecord(0).getEventType());
    710   assertEqual(LOW, eventTracker.getRecord(0).getButtonState());
    711 
    712   // release the button within 200 ms for a click, but must wait for debounce
    713   helper.releaseButton(BASE_TIME + 650);
    714   assertEqual(0, eventTracker.getNumEvents());
    715 
    716   // Wait another 50 ms for debounce. Should get a DoubleClicked, and a
    717   // Released because we don't suppress.
    718   helper.releaseButton(BASE_TIME + 700);
    719   assertEqual(2, eventTracker.getNumEvents());
    720   expected = AceButton::kEventDoubleClicked;
    721   assertEqual(expected, eventTracker.getRecord(0).getEventType());
    722   assertEqual(HIGH, eventTracker.getRecord(0).getButtonState());
    723   expected = AceButton::kEventReleased;
    724   assertEqual(expected, eventTracker.getRecord(1).getEventType());
    725   assertEqual(HIGH, eventTracker.getRecord(1).getButtonState());
    726 
    727   // generate third click within 400 ms of the DoubleClicked event (which
    728   // occurred at +700 ms)
    729 
    730   // button pressed, but must wait to debounce
    731   helper.pressButton(BASE_TIME + 900);
    732   assertEqual(0, eventTracker.getNumEvents());
    733 
    734   // after 50 ms or more, we should get an event,
    735   helper.pressButton(BASE_TIME + 950);
    736   assertEqual(1, eventTracker.getNumEvents());
    737   expected = AceButton::kEventPressed;
    738   assertEqual(expected, eventTracker.getRecord(0).getEventType());
    739   assertEqual(LOW, eventTracker.getRecord(0).getButtonState());
    740 
    741   // release the button within 200 ms for a click, but must wait for debounce
    742   helper.releaseButton(BASE_TIME + 1050);
    743   assertEqual(0, eventTracker.getNumEvents());
    744 
    745   // Wait another 50 ms for debounce.
    746   // Verify that we get only 1 Clicked event not another DoubleClicked,
    747   // and an unsuppressed Released.
    748   helper.releaseButton(BASE_TIME + 1100);
    749   assertEqual(2, eventTracker.getNumEvents());
    750   expected = AceButton::kEventClicked;
    751   assertEqual(expected, eventTracker.getRecord(0).getEventType());
    752   assertEqual(HIGH, eventTracker.getRecord(0).getButtonState());
    753   expected = AceButton::kEventReleased;
    754   assertEqual(expected, eventTracker.getRecord(1).getEventType());
    755   assertEqual(HIGH, eventTracker.getRecord(1).getButtonState());
    756 }
    757 
    758 // Test that no double clicks generated with isFeature() flag off.
    759 test(no_double_click_without_feature_flag) {
    760   const uint8_t DEFAULT_RELEASED_STATE = HIGH;
    761   const unsigned long BASE_TIME = 65500;
    762   uint8_t expected;
    763 
    764   // reset the button
    765   // make sure isFeatureDoubleClick flag is cleared
    766   helper.init(PIN, DEFAULT_RELEASED_STATE, BUTTON_ID);
    767   testableConfig.setFeature(ButtonConfig::kFeatureClick);
    768   testableConfig.clearFeature(ButtonConfig::kFeatureDoubleClick);
    769 
    770   // initial button state
    771   helper.releaseButton(BASE_TIME + 0);
    772   assertEqual(0, eventTracker.getNumEvents());
    773 
    774   // initilization phase
    775   helper.releaseButton(BASE_TIME + 50);
    776   assertEqual(0, eventTracker.getNumEvents());
    777 
    778   // generate first click
    779 
    780   // button pressed, but must wait to debounce
    781   helper.pressButton(BASE_TIME + 140);
    782   assertEqual(0, eventTracker.getNumEvents());
    783 
    784   // after 50 ms or more, we should get an event
    785   helper.pressButton(BASE_TIME + 190);
    786   assertEqual(1, eventTracker.getNumEvents());
    787   expected = AceButton::kEventPressed;
    788   assertEqual(expected, eventTracker.getRecord(0).getEventType());
    789   assertEqual(LOW, eventTracker.getRecord(0).getButtonState());
    790 
    791   // release the button within 200 ms for a click, but must wait for debounce
    792   helper.releaseButton(BASE_TIME + 300);
    793   assertEqual(0, eventTracker.getNumEvents());
    794 
    795   // Wait another 50 ms for debounce to get Released
    796   helper.releaseButton(BASE_TIME + 350);
    797   assertEqual(2, eventTracker.getNumEvents());
    798   expected = AceButton::kEventClicked;
    799   assertEqual(expected, eventTracker.getRecord(0).getEventType());
    800   assertEqual(HIGH, eventTracker.getRecord(0).getButtonState());
    801   expected = AceButton::kEventReleased;
    802   assertEqual(expected, eventTracker.getRecord(1).getEventType());
    803   assertEqual(HIGH, eventTracker.getRecord(1).getButtonState());
    804 
    805   // generate second click within 400 ms of the Clicked event (which
    806   // occurred at +350 ms) for a double click
    807 
    808   // button pressed, but must wait to debounce
    809   helper.pressButton(BASE_TIME + 500);
    810   assertEqual(0, eventTracker.getNumEvents());
    811 
    812   // after 50 ms or more, we should get an event
    813   helper.pressButton(BASE_TIME + 550);
    814   assertEqual(1, eventTracker.getNumEvents());
    815   expected = AceButton::kEventPressed;
    816   assertEqual(expected, eventTracker.getRecord(0).getEventType());
    817   assertEqual(LOW, eventTracker.getRecord(0).getButtonState());
    818 
    819   // release the button within 200 ms for a click, but must wait for debounce
    820   helper.releaseButton(BASE_TIME + 650);
    821   assertEqual(0, eventTracker.getNumEvents());
    822 
    823   // Wait another 50 ms for debounce. Should get just another click since
    824   // double-click is turned off.
    825   helper.releaseButton(BASE_TIME + 700);
    826   assertEqual(2, eventTracker.getNumEvents());
    827   expected = AceButton::kEventClicked;
    828   assertEqual(expected, eventTracker.getRecord(0).getEventType());
    829   assertEqual(HIGH, eventTracker.getRecord(0).getButtonState());
    830   expected = AceButton::kEventReleased;
    831   assertEqual(expected, eventTracker.getRecord(1).getEventType());
    832   assertEqual(HIGH, eventTracker.getRecord(1).getButtonState());
    833 }
    834 
    835 // Test that an orphaned click is properly removed to prevent spurious
    836 // double-click if the second click happens slightly over 65.536 seconds later.
    837 test(orphaned_click_cleared) {
    838   const uint8_t DEFAULT_RELEASED_STATE = HIGH;
    839   const unsigned long BASE_TIME = 65500;
    840   const unsigned long ROLLOVER_TIME = 65536;
    841   uint8_t expected;
    842 
    843   // reset the button, and enable double-click
    844   helper.init(PIN, DEFAULT_RELEASED_STATE, BUTTON_ID);
    845   testableConfig.setFeature(ButtonConfig::kFeatureClick);
    846   testableConfig.setFeature(ButtonConfig::kFeatureDoubleClick);
    847 
    848   // initial button state
    849   helper.releaseButton(BASE_TIME + 0);
    850   assertEqual(0, eventTracker.getNumEvents());
    851 
    852   // initilization phase
    853   helper.releaseButton(BASE_TIME + 50);
    854   assertEqual(0, eventTracker.getNumEvents());
    855 
    856   // button pressed, but must wait to debounce
    857   helper.pressButton(BASE_TIME + 140);
    858   assertEqual(0, eventTracker.getNumEvents());
    859 
    860   // after 50 ms or more, we should get an event
    861   helper.pressButton(BASE_TIME + 190);
    862   assertEqual(1, eventTracker.getNumEvents());
    863   expected = AceButton::kEventPressed;
    864   assertEqual(expected, eventTracker.getRecord(0).getEventType());
    865   assertEqual(LOW, eventTracker.getRecord(0).getButtonState());
    866 
    867   // release the button within 200 ms for a click, but must wait for debounce
    868   helper.releaseButton(BASE_TIME + 300);
    869   assertEqual(0, eventTracker.getNumEvents());
    870 
    871   // Wait another 50 ms to get event
    872   helper.releaseButton(BASE_TIME + 350);
    873   assertEqual(2, eventTracker.getNumEvents());
    874   expected = AceButton::kEventClicked;
    875   assertEqual(expected, eventTracker.getRecord(0).getEventType());
    876   assertEqual(HIGH, eventTracker.getRecord(0).getButtonState());
    877   expected = AceButton::kEventReleased;
    878   assertEqual(expected, eventTracker.getRecord(1).getEventType());
    879   assertEqual(HIGH, eventTracker.getRecord(1).getButtonState());
    880 
    881   // Move time forward, so that the orphaned click is cleared.
    882   // If AceButton.checkOrphanedClick() is disabled, or this statement is removed
    883   // (thereby preventing a call to checkOrphanedClick()), then the asserts below
    884   // will fail.
    885   helper.checkTime(BASE_TIME + 5000);
    886   assertEqual(0, eventTracker.getNumEvents());
    887 
    888   // Generate another click between (65.535s, 65.535s + 400 ms) of the first
    889   // CLICK event (i.e. +250 ms). If the first orphaned click was not properly
    890   // reset, then this will genearte a double click instead of a single click.
    891 
    892   // button pressed, but must wait to debounce
    893   helper.pressButton(ROLLOVER_TIME + BASE_TIME + 400);
    894   assertEqual(0, eventTracker.getNumEvents());
    895 
    896   // after 50 ms or more, we should get an event
    897   helper.pressButton(ROLLOVER_TIME + BASE_TIME + 450);
    898   assertEqual(1, eventTracker.getNumEvents());
    899   expected = AceButton::kEventPressed;
    900   assertEqual(expected, eventTracker.getRecord(0).getEventType());
    901   assertEqual(LOW, eventTracker.getRecord(0).getButtonState());
    902 
    903   // release the button within 200 ms for a click, but must wait for debounce
    904   helper.releaseButton(ROLLOVER_TIME + BASE_TIME + 550);
    905   assertEqual(0, eventTracker.getNumEvents());
    906 
    907   // Wait another 50 ms for debounce. Should get a single click, not
    908   // a double click.
    909   helper.releaseButton(ROLLOVER_TIME + BASE_TIME + 600);
    910   assertEqual(2, eventTracker.getNumEvents());
    911   expected = AceButton::kEventClicked;
    912   assertEqual(expected, eventTracker.getRecord(0).getEventType());
    913   assertEqual(HIGH, eventTracker.getRecord(0).getButtonState());
    914   expected = AceButton::kEventReleased;
    915   assertEqual(expected, eventTracker.getRecord(1).getEventType());
    916   assertEqual(HIGH, eventTracker.getRecord(1).getButtonState());
    917 }
    918 
    919 // Test that an orphaned click generates a double click if not cleared.
    920 test(orphaned_click_causes_double_click_if_not_cleared) {
    921   const uint8_t DEFAULT_RELEASED_STATE = HIGH;
    922   const unsigned long BASE_TIME = 65500;
    923   const unsigned long ROLLOVER_TIME = 65536;
    924   uint8_t expected;
    925 
    926   // reset the button, and enable double-click
    927   helper.init(PIN, DEFAULT_RELEASED_STATE, BUTTON_ID);
    928   testableConfig.setFeature(ButtonConfig::kFeatureClick);
    929   testableConfig.setFeature(ButtonConfig::kFeatureDoubleClick);
    930 
    931   // initial button state
    932   helper.releaseButton(BASE_TIME + 0);
    933   assertEqual(0, eventTracker.getNumEvents());
    934 
    935   // initilization phase
    936   helper.releaseButton(BASE_TIME + 50);
    937   assertEqual(0, eventTracker.getNumEvents());
    938 
    939   // button pressed, but must wait to debounce
    940   helper.pressButton(BASE_TIME + 140);
    941   assertEqual(0, eventTracker.getNumEvents());
    942 
    943   // after 50 ms or more, we should get an event
    944   helper.pressButton(BASE_TIME + 190);
    945   assertEqual(1, eventTracker.getNumEvents());
    946   expected = AceButton::kEventPressed;
    947   assertEqual(expected, eventTracker.getRecord(0).getEventType());
    948   assertEqual(LOW, eventTracker.getRecord(0).getButtonState());
    949 
    950   // release the button within 200 ms for a click, but must wait for debounce
    951   helper.releaseButton(BASE_TIME + 300);
    952   assertEqual(0, eventTracker.getNumEvents());
    953 
    954   // Wait another 50 ms to get event
    955   helper.releaseButton(BASE_TIME + 350);
    956   assertEqual(2, eventTracker.getNumEvents());
    957   expected = AceButton::kEventClicked;
    958   assertEqual(expected, eventTracker.getRecord(0).getEventType());
    959   assertEqual(HIGH, eventTracker.getRecord(0).getButtonState());
    960   expected = AceButton::kEventReleased;
    961   assertEqual(expected, eventTracker.getRecord(1).getEventType());
    962   assertEqual(HIGH, eventTracker.getRecord(1).getButtonState());
    963 
    964   // Simulate an orphaned click not getting cleared by not calling
    965   // AceButton.check() for 65536 milliseconds.
    966 
    967   // Generate another click between (65.535s, 65.535s + 400 ms) of the first
    968   // CLICK event (i.e. +250 ms). If the first orphaned click was not properly
    969   // reset, then this will genearte a double click instead of a single click.
    970 
    971   // button pressed, but must wait to debounce
    972   helper.pressButton(ROLLOVER_TIME + BASE_TIME + 400);
    973   assertEqual(0, eventTracker.getNumEvents());
    974 
    975   // after 50 ms or more, we should get an event
    976   helper.pressButton(ROLLOVER_TIME + BASE_TIME + 450);
    977   assertEqual(1, eventTracker.getNumEvents());
    978   expected = AceButton::kEventPressed;
    979   assertEqual(expected, eventTracker.getRecord(0).getEventType());
    980   assertEqual(LOW, eventTracker.getRecord(0).getButtonState());
    981 
    982   // release the button within 200 ms for a click, but must wait for debounce
    983   helper.releaseButton(ROLLOVER_TIME + BASE_TIME + 550);
    984   assertEqual(0, eventTracker.getNumEvents());
    985 
    986   // Wait another 50 ms for debounce. Should get a double click because the
    987   // orphaned click was not removed before the 16-bit integer overflowed .
    988   helper.releaseButton(ROLLOVER_TIME + BASE_TIME + 600);
    989   assertEqual(2, eventTracker.getNumEvents());
    990   expected = AceButton::kEventDoubleClicked;
    991   assertEqual(expected, eventTracker.getRecord(0).getEventType());
    992   assertEqual(HIGH, eventTracker.getRecord(0).getButtonState());
    993   expected = AceButton::kEventReleased;
    994   assertEqual(expected, eventTracker.getRecord(1).getEventType());
    995   assertEqual(HIGH, eventTracker.getRecord(1).getButtonState());
    996 }
    997 
    998 // Test that an orphaned click is removed if Click is enabled.
    999 test(orphaned_click_removed_if_click_enabled) {
   1000   const uint8_t DEFAULT_RELEASED_STATE = HIGH;
   1001   const unsigned long BASE_TIME = 65500;
   1002   const unsigned long ROLLOVER_TIME = 65536;
   1003   uint8_t expected;
   1004 
   1005   // reset the button, and enable double-click
   1006   helper.init(PIN, DEFAULT_RELEASED_STATE, BUTTON_ID);
   1007   testableConfig.setFeature(ButtonConfig::kFeatureClick);
   1008 
   1009   // initial button state
   1010   helper.releaseButton(BASE_TIME + 0);
   1011   assertEqual(0, eventTracker.getNumEvents());
   1012 
   1013   // initilization phase
   1014   helper.releaseButton(BASE_TIME + 50);
   1015   assertEqual(0, eventTracker.getNumEvents());
   1016 
   1017   // button pressed, but must wait to debounce
   1018   helper.pressButton(BASE_TIME + 140);
   1019   assertEqual(0, eventTracker.getNumEvents());
   1020 
   1021   // after 50 ms or more, we should get an event
   1022   helper.pressButton(BASE_TIME + 190);
   1023   assertEqual(1, eventTracker.getNumEvents());
   1024   expected = AceButton::kEventPressed;
   1025   assertEqual(expected, eventTracker.getRecord(0).getEventType());
   1026   assertEqual(LOW, eventTracker.getRecord(0).getButtonState());
   1027 
   1028   // release the button within 200 ms for a click, but must wait for debounce
   1029   helper.releaseButton(BASE_TIME + 300);
   1030   assertEqual(0, eventTracker.getNumEvents());
   1031 
   1032   // Wait another 50 ms to get event
   1033   helper.releaseButton(BASE_TIME + 350);
   1034   assertEqual(2, eventTracker.getNumEvents());
   1035   expected = AceButton::kEventClicked;
   1036   assertEqual(expected, eventTracker.getRecord(0).getEventType());
   1037   assertEqual(HIGH, eventTracker.getRecord(0).getButtonState());
   1038   expected = AceButton::kEventReleased;
   1039   assertEqual(expected, eventTracker.getRecord(1).getEventType());
   1040   assertEqual(HIGH, eventTracker.getRecord(1).getButtonState());
   1041 
   1042   // Move time forward, so that the orphaned click is cleared.
   1043   // If AceButton.checkOrphanedClick() is disabled, or this statement is removed
   1044   // (thereby preventing a call to checkOrphanedClick()), then the asserts below
   1045   // will fail.
   1046   helper.checkTime(BASE_TIME + 5000);
   1047   assertEqual(0, eventTracker.getNumEvents());
   1048 
   1049   // Turn on DoubleClick in the middle of click processing. If we called
   1050   // checkOrphanedClick() only if DoubleClick was enabled (instead of checking
   1051   // it when Click is enabled as well), then this change in ButtonConfig will
   1052   // cause this test to fail.
   1053   testableConfig.setFeature(ButtonConfig::kFeatureDoubleClick);
   1054 
   1055   // Generate another click between (65.535s, 65.535s + 400 ms) of the first
   1056   // CLICK event (i.e. +250 ms). If the first orphaned click was not properly
   1057   // reset, then this will genearte a double click instead of a single click.
   1058 
   1059   // button pressed, but must wait to debounce
   1060   helper.pressButton(ROLLOVER_TIME + BASE_TIME + 400);
   1061   assertEqual(0, eventTracker.getNumEvents());
   1062 
   1063   // after 50 ms or more, we should get an event
   1064   helper.pressButton(ROLLOVER_TIME + BASE_TIME + 450);
   1065   assertEqual(1, eventTracker.getNumEvents());
   1066   expected = AceButton::kEventPressed;
   1067   assertEqual(expected, eventTracker.getRecord(0).getEventType());
   1068   assertEqual(LOW, eventTracker.getRecord(0).getButtonState());
   1069 
   1070   // release the button within 200 ms for a click, but must wait for debounce
   1071   helper.releaseButton(ROLLOVER_TIME + BASE_TIME + 550);
   1072   assertEqual(0, eventTracker.getNumEvents());
   1073 
   1074   // Wait another 50 ms for debounce. Should get a single click, not
   1075   // a double click.
   1076   helper.releaseButton(ROLLOVER_TIME + BASE_TIME + 600);
   1077   assertEqual(2, eventTracker.getNumEvents());
   1078   expected = AceButton::kEventClicked;
   1079   assertEqual(expected, eventTracker.getRecord(0).getEventType());
   1080   assertEqual(HIGH, eventTracker.getRecord(0).getButtonState());
   1081   expected = AceButton::kEventReleased;
   1082   assertEqual(expected, eventTracker.getRecord(1).getEventType());
   1083   assertEqual(HIGH, eventTracker.getRecord(1).getButtonState());
   1084 }
   1085 
   1086 // Test that kFeatureSuppressClickBeforeDoubleClick causes the first Clicked to
   1087 // be postponed until it can determine if a DoubleClick actually occurred.
   1088 test(suppress_click_before_double_click) {
   1089   const uint8_t DEFAULT_RELEASED_STATE = HIGH;
   1090   const unsigned long BASE_TIME = 65500;
   1091   uint8_t expected;
   1092 
   1093   // reset the button
   1094   helper.init(PIN, DEFAULT_RELEASED_STATE, BUTTON_ID);
   1095   testableConfig.setFeature(ButtonConfig::kFeatureDoubleClick);
   1096   testableConfig.setFeature(
   1097       ButtonConfig::kFeatureSuppressClickBeforeDoubleClick);
   1098 
   1099   // initial button state
   1100   helper.releaseButton(BASE_TIME + 0);
   1101   assertEqual(0, eventTracker.getNumEvents());
   1102 
   1103   // initilization phase
   1104   helper.releaseButton(BASE_TIME + 50);
   1105   assertEqual(0, eventTracker.getNumEvents());
   1106 
   1107   // generate first click
   1108 
   1109   // button pressed, but must wait to debounce
   1110   helper.pressButton(BASE_TIME + 140);
   1111   assertEqual(0, eventTracker.getNumEvents());
   1112 
   1113   // after 50 ms or more, we should get an event
   1114   helper.pressButton(BASE_TIME + 190);
   1115   assertEqual(1, eventTracker.getNumEvents());
   1116   expected = AceButton::kEventPressed;
   1117   assertEqual(expected, eventTracker.getRecord(0).getEventType());
   1118   assertEqual(LOW, eventTracker.getRecord(0).getButtonState());
   1119 
   1120   // release the button within 200 ms for a click, but must wait for debounce
   1121   helper.releaseButton(BASE_TIME + 300);
   1122   assertEqual(0, eventTracker.getNumEvents());
   1123 
   1124   // Wait another 50 ms for debounce. Check that this first Click is
   1125   // postponed, so we get only the Released.
   1126   helper.releaseButton(BASE_TIME + 350);
   1127   assertEqual(1, eventTracker.getNumEvents());
   1128   expected = AceButton::kEventReleased;
   1129   assertEqual(expected, eventTracker.getRecord(0).getEventType());
   1130   assertEqual(HIGH, eventTracker.getRecord(0).getButtonState());
   1131 
   1132   // generate second click within 400 ms of the Clicked event (which
   1133   // occurred at +350 ms) for a double click
   1134 
   1135   // button pressed, but must wait to debounce
   1136   helper.pressButton(BASE_TIME + 500);
   1137   assertEqual(0, eventTracker.getNumEvents());
   1138 
   1139   // after 50 ms or more, we should get a Pressed
   1140   helper.pressButton(BASE_TIME + 550);
   1141   assertEqual(1, eventTracker.getNumEvents());
   1142   expected = AceButton::kEventPressed;
   1143   assertEqual(expected, eventTracker.getRecord(0).getEventType());
   1144   assertEqual(LOW, eventTracker.getRecord(0).getButtonState());
   1145 
   1146   // release the button within 200 ms for a click, but must wait for debounce
   1147   helper.releaseButton(BASE_TIME + 650);
   1148   assertEqual(0, eventTracker.getNumEvents());
   1149 
   1150   // Wait another 50 ms for debounce. Should get a (DoubleClicked, Released) but
   1151   // not a Clicked because we suppressed the first postponed Clicked.
   1152   helper.releaseButton(BASE_TIME + 700);
   1153   assertEqual(2, eventTracker.getNumEvents());
   1154   expected = AceButton::kEventDoubleClicked;
   1155   assertEqual(expected, eventTracker.getRecord(0).getEventType());
   1156   assertEqual(HIGH, eventTracker.getRecord(0).getButtonState());
   1157   expected = AceButton::kEventReleased;
   1158   assertEqual(expected, eventTracker.getRecord(1).getEventType());
   1159   assertEqual(HIGH, eventTracker.getRecord(1).getButtonState());
   1160 
   1161   // generate third click within 400 ms of the DoubleClicked event (which
   1162   // occurred at +700 ms)
   1163 
   1164   // button pressed, but must wait to debounce
   1165   helper.pressButton(BASE_TIME + 900);
   1166   assertEqual(0, eventTracker.getNumEvents());
   1167 
   1168   // after 50 ms or more, we should get a Pressed event
   1169   helper.pressButton(BASE_TIME + 950);
   1170   assertEqual(1, eventTracker.getNumEvents());
   1171   expected = AceButton::kEventPressed;
   1172   assertEqual(expected, eventTracker.getRecord(0).getEventType());
   1173   assertEqual(LOW, eventTracker.getRecord(0).getButtonState());
   1174 
   1175   // release the button within 200 ms for a click, but must wait for debounce
   1176   helper.releaseButton(BASE_TIME + 1050);
   1177   assertEqual(0, eventTracker.getNumEvents());
   1178 
   1179   // Wait another 50 ms for debounce.
   1180   // Verify that we get only a Released event not another DoubleClicked.
   1181   // The Clicked event is postponed again.
   1182   helper.releaseButton(BASE_TIME + 1100);
   1183   assertEqual(1, eventTracker.getNumEvents());
   1184   expected = AceButton::kEventReleased;
   1185   assertEqual(expected, eventTracker.getRecord(0).getEventType());
   1186   assertEqual(HIGH, eventTracker.getRecord(0).getButtonState());
   1187 
   1188   // Wait 300 ms, nothing should happen.
   1189   helper.checkTime(BASE_TIME + 1400);
   1190   assertEqual(0, eventTracker.getNumEvents());
   1191 
   1192   // Wait 400 ms to get the long postponed Clicked.
   1193   helper.checkTime(BASE_TIME + 1500);
   1194   assertEqual(1, eventTracker.getNumEvents());
   1195   assertEqual(+AceButton::kEventClicked,
   1196       eventTracker.getRecord(0).getEventType());
   1197   assertEqual(HIGH, eventTracker.getRecord(0).getButtonState());
   1198 }
   1199 
   1200 // ------------------------------------------------------------------
   1201 // LongPress tests
   1202 // ------------------------------------------------------------------
   1203 
   1204 // Test a long press without suppression should generate a released event at
   1205 // the end.
   1206 test(long_press_without_suppression) {
   1207   const uint8_t DEFAULT_RELEASED_STATE = HIGH;
   1208   const unsigned long BASE_TIME = 65500;
   1209   uint8_t expected;
   1210 
   1211   // reset the button
   1212   helper.init(PIN, DEFAULT_RELEASED_STATE, BUTTON_ID);
   1213   testableConfig.setFeature(ButtonConfig::kFeatureLongPress);
   1214 
   1215   // initial button state
   1216   helper.releaseButton(BASE_TIME + 0);
   1217   assertEqual(0, eventTracker.getNumEvents());
   1218 
   1219   // initilization phase
   1220   helper.releaseButton(BASE_TIME + 50);
   1221   assertEqual(0, eventTracker.getNumEvents());
   1222 
   1223   // button pressed, but must wait to debounce
   1224   helper.pressButton(BASE_TIME + 140);
   1225   assertEqual(0, eventTracker.getNumEvents());
   1226 
   1227   // after 50 ms or more, we should get an event
   1228   helper.pressButton(BASE_TIME + 190);
   1229   assertEqual(1, eventTracker.getNumEvents());
   1230   expected = AceButton::kEventPressed;
   1231   assertEqual(expected, eventTracker.getRecord(0).getEventType());
   1232   assertEqual(LOW, eventTracker.getRecord(0).getButtonState());
   1233 
   1234   // keeping holding the button
   1235   helper.pressButton(BASE_TIME + 1100);
   1236   assertEqual(0, eventTracker.getNumEvents());
   1237 
   1238   // keeping holding the button longer than 1000 ms
   1239   helper.pressButton(BASE_TIME + 1200);
   1240   assertEqual(1, eventTracker.getNumEvents());
   1241   expected = AceButton::kEventLongPressed;
   1242   assertEqual(expected, eventTracker.getRecord(0).getEventType());
   1243   assertEqual(LOW, eventTracker.getRecord(0).getButtonState());
   1244 
   1245   // finally release the button
   1246   helper.releaseButton(BASE_TIME + 1600);
   1247   assertEqual(0, eventTracker.getNumEvents());
   1248 
   1249   // Must wait for debouncing for the kEventReleased.
   1250   helper.releaseButton(BASE_TIME + 1660);
   1251   assertEqual(1, eventTracker.getNumEvents());
   1252   expected = AceButton::kEventReleased;
   1253   assertEqual(expected, eventTracker.getRecord(0).getEventType());
   1254   assertEqual(HIGH, eventTracker.getRecord(0).getButtonState());
   1255 }
   1256 
   1257 // Test a long press with suppression should produce no released event.
   1258 test(long_press_with_supression) {
   1259   const uint8_t DEFAULT_RELEASED_STATE = HIGH;
   1260   const unsigned long BASE_TIME = 65500;
   1261   uint8_t expected;
   1262 
   1263   // reset the button
   1264   helper.init(PIN, DEFAULT_RELEASED_STATE, BUTTON_ID);
   1265   testableConfig.setFeature(ButtonConfig::kFeatureLongPress);
   1266   testableConfig.setFeature(ButtonConfig::kFeatureSuppressAfterLongPress);
   1267 
   1268   // initial button state
   1269   helper.releaseButton(BASE_TIME + 0);
   1270   assertEqual(0, eventTracker.getNumEvents());
   1271 
   1272   // initilization phase
   1273   helper.releaseButton(BASE_TIME + 50);
   1274   assertEqual(0, eventTracker.getNumEvents());
   1275 
   1276   // button pressed, but must wait to debounce
   1277   helper.pressButton(BASE_TIME + 140);
   1278   assertEqual(0, eventTracker.getNumEvents());
   1279 
   1280   // after 50 ms or more, we should get an event
   1281   helper.pressButton(BASE_TIME + 190);
   1282   assertEqual(1, eventTracker.getNumEvents());
   1283   expected = AceButton::kEventPressed;
   1284   assertEqual(expected, eventTracker.getRecord(0).getEventType());
   1285   assertEqual(LOW, eventTracker.getRecord(0).getButtonState());
   1286 
   1287   // keeping holding the button
   1288   helper.pressButton(BASE_TIME + 1100);
   1289   assertEqual(0, eventTracker.getNumEvents());
   1290 
   1291   // keeping holding the button longer than 1000 ms
   1292   helper.pressButton(BASE_TIME + 1200);
   1293   assertEqual(1, eventTracker.getNumEvents());
   1294   expected = AceButton::kEventLongPressed;
   1295   assertEqual(expected, eventTracker.getRecord(0).getEventType());
   1296   assertEqual(LOW, eventTracker.getRecord(0).getButtonState());
   1297 
   1298   // finally release the button
   1299   helper.releaseButton(BASE_TIME + 1600);
   1300   assertEqual(0, eventTracker.getNumEvents());
   1301 
   1302   // Must wait for debouncing. We elected kFeatureSuppressAfterLongPress so
   1303   // no kEventReleased is generated.
   1304   helper.releaseButton(BASE_TIME + 1660);
   1305   assertEqual(0, eventTracker.getNumEvents());
   1306 }
   1307 
   1308 // Test that no LongPress generated with isFeature() flag off.
   1309 test(no_long_press_without_feature_flag) {
   1310   const uint8_t DEFAULT_RELEASED_STATE = HIGH;
   1311   const unsigned long BASE_TIME = 65500;
   1312   uint8_t expected;
   1313 
   1314   // reset the button
   1315   helper.init(PIN, DEFAULT_RELEASED_STATE, BUTTON_ID);
   1316   testableConfig.clearFeature(ButtonConfig::kFeatureLongPress);
   1317 
   1318   // initial button state
   1319   helper.releaseButton(BASE_TIME + 0);
   1320   assertEqual(0, eventTracker.getNumEvents());
   1321 
   1322   // initilization phase
   1323   helper.releaseButton(BASE_TIME + 50);
   1324   assertEqual(0, eventTracker.getNumEvents());
   1325 
   1326   // button pressed, but must wait to debounce
   1327   helper.pressButton(BASE_TIME + 140);
   1328   assertEqual(0, eventTracker.getNumEvents());
   1329 
   1330   // after 50 ms or more, we should get an event
   1331   helper.pressButton(BASE_TIME + 190);
   1332   assertEqual(1, eventTracker.getNumEvents());
   1333   expected = AceButton::kEventPressed;
   1334   assertEqual(expected, eventTracker.getRecord(0).getEventType());
   1335   assertEqual(LOW, eventTracker.getRecord(0).getButtonState());
   1336 
   1337   // keeping holding the button
   1338   helper.pressButton(BASE_TIME + 1100);
   1339   assertEqual(0, eventTracker.getNumEvents());
   1340 
   1341   // keeping holding the button longer than 1000 ms
   1342   helper.pressButton(BASE_TIME + 1200);
   1343   assertEqual(0, eventTracker.getNumEvents());
   1344 
   1345   // finally release the button
   1346   helper.releaseButton(BASE_TIME + 1600);
   1347   assertEqual(0, eventTracker.getNumEvents());
   1348 
   1349   // Must wait for debouncing. Only a Released event should be generated.
   1350   helper.releaseButton(BASE_TIME + 1660);
   1351   assertEqual(1, eventTracker.getNumEvents());
   1352   expected = AceButton::kEventReleased;
   1353   assertEqual(expected, eventTracker.getRecord(0).getEventType());
   1354   assertEqual(HIGH, eventTracker.getRecord(0).getButtonState());
   1355 }
   1356 
   1357 // ------------------------------------------------------------------
   1358 // RepeatPress tests
   1359 // ------------------------------------------------------------------
   1360 
   1361 // Test repeated press
   1362 test(repeat_press_without_suppression) {
   1363   const uint8_t DEFAULT_RELEASED_STATE = HIGH;
   1364   const unsigned long BASE_TIME = 65500;
   1365   uint8_t expected;
   1366 
   1367   // reset the button
   1368   helper.init(PIN, DEFAULT_RELEASED_STATE, BUTTON_ID);
   1369   testableConfig.setFeature(ButtonConfig::kFeatureRepeatPress);
   1370 
   1371   // initial button state
   1372   helper.releaseButton(BASE_TIME + 0);
   1373   assertEqual(0, eventTracker.getNumEvents());
   1374 
   1375   // initilization phase
   1376   helper.releaseButton(BASE_TIME + 50);
   1377   assertEqual(0, eventTracker.getNumEvents());
   1378 
   1379   // button pressed, but must wait to debounce
   1380   helper.pressButton(BASE_TIME + 140);
   1381   assertEqual(0, eventTracker.getNumEvents());
   1382 
   1383   // after 50 ms or more, we should get an event
   1384   helper.pressButton(BASE_TIME + 190);
   1385   assertEqual(1, eventTracker.getNumEvents());
   1386   expected = AceButton::kEventPressed;
   1387   assertEqual(expected, eventTracker.getRecord(0).getEventType());
   1388   assertEqual(LOW, eventTracker.getRecord(0).getButtonState());
   1389 
   1390   // keeping holding the button
   1391   helper.pressButton(BASE_TIME + 1100);
   1392   assertEqual(0, eventTracker.getNumEvents());
   1393 
   1394   // keeping holding the button longer than 1000 ms, the kEventRepeatPressed
   1395   // should trigger immediately after this duration
   1396   helper.pressButton(BASE_TIME + 1200);
   1397   assertEqual(1, eventTracker.getNumEvents());
   1398   expected = AceButton::kEventRepeatPressed;
   1399   assertEqual(expected, eventTracker.getRecord(0).getEventType());
   1400   assertEqual(LOW, eventTracker.getRecord(0).getButtonState());
   1401 
   1402   // keeping holding the button for longer than repeat interval (200ms)
   1403   helper.pressButton(BASE_TIME + 1400);
   1404   assertEqual(1, eventTracker.getNumEvents());
   1405   expected = AceButton::kEventRepeatPressed;
   1406   assertEqual(expected, eventTracker.getRecord(0).getEventType());
   1407   assertEqual(LOW, eventTracker.getRecord(0).getButtonState());
   1408 
   1409   // finally release the button
   1410   helper.releaseButton(BASE_TIME + 1700);
   1411   assertEqual(0, eventTracker.getNumEvents());
   1412 
   1413   // Must wait for debouncing for the kEventReleased.
   1414   helper.releaseButton(BASE_TIME + 1760);
   1415   assertEqual(1, eventTracker.getNumEvents());
   1416   expected = AceButton::kEventReleased;
   1417   assertEqual(expected, eventTracker.getRecord(0).getEventType());
   1418   assertEqual(HIGH, eventTracker.getRecord(0).getButtonState());
   1419 }
   1420 
   1421 // Test repeated press
   1422 test(repeat_press_with_suppression) {
   1423   const uint8_t DEFAULT_RELEASED_STATE = HIGH;
   1424   const unsigned long BASE_TIME = 65500;
   1425   uint8_t expected;
   1426 
   1427   // reset the button
   1428   helper.init(PIN, DEFAULT_RELEASED_STATE, BUTTON_ID);
   1429   testableConfig.setFeature(ButtonConfig::kFeatureRepeatPress);
   1430   testableConfig.setFeature(ButtonConfig::kFeatureSuppressAfterRepeatPress);
   1431 
   1432   // initial button state
   1433   helper.releaseButton(BASE_TIME + 0);
   1434   assertEqual(0, eventTracker.getNumEvents());
   1435 
   1436   // initilization phase
   1437   helper.releaseButton(BASE_TIME + 50);
   1438   assertEqual(0, eventTracker.getNumEvents());
   1439 
   1440   // button pressed, but must wait to debounce
   1441   helper.pressButton(BASE_TIME + 140);
   1442   assertEqual(0, eventTracker.getNumEvents());
   1443 
   1444   // after 50 ms or more, we should get an event
   1445   helper.pressButton(BASE_TIME + 190);
   1446   assertEqual(1, eventTracker.getNumEvents());
   1447   expected = AceButton::kEventPressed;
   1448   assertEqual(expected, eventTracker.getRecord(0).getEventType());
   1449   assertEqual(LOW, eventTracker.getRecord(0).getButtonState());
   1450 
   1451   // keeping holding the button
   1452   helper.pressButton(BASE_TIME + 1100);
   1453   assertEqual(0, eventTracker.getNumEvents());
   1454 
   1455   // keeping holding the button longer than 1000 ms, the kEventRepeatPressed
   1456   // should trigger immediately after this duration
   1457   helper.pressButton(BASE_TIME + 1200);
   1458   assertEqual(1, eventTracker.getNumEvents());
   1459   expected = AceButton::kEventRepeatPressed;
   1460   assertEqual(expected, eventTracker.getRecord(0).getEventType());
   1461   assertEqual(LOW, eventTracker.getRecord(0).getButtonState());
   1462 
   1463   // keeping holding the button for longer than repeat interval (200ms)
   1464   helper.pressButton(BASE_TIME + 1400);
   1465   assertEqual(1, eventTracker.getNumEvents());
   1466   expected = AceButton::kEventRepeatPressed;
   1467   assertEqual(expected, eventTracker.getRecord(0).getEventType());
   1468   assertEqual(LOW, eventTracker.getRecord(0).getButtonState());
   1469 
   1470   // finally release the button
   1471   helper.releaseButton(BASE_TIME + 1700);
   1472   assertEqual(0, eventTracker.getNumEvents());
   1473 
   1474   // Must wait for debouncing for the kEventReleased.
   1475   // But there is no Released event because of suppression.
   1476   helper.releaseButton(BASE_TIME + 1760);
   1477   assertEqual(0, eventTracker.getNumEvents());
   1478 }
   1479 
   1480 // Test that no RepeatPress generated with isFeature() flag off.
   1481 test(no_repeat_press_without_feature_flag) {
   1482   const uint8_t DEFAULT_RELEASED_STATE = HIGH;
   1483   const unsigned long BASE_TIME = 65500;
   1484   uint8_t expected;
   1485 
   1486   // reset the button
   1487   helper.init(PIN, DEFAULT_RELEASED_STATE, BUTTON_ID);
   1488   testableConfig.clearFeature(ButtonConfig::kFeatureRepeatPress);
   1489 
   1490   // initial button state
   1491   helper.releaseButton(BASE_TIME + 0);
   1492   assertEqual(0, eventTracker.getNumEvents());
   1493 
   1494   // initilization phase
   1495   helper.releaseButton(BASE_TIME + 50);
   1496   assertEqual(0, eventTracker.getNumEvents());
   1497 
   1498   // button pressed, but must wait to debounce
   1499   helper.pressButton(BASE_TIME + 140);
   1500   assertEqual(0, eventTracker.getNumEvents());
   1501 
   1502   // after 50 ms or more, we should get an event
   1503   helper.pressButton(BASE_TIME + 190);
   1504   assertEqual(1, eventTracker.getNumEvents());
   1505   expected = AceButton::kEventPressed;
   1506   assertEqual(expected, eventTracker.getRecord(0).getEventType());
   1507   assertEqual(LOW, eventTracker.getRecord(0).getButtonState());
   1508 
   1509   // keeping holding the button
   1510   helper.pressButton(BASE_TIME + 1100);
   1511   assertEqual(0, eventTracker.getNumEvents());
   1512 
   1513   // keeping holding the button longer than 1000 ms, nothing should
   1514   // should trigger
   1515   helper.pressButton(BASE_TIME + 1200);
   1516   assertEqual(0, eventTracker.getNumEvents());
   1517 
   1518   // keeping holding the button for longer than repeat interval (200ms)
   1519   helper.pressButton(BASE_TIME + 1400);
   1520   assertEqual(0, eventTracker.getNumEvents());
   1521 
   1522   // finally release the button
   1523   helper.releaseButton(BASE_TIME + 1700);
   1524   assertEqual(0, eventTracker.getNumEvents());
   1525 
   1526   // Must wait for debouncing. Only a Released event should be generated.
   1527   helper.releaseButton(BASE_TIME + 1760);
   1528   assertEqual(1, eventTracker.getNumEvents());
   1529   expected = AceButton::kEventReleased;
   1530   assertEqual(expected, eventTracker.getRecord(0).getEventType());
   1531   assertEqual(HIGH, eventTracker.getRecord(0).getButtonState());
   1532 }