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 |
README.md (40586B)
1 # AceButton 2 3 An adjustable, compact, event-driven button library for Arduino platforms. 4 5 Version: 1.3.3 (2019-03-10) 6 7 [![AUniter Jenkins Badge](https://us-central1-xparks2018.cloudfunctions.net/badge?project=AceButton)](https://github.com/bxparks/AUniter) 8 9 ## Summary 10 11 This library provides classes which accept inputs from a mechanical button 12 connected to a digital input pin on the Arduino. The library should be able to 13 handle momentary buttons, maintained buttons, and switches, but it was designed 14 primarily for momentary buttons. 15 16 The library is called the ACE Button Library (or AceButton Library) because: 17 18 * many configurations of the button are **adjustable**, either at compile-time 19 or run-time 20 * the library is optimized to create **compact** objects which take up 21 a minimal amount of static memory 22 * the library detects changes in the button state and sends **events** to 23 a user-defined `EventHandler` callback function 24 25 Most of the features of the library can be accessed through 2 classes and 26 1 callback function: 27 28 * `AceButton` (class) 29 * `ButtonConfig` (class) 30 * `EventHandler` (typedef) 31 32 The `AceButton` class contains the logic for debouncing and determining if a 33 particular event has occurred. The `ButtonConfig` class holds various timing 34 parameters, the event handler, code for reading the button, and code for 35 getting the internal clock. The `EventHandler` is a user-defined callback 36 function with a specific signature which is registered with the `ButtonConfig` 37 object. When the library detects interesting events, the callback function is 38 called by the library, allowing the client code to handle the event. 39 40 The supported events are: 41 42 * `AceButton::kEventPressed` 43 * `AceButton::kEventReleased` 44 * `AceButton::kEventClicked` 45 * `AceButton::kEventDoubleClicked` 46 * `AceButton::kEventLongPressed` 47 * `AceButton::kEventRepeatPressed` 48 49 (TripleClicked is not supported but can be easily added to the library if 50 requested.) 51 52 ### Features 53 54 Here are the high-level features of the AceButton library: 55 56 * debounces the mechanical contact 57 * supports both pull-up and pull-down wiring 58 * event-driven through a user-defined `EventHandler` callback funcition 59 * supports 6 event types: 60 * Pressed 61 * Released 62 * Clicked 63 * DoubleClicked 64 * LongPressed 65 * RepeatPressed 66 * can distinguish between Clicked and DoubleClicked 67 * adjustable configurations at runtime or compile-time 68 * timing parameters 69 * `digitalRead()` button read function can be overridden 70 * `millis()` clock function can be overridden 71 * small memory footprint 72 * each `AceButton` consumes 14 bytes 73 * each `ButtonConfig` consumes 20 bytes 74 * one System `ButtonConfig` instance created automatically by the library 75 * thoroughly unit tested using [AUnit](https://github.com/bxparks/AUnit) 76 * properly handles reboots while the button is pressed 77 * properly handles orphaned clicks, to prevent spurious double-clicks 78 * only 13-15 microseconds (on 16MHz ATmega328P) per polling call to `AceButton::check()` 79 * can be instrumented to extract profiling numbers 80 * tested on Arduino AVR (UNO, Nano, etc), Teensy ARM (LC 81 and 3.2), ESP8266 and ESP32 platforms 82 83 Compared to other Arduino button libraries, I think the unique or exceptional 84 features of the AceButton library are: 85 86 * many supported event types (e.g. LongPressed and RepeatPressed) 87 * able to distinguish between Clicked and DoubleClicked 88 * small memory usage 89 * thorough unit testing 90 * proper handling of orphaned clicks 91 * proper handling of a reboot while button is pressed 92 93 ### Non-goals 94 95 An Arduino UNO or Nano has 16 times more flash memory (32KB) than static memory 96 (2KB), so the library is optimized to minimize the static memory usage. The 97 AceButton library is not optimized to create a small program size (i.e. flash 98 memory), or for small CPU cycles (i.e. high execution speed). I assumed that if 99 you are seriously optimizing for program size or CPU cycles, you will probably 100 want to write everything yourself from scratch. 101 102 That said, the [examples/AutoBenchmark](examples/AutoBenchmark) program 103 shows that `AceButton::check()` takes between 13-15 microseconds on a 16MHz 104 ATmega328P chip on average. Hopefully that is fast enough for the vast 105 majority of people. 106 107 ### HelloButton 108 109 Here is a simple program (see `examples/HelloButton.ino`) which controls 110 the builtin LED on the Arduino board using a momentary button connected 111 to PIN 2. 112 113 ```C++ 114 #include <AceButton.h> 115 using namespace ace_button; 116 117 const int BUTTON_PIN = 2; 118 const int LED_ON = HIGH; 119 const int LED_OFF = LOW; 120 121 AceButton button(BUTTON_PIN); 122 123 void handleEvent(AceButton*, uint8_t, uint8_t); 124 125 void setup() { 126 pinMode(LED_BUILTIN, OUTPUT); 127 pinMode(BUTTON_PIN, INPUT_PULLUP); 128 button.setEventHandler(handleEvent); 129 } 130 131 void loop() { 132 button.check(); 133 } 134 135 void handleEvent(AceButton* /* button */, uint8_t eventType, 136 uint8_t /* buttonState */) { 137 switch (eventType) { 138 case AceButton::kEventPressed: 139 digitalWrite(LED_BUILTIN, LED_ON); 140 break; 141 case AceButton::kEventReleased: 142 digitalWrite(LED_BUILTIN, LED_OFF); 143 break; 144 } 145 } 146 ``` 147 148 (The `button` and `buttonState` parameters are commented out to avoid an `unused 149 parameter` warning from the compiler. We can't remove the parameters completely 150 because the method signature is defined by the `EventHandler` typedef.) 151 152 ## Installation 153 154 The latest stable release is available in the Arduino IDE Library Manager. 155 Search for "AceButton". Click install. 156 157 The development version can be installed by cloning the 158 [GitHub repository](https://github.com/bxparks/AceButton), checking out the 159 `develop` branch, then manually copying over the contents to the `./libraries` 160 directory used by the Arduino IDE. (The result is a directory named 161 `./libraries/AceButton`.) The `master` branch contains the stable release. 162 163 ### Source Code 164 165 The source files are organized as follows: 166 * `src/AceButton.h` - main header file 167 * `src/ace_button/` - all implementation files 168 * `src/ace_button/testing/` - internal testing files 169 * `tests/` - unit tests which require [AUnit](https://github.com/bxparks/AUnit) 170 * `examples/` - example sketches 171 172 ### Docs 173 174 Besides this README.md file, the [docs/](docs/) directory contains the 175 [Doxygen docs published on GitHub Pages](https://bxparks.github.io/AceButton/html/). 176 It can help you navigate an unfamiliar code base. 177 178 ### Examples 179 180 The following example sketches are provided: 181 182 * [HelloButton.ino](examples/HelloButton) 183 * minimal program that reads a switch and control the built-in LED 184 * [SingleButton.ino](examples/SingleButton) 185 * controls a single button wired with a pull-up resistor 186 * prints out a status line for every supported event 187 * [SingleButtonPullDown.ino](examples/SingleButtonPullDown) 188 * same as SingleButton.ino but with an external pull-down resistor 189 * [Stopwatch.ino](examples/Stopwatch) 190 * measures the speed of `AceButton:check()` with a start/stop/reset button 191 * uses `kFeatureLongPress` 192 * [TunerButtons.ino](examples/TunerButtons) 193 * implements 5 radio buttons (tune-up, tune-down, and 3 presets) 194 * shows multiple `ButtonConfig` instances 195 * shows multiple `EventHandler`s 196 * shows an example of how to use `getId()` 197 * uses `kFeatureLongPress`, `kFeatureRepeatPress`, 198 `kFeatureSuppressAfterLongPress`, and `kFeatureSuppressAfterRepeatPress` 199 * [ClickVersusDoubleClickUsingReleased.ino](examples/ClickVersusDoubleClickUsingReleased) 200 * a way to distinguish between a `kEventClicked` from a 201 `kEventDoubleClicked` using a `kEventReleased` instead 202 * [ClickVersusDoubleClickUsingSuppression.ino](examples/ClickVersusDoubleClickUsingSuppression) 203 * another way to dstinguish between a `kEventClicked` from a 204 `kEventDoubleClicked` using the `kFeatureSuppressClickBeforeDoubleClick` 205 flag at the cost of increasing the response time of the `kEventClicked` 206 event 207 * [ClickVersusDoubleClickUsingBoth.ino](examples/ClickVersusDoubleClickUsingBoth) 208 * an example that combines both the "UsingPressed" and "UsingSuppression" 209 techniques 210 * [CapacitiveButton](examples/CapacitiveButton) 211 * reads a capacitive button using the 212 [CapacitiveSensor](https://github.com/PaulStoffregen/CapacitiveSensor) 213 library 214 * [AutoBenchmark.ino](examples/AutoBenchmark) 215 * generates the timing stats (min/average/max) for the `AceButton::check()` 216 method for various types of events (idle, press/release, click, 217 double-click, and long-press) 218 219 ## Usage 220 221 There are 2 classes and one typedef that a user will normally interact with: 222 223 * `AceButton` (class) 224 * `ButtonConfig` (class) 225 * `EventHandler` (typedef) 226 227 We explain how to use these below. 228 229 ### Include Header and Use Namespace 230 231 Only a single header file `AceButton.h` is required to use this library. 232 To prevent name clashes with other libraries that the calling code may use, all 233 classes are defined in the `ace_button` namespace. To use the code without 234 prepending the `ace_button::` prefix, use the `using` directive: 235 236 ```C++ 237 #include <AceButton.h> 238 using namespace ace_button; 239 ``` 240 241 If you are dependent on just `AceButton`, the following might be sufficient: 242 243 ```C++ 244 #include <AceButton.h> 245 using ace_button::AceButton; 246 ``` 247 248 ### Pin Wiring and Initialization 249 250 An Arduino microcontroller pin can be in an `OUTPUT` mode, an `INPUT` mode, or 251 an `INPUT_PULLUP` mode. This mode is controlled by the `pinMode()` method. 252 253 By default upon boot, the pin is set to the `INPUT` mode. However, this `INPUT` 254 mode puts the pin into a high impedance state, which means that if there is no 255 wire connected to the pin, the voltage on the pin is indeterminant. When the 256 input pin is read (using `digitalRead()`), the boolean value will be a random 257 value. If you are using the pin in `INPUT` mode, you *must* connect an external 258 pull-up resistor (connected to Vcc) or pull-down resistor (connected to ground) 259 so that the voltage level of the pin is defined when there is nothing connected 260 to the pin (i.e. when the button is not pressed). 261 262 The `INPUT_PULLUP` mode is a special `INPUT` mode which tells the 263 microcontroller to connect an internal pull-up resistor to the pin. It is 264 activated by calling `pintMode(pin, INPUT_PULLUP)` on the given `pin`. This mode 265 is very convenient because it eliminates the external resistor, making the 266 wiring simpler. 267 268 The AceButton library itself does *not* call the `pinMode()` function. The 269 calling application is responsible for calling `pinMode()`. Normally, this 270 happens in the global `setup()` method but the call can happen somewhere else if 271 the application requires it. The reason for decoupling the hardware 272 configuration from the AceButton library is mostly because the library does not 273 actually care about the specific hardware wiring of the button. It does not care 274 whether an external resistor is used, or the internal resistor is used. It only 275 cares about whether the resistor is a pull-up or a pull-down. 276 277 See https://www.arduino.cc/en/Tutorial/DigitalPins for additional information 278 about the I/O pins on an Arduino. 279 280 ### AceButton Class 281 282 Each physical button will be handled by an instance of `AceButton`. At a 283 minimum, the instance needs to be told the pin number of the button. This can 284 be done through the constructor: 285 286 ```C++ 287 const uint8_t BUTTON_PIN = 2; 288 289 AceButton button(BUTTON_PIN); 290 291 void setup() { 292 pinMode(BUTTON_PIN, INPUT_PULLUP); 293 ... 294 } 295 ``` 296 297 Or we can use the `init()` method in the `setup()`: 298 299 ```C++ 300 AceButton button; 301 302 void setup() { 303 pinMode(BUTTON_PIN, INPUT_PULLUP); 304 button.init(BUTTON_PIN); 305 ... 306 } 307 ``` 308 309 Both the constructor and the `init()` function take 3 optional parameters: 310 ```C++ 311 AceButton(uint8_t pin = 0, uint8_t defaultReleasedState = HIGH, uint8_t id = 0); 312 313 void init(uint8_t pin = 0, uint8_t defaultReleasedState = HIGH, uint8_t id = 0); 314 ``` 315 316 * `pin`: the I/O pin number assigned to the button 317 * `defaultReleasedState`: the logical value of the button when it is in its 318 default "released" state (`HIGH` using a pull-up resistor, 319 `LOW` for a pull-down pull-down resistor) 320 * `id`: an optional, user-defined identifier for the the button, 321 for example, an index into an array with additional information 322 323 The `pin` must be defined either through the constructor or the `init()` method. 324 But the other two parameters may be optional in many cases. 325 326 Finally, the `AceButton::check()` method should be called from the `loop()` 327 method periodically. Roughly speaking, this should be about 4 times faster than 328 the value of `getDebounceDelay()` so that the various event detection logic can 329 work properly. (If the debounce delay is 20 ms, `AceButton::check()` should be 330 called every 5 ms or faster.) 331 332 ```C++ 333 void loop() { 334 ... 335 button.check(); 336 ... 337 } 338 ``` 339 340 ### ButtonConfig Class 341 342 The core concept of the AceButton library is the separation of the 343 button (`AceButton`) from its configuration (`ButtonConfig`). 344 345 * The `AceButton` class has the logic for debouncing and detecting the various 346 events (Pressed, Released, etc), and the various bookkeeping variables 347 needed to implement the logic. These variables are associated with the 348 specific instance of that `AceButton`. 349 * The `ButtonConfig` class has the various timing parameters which control 350 how much time is needed to detect certain events. This class also has the 351 ability to override the default methods for reading the pin (`readButton()`) 352 and the clock (`getClock()`). This ability allows unit tests to be written. 353 354 The `ButtonConfig` can be created and assigned to one or more `AceButton` 355 instances using dependency injection through the `AceButton(ButtonConfig*)` 356 constructor. If this constructor is used, then the `AceButton::init()` method 357 must be used to set the pin number of the button. For example: 358 359 ```C++ 360 const uint8_t PIN1 = 2; 361 const uint8_t PIN2 = 4; 362 363 ButtonConfig buttonConfig; 364 AceButton button1(&buttonConfig); 365 AceButton button2(&buttonConfig); 366 367 void setup() { 368 pinMode(PIN1, INPUT_PULLUP); 369 button1.init(PIN1); 370 371 pinMode(PIN2, INPUT_PULLUP); 372 button2.init(PIN2); 373 ... 374 } 375 ``` 376 377 Another way to inject the `ButtonConfig` dependency is to use the 378 `AceButton::setButtonConfig()` method but it is recommended that you use the 379 constructor instead because the dependency is easier to follow. 380 381 #### System ButtonConfig 382 383 A single instance of `ButtonConfig` called the "System ButtonConfig" is 384 automatically created by the library at startup. By default, all instances of 385 `AceButton` are automatically assigned to this singleton instance. We explain in 386 the _Single Button Simplifications_ section below how this simplifies the code 387 needed to handle a single button. 388 389 #### Configuring the EventHandler 390 391 The `ButtonConfig` class provides a number of methods which are mostly 392 used internally by the `AceButton` class. The one method which is expected 393 to be used by the calling client code is `setEventHandler()` which 394 assigns the user-defined `EventHandler` callback function to the `ButtonConfig` 395 instance. This is explained in more detail below in the 396 _EventHandler Callback_ section. 397 398 #### Timing Parameters 399 400 Here are the methods to retrieve the timing parameters: 401 402 * `uint16_t getDebounceDelay();` (default: 20 ms) 403 * `uint16_t getClickDelay();` (default: 200 ms) 404 * `uint16_t getDoubleClickDelay();` (default: 400 ms) 405 * `uint16_t getLongPressDelay();` (default: 1000 ms) 406 * `uint16_t getRepeatPressDelay();` (default: 1000 ms) 407 * `uint16_t getRepeatPressInterval();` (default: 200 ms) 408 409 The default values of each timing parameter can be changed at run-time using 410 the following methods: 411 412 * `void setDebounceDelay(uint16_t debounceDelay);` 413 * `void setClickDelay(uint16_t clickDelay);` 414 * `void setDoubleClickDelay(uint16_t doubleClickDelay);` 415 * `void setLongPressDelay(uint16_t longPressDelay);` 416 * `void setRepeatPressDelay(uint16_t repeatPressDelay);` 417 * `void setRepeatPressInterval(uint16_t repeatPressInterval);` 418 419 #### Hardware Dependencies 420 421 The `ButtonConfig` class has 2 methods which provide hooks to its external 422 hardware dependencies: 423 424 * `virtual unsigned long getClock();` 425 * `virtual int readButton(uint8_t pin);` 426 427 By default these are mapped to the underlying Arduino system functions respectively: 428 429 * `millis()` 430 * `digitalRead()` 431 432 Unit tests are possible because these methods are `virtual` and the hardware 433 dependencies can be swapped out with fake ones. 434 435 #### Multiple ButtonConfig Instances 436 437 We have assumed that there is a 1-to-many relationship between a `ButtonConfig` 438 and the `AceButton`. In other words, multiple buttons will normally be 439 associated with a single configuration. Each `AceButton` has a pointer to an 440 instance of `ButtonConfig`. So the cost of separating the `ButtonConfig` from 441 `AceButton` is 2 bytes in each instance of `AceButton`. Note that this is 442 equivalent to adding virtual methods to `AceButton` (which would add 2 bytes), 443 so in terms of static RAM size, this is a wash. 444 445 The library is designed to handle multiple buttons, and it assumes that the 446 buttons are normally grouped together into a handful of types. For example, 447 consider the buttons of a car radio. It has several types of buttons: 448 449 * the tuner buttons (2, up and down) 450 * the preset buttons (6) 451 * the AM/FM band button (1) 452 453 In this example, there are 9 buttons, but only 3 instances of `ButtonConfig` 454 would be needed. 455 456 ### EventHandler 457 458 The event handler is a callback function that gets called when the `AceButton` 459 class determines that an interesting event happened on the button. The 460 advantage of this mechanism is that all the complicated logic of determining 461 the various events happens inside the `AceButton` class, and the user will 462 normally not need to worry about the details. 463 464 #### EventHandler Signature 465 466 The event handler has the following signature: 467 468 ```C++ 469 typedef void (*EventHandler)(AceButton* button, uint8_t eventType, 470 uint8_t buttonState); 471 ``` 472 473 The event handler is registered with the `ButtonConfig` object, not with the 474 `AceButton` object, although the convenience method 475 `AceButton::setEventHandler()` is provided as a pass-through to the underlying 476 `ButtonConfig` (see the _Single Button Simplifications_ section below): 477 478 ```C++ 479 ButtonConfig buttonConfig; 480 481 void handleEvent(AceButton* button, uint8_t eventType, uint8_t buttonState) { 482 ... 483 } 484 485 void setup() { 486 ... 487 buttonConfig.setEventHandler(handleEvent); 488 ... 489 } 490 ``` 491 492 The motivation for this design is to save static memory. If multiple buttons 493 are associated with a single `ButtonConfig`, then it is not necessary for every 494 button of that type to hold the same pointer to the `EventHandler` function. It 495 is only necessary to save that information once, in the `ButtonConfig` object. 496 497 **Pro Tip**: Comment out the unused parameter(s) in the `handleEvent()` method 498 to avoid the `unused parameter` compiler warning: 499 ```C++ 500 void handleEvent(AceButton* /* button */, uint8_t eventType, 501 uint8_t /* buttonState */) { 502 ... 503 } 504 ``` 505 The Arduino sketch compiler can get confused with the parameters commented out, 506 so you may need to add a forward declaration for the `handleEvent()` method 507 before the `setup()` method: 508 ```C++ 509 void handleEvent(AceButton*, uint8_t, uint8_t); 510 ``` 511 512 #### EventHandler Parameters 513 514 The `EventHandler` function receives 3 parameters from the `AceButton`: 515 516 * `aceButton` 517 * pointer to the `AceButton` instance that generated this event 518 * can be used to retrieve the `getPin()` or the `getId()` 519 * `eventType` 520 * the type of this event given by the various `AceButton::kEventXxx` 521 constants 522 * `buttonState` 523 * the `HIGH` or `LOW` button state that generated this event 524 525 The `aceButton` pointer should be used only to extract information about the 526 button that triggered the event. It should **not** be used to modify the 527 button's internal variables in any way within the eventHandler. The logic in 528 `AceButton::check()` assumes that those internal variable are held constant, 529 and if they are changed by the eventHandler, unpredictable results may occur. 530 (I was tempted to make the `aceButton` a pointer to a `const AceButton` 531 but this cause too many viral changes to the code which seemed to increase 532 the complexity without too much benefit.) 533 534 If you are using only a single button, then you should need to check 535 only the `eventType`. 536 537 It is not expected that `buttonState` will be needed very often. It should be 538 sufficient to examine just the `eventType` to determine the action that needs 539 to be performed. Part of the difficulty with this parameter is that it has the 540 value of `LOW` or `HIGH`, but the physical interpretation of those values depends 541 on whether the button was wired with a pull-up or pull-down resistor. The helper 542 function `AceButton::isReleased(uint8_t buttonState)` is provided to make this 543 determination if you need it. 544 545 #### One EventHandler 546 547 Only a single `EventHandler` per `ButtonConfig` is supported. An alternative 548 would have been to register a separate event handler for each of the 6 549 `kEventXxx` events. But each callback function requires 2 bytes of memory, and 550 it was assumed that in most cases, the calling client code would be interested 551 in only a few of these event types, so it seemed wasteful to allocate 12 bytes 552 when most of these would be unused. If the client code really wanted separate 553 event handlers, it can be easily emulated by invoking them through the main 554 event handler: 555 556 ```C++ 557 void handleEvent(AceButton* button, uint8_t eventType, uint8_t buttonState) { 558 switch (eventType) { 559 case AceButton:kEventPressed: 560 handleEventPressed(button, eventType, buttonState); 561 break; 562 case AceButton::kEventReleased: 563 handleEventReleased(button, eventType, buttonState); 564 break; 565 ... 566 } 567 } 568 ``` 569 570 #### EventHandler Tips 571 572 The Arduino runtime environment is single-threaded, so the `EventHandler` is 573 called in the middle of the `AceButton::check()` method, in the same thread as 574 the `check()` method. It is therefore important to write the `EventHandler` 575 code to run somewhat quickly, so that the delay doesn't negatively impact the 576 logic of the `AceButton::check()` algorithm. Since `AceButton::check()` should 577 run approximately every 5 ms, the user-provided `EventHandler` should run 578 somewhat faster than 5 ms. Given a choice, it is probably better to use the 579 `EventHandler` to set some flags or variables and return quickly, then do 580 additional processing from the `loop()` method. 581 582 Speaking of threads, the API of the AceButton Library was designed to work in a 583 multi-threaded environment, if that situation were to occur in the Arduino 584 world. 585 586 ### Event Types 587 588 The supported events are defined by a list of constants in `AceButton`: 589 590 * `AceButton::kEventPressed` (always enabled) 591 * `AceButton::kEventReleased` (conditionally enabled) 592 * `AceButton::kEventClicked` (default: disabled) 593 * `AceButton::kEventDoubleClicked` (default: disabled) 594 * `AceButton::kEventLongPressed` (default: disabled) 595 * `AceButton::kEventRepeatPressed` (default: disabled) 596 597 These values are sent to the `EventHandler` in the `eventType` parameter. 598 599 Two of the events are enabled by default, four are disabled by default but can 600 be enabled by using a Feature flag described below. 601 602 ### ButtonConfig Feature Flags 603 604 There are 9 flags defined in `ButtonConfig` which can 605 control the behavior of `AceButton` event handling: 606 607 * `ButtonConfig::kFeatureClick` 608 * `ButtonConfig::kFeatureDoubleClick` 609 * `ButtonConfig::kFeatureLongPress` 610 * `ButtonConfig::kFeatureRepeatPress` 611 * `ButtonConfig::kFeatureSuppressAfterClick` 612 * `ButtonConfig::kFeatureSuppressAfterDoubleClick` 613 * `ButtonConfig::kFeatureSuppressAfterLongPress` 614 * `ButtonConfig::kFeatureSuppressAfterRepeatPress` 615 * `ButtonConfig::kFeatureSuppressClickBeforeDoubleClick` 616 * `ButtonConfig::kFeatureSuppressAll` 617 618 These constants are used to set or clear the given flag: 619 620 ```C++ 621 ButtonConfig* config = button.getButtonConfig(); 622 623 config->setFeature(ButtonConfig::kFeatureLongPress); 624 625 config->clearFeature(ButtonConfig::kFeatureLongPress); 626 627 if (config->isFeature(ButtonConfig::kFeatureLongPress)) { 628 ... 629 } 630 ``` 631 632 The meaning of these flags are described below. 633 634 #### Event Activation 635 636 Of the 6 event types, 4 are disabled by default: 637 638 * `AceButton::kEventClicked` 639 * `AceButton::kEventDoubleClicked` 640 * `AceButton::kEventLongPressed` 641 * `AceButton::kEventRepeatPressed` 642 643 To receive these events, call `ButtonConfig::setFeature()` with the following 644 flags respectively: 645 646 * `ButtonConfig::kFeatureClick` 647 * `ButtonConfig::kFeatureDoubleClick` 648 * `ButtonConfig::kFeatureLongPress` 649 * `ButtonConfig::kFeatureRepeatPress` 650 651 To disable these events, call `ButtonConfig::clearFeature()` with one of these 652 flags. 653 654 Enabling `kFeatureDoubleClick` automatically enables `kFeatureClick`, because we 655 need to have a Clicked event before a DoubleClicked event can be detected. 656 657 It seems unlikely that both `LongPress` and `RepeatPress` events would be 658 useful at the same time, but both event types can be activated if you need it. 659 660 #### Event Suppression 661 662 Event types can be considered to be built up in layers, starting with the 663 lowest level primitive events: Pressed and Released. Higher level events are 664 built on top of the lower level events through various timing delays. When a 665 higher level event is detected, it is sometimes useful to suppress the lower 666 level event that was used to detect the higher level event. 667 668 For example, a Clicked event requires a Pressed event followed by a Released 669 event within a `ButtonConfig::getClickDelay()` milliseconds (200 ms by 670 default). The Pressed event is always generated. If a Clicked event is 671 detected, we could choose to generate both a Released event and a Clicked 672 event, and this is the default behavior. 673 674 However, many times, it is useful to suppress the Released event if the Clicked 675 event is detected. The `ButtonConfig` can be configured to suppress these lower 676 level events. Call the `setFeature(feature)` method passing the various 677 `kFeatureSuppressXxx` constants: 678 679 * `ButtonConfig::kFeatureSuppressAfterClick` 680 * suppresses the Released event after a Clicked event is detected 681 * also suppresses the Released event from the *first* Clicked of a 682 DoubleClicked, since `kFeatureDoubleClick` automatically enables 683 `kFeatureClick` 684 * `ButtonConfig::kFeatureSuppressAfterDoubleClick` 685 * suppresses the Released event and the *second* Clicked event if a 686 DoubleClicked event is detected 687 * `ButtonConfig::kFeatureSuppressAfterLongPress` 688 * suppresses the Released event if a LongPressed event is detected 689 * `ButtonConfig::kFeatureSuppressAfterRepeatPress` 690 * suppresses the Released event after the last RepeatPressed event 691 * `ButtonConfig::kFeatureSuppressAll` 692 * a convenience parameter that is the equivalent of suppressing all of the 693 previous events 694 * `ButtonConfig::kFeatureSuppressClickBeforeDoubleClick` 695 * The *first* Clicked event is postponed by `getDoubleClickDelay()` 696 millis until the code can determine if a DoubleClick has occurred. If so, 697 then the postponed Clicked message to the `EventHandler` is suppressed. 698 * See the section ___Distinguishing Between a Clicked and DoubleClicked___ 699 for more info. 700 701 By default, no suppression is performed. 702 703 As an example, to suppress the `Released` event after a `LongPressed` event 704 (this is actually often the case), you would do this: 705 706 ```C++ 707 ButtonConfig* config = button.getButtonConfig(); 708 config->setFeature(ButtonConfig::kFeatureSuppressAfterLongPress); 709 ``` 710 711 The special convenient constant `kFeatureSuppressAll` is equivalent of using all 712 suppression constants: 713 714 ```C++ 715 ButtonConfig* config = button.getButtonConfig(); 716 config->setFeature(ButtonConfig::kFeatureSuppressAll); 717 ``` 718 719 All suppressions can be cleared by using: 720 ```C++ 721 ButtonConfig* config = button.getButtonConfig(); 722 config->clearFeature(ButtonConfig::kFeatureSuppressAll); 723 ``` 724 725 Note, however, that the `isFeature(ButtonConfig::kFeatureSuppressAll)` currently 726 means "isAnyFeature() implemented?" not "areAllFeatures() implemented?" We don't 727 expect `isFeature()` to be used often (or at all) for `kFeatureSuppressAll`. 728 729 ### Distinguishing Between a Clicked and DoubleClicked 730 731 On a project using only a small number of buttons (due to physical limits or the 732 limited availability of pins), it may be desirable to distinguish between a 733 single Clicked event and a DoubleClicked event from a single button. This is a 734 challenging problem to solve because fundamentally, a DoubleClicked event *must 735 always* generate a Clicked event, because a Clicked event must happen before it 736 can become a DoubleClicked event. 737 738 Notice that on a desktop computer (running Windows, MacOS or Linux), a 739 double-click on a mouse always generates both a Clicked and a DoubleClicked. The 740 first Click selects the given desktop object (e.g. an icon or a window), and 741 the DoubleClick performs some action on the selected object (e.g. open the 742 icon, or resize the window). 743 744 The AceButton Library provides 3 solutions which may work for some projects: 745 746 **Method 1:** The `kFeatureSuppressClickBeforeDoubleClick` flag causes the first 747 Clicked event to be detected, but the posting of the event message (i.e. the 748 call to the `EventHandler`) is postponed until the state of the DoubleClicked 749 can be determined. If the DoubleClicked happens, then the first Clicked event 750 message is suppressed. If DoubleClicked does not occur, the long delayed 751 Clicked message is sent via the `EventHandler`. 752 753 There are two noticeable disadvantages of this method. First, the response time 754 of all Clicked events is delayed by about 600 ms (`kClickDelay + 755 kDoubleClickDelay`) whether or not the DoubleClicked event happens. Second, the 756 user may not be able to accurately produce a Clicked event (due to the physical 757 characteristics of the button, or the user's dexterity). 758 759 It may also be worth noting that only the Clicked event is postponed. 760 The accompanying Released event of the Clicked event is not postponed. So a 761 single click action (without a DoubleClick) produces the following sequence of 762 events to the EventHandler: 763 764 1. `kEventPressed` - at time 0ms 765 1. `kEventReleased` - at time 200ms 766 1. `kEventClicked` - at time 600ms (200ms + 400ms) 767 768 The `ButtonConfig` configuration looks like this: 769 ```C++ 770 ButtonConfig* buttonConfig = button.getButtonConfig(); 771 buttonConfig->setFeature(ButtonConfig::kFeatureDoubleClick); 772 buttonConfig->setFeature( 773 ButtonConfig::kFeatureSuppressClickBeforeDoubleClick); 774 ``` 775 776 See the example code at 777 `examples/ClickVersusDoubleClickUsingSuppression/`. 778 779 **Method 2:** A viable alternative is to use the Released event instead of the 780 Clicked event to distinguish it from the DoubleClicked. For this method to work, 781 we need to suppress the Released event after both Clicked and DoubleClicked. 782 783 The advantage of using this method is that there is no response time lag in the 784 handling of the Released event. To the user, there is almost no difference 785 between triggering on the Released event, versus triggering on the Clicked 786 event. 787 788 The disadvantage of this method is that the Clicked event must be be ignored 789 (because of the spurious Clicked event generated by the DoubleClicked). If the 790 user accidentally presses and releases the button to quickly, it generates a 791 Clicked event, which will cause the program to do nothing. 792 793 The `ButtonConfig` configuration looks like this: 794 ```C++ 795 ButtonConfig* buttonConfig = button.getButtonConfig(); 796 buttonConfig->setEventHandler(handleEvent); 797 buttonConfig->setFeature(ButtonConfig::kFeatureDoubleClick); 798 buttonConfig->setFeature(ButtonConfig::kFeatureSuppressAfterClick); 799 buttonConfig->setFeature(ButtonConfig::kFeatureSuppressAfterDoubleClick); 800 ``` 801 802 See the example code at 803 `examples/ClickVersusDoubleClickUsingReleased/`. 804 805 **Method 3:** We could actually combine both Methods 1 and 2 so that either 806 Released or a delayed Click is considered to be a "Click". This may be the best 807 of both worlds. 808 809 The `ButtonConfig` configuration looks like this: 810 ```C++ 811 ButtonConfig* buttonConfig = button.getButtonConfig(); 812 buttonConfig->setEventHandler(handleEvent); 813 buttonConfig->setFeature(ButtonConfig::kFeatureDoubleClick); 814 buttonConfig->setFeature( 815 ButtonConfig::kFeatureSuppressClickBeforeDoubleClick); 816 buttonConfig->setFeature(ButtonConfig::kFeatureSuppressAfterClick); 817 buttonConfig->setFeature(ButtonConfig::kFeatureSuppressAfterDoubleClick); 818 ``` 819 820 See the example code at 821 `examples/ClickVersusDoubleClickUsingBoth/`. 822 823 ### Single Button Simplifications 824 825 Although the AceButton library is designed to shine for multiple buttons, you 826 may want to use it to handle just one button. The library provides some features 827 to make this simple case easy. 828 829 1. The library automatically creates one instance of `ButtonConfig` 830 called a "System ButtonConfig". This System ButtonConfig can be retrieved 831 using the class static method `ButtonConfig::getSystemButtonConfig()`. 832 1. Every instance of `AceButton` is assigned an instance of the System 833 ButtonConfig by default (which can be overridden manually). 834 1. A convenience method allows the `EventHandler` for the System 835 ButtonConfig to be set easily through `AceButton` itself, instead of having 836 to get the System ButtonConfig first, then set the event handler. In other 837 words, `button.setEventHandler(handleEvent)` is a synonym for 838 `button.getButtonConfig()->setEventHandler(handleEvent)`. 839 840 These simplifying features allow a single button to be configured and used like 841 this: 842 843 ```C++ 844 AceButton button(BUTTON_PIN); 845 846 void setup() { 847 pinMode(BUTTON_PIN, INPUT_PULLUP); 848 button.setEventHandler(handleEvent); 849 ... 850 } 851 852 void loop() { 853 button.check(); 854 } 855 856 void handleEvent(AceButton* button, uint8_t eventType, uint8_t buttonState) { 857 ... 858 } 859 ``` 860 861 To configure the System ButtonConfig, you may need to add something like 862 this to the `setup()` section: 863 864 ```C++ 865 button.getButtonConfig()->setFeature(ButtonConfig::kFeatureLongPress); 866 ``` 867 868 ### Multiple Buttons 869 870 When transitioning from a single button to multiple buttons, it's important to 871 remember what's happening underneath the convenience methods. The single 872 `AceButton` button is assigned to the System ButtonConfig that was created 873 automatically. When an `EventHandler` is assigned to the button, it is actually 874 assigned to the System ButtonConfig. All subsequent instances of `AceButton` 875 will also be associated with this event handler, unless another `ButtonConfig` 876 is explicitly assigned. 877 878 See the example sketch `TunerButtons.ino` to see how to use multiple 879 `ButtonConfig` instances with multiple `AceButton` instances. 880 881 ### Events After Reboot 882 883 A number of edge cases occur when the microcontroller is rebooted: 884 885 * if the button is held down, should the Pressed event be triggered? 886 * if the button is in its natural Released state, should the Released event 887 happen? 888 * if the button is Pressed down, and `ButtonConfig` is configured to 889 support RepeatPress events, should the `kEventRepeatPressed` events 890 be triggered initially? 891 892 I think most users would expect that in all these cases, the answer is no, the 893 microcontroller should not trigger an event until the button undergoes a 894 human-initiated change in state. The AceButton library implements this logic. 895 (It might be useful to make this configurable using a `ButtonConfig` feature 896 flag but that is not implemented.) 897 898 On the other hand, it is sometimes useful to perform some special action if a 899 button is pressed while the device is rebooted. To support this use-case, call 900 the `AceButton::isPressedRaw()` in the global `setup()` method (after the 901 button is configured). It will directly call the `digitalRead()` method 902 associated with the button pin and return `true` if the button is in the 903 Pressed state. 904 905 ### Orphaned Clicks 906 907 When a Clicked event is generated, the `AceButton` class looks for a 908 second Clicked event within a certain time delay (default 400 ms) to 909 determine if the second Clicked event is actually a DoubleClicked event. 910 911 All internal timestamps in `AceButton` are stored as `uint16_t` 912 (i.e. an unsigned integer of 16 bits) in millisecond units. A 16-bit 913 unsigned counter rolls over after 65536 iterations. Therefore, if the second 914 Clicked event happens between (65.636 seconds, 66.036 seconds) after the first 915 Clicked event, a naive-logic would erroneously consider the (long-delayed) 916 second click as a double-click. 917 918 The `AceButton` contains code that prevents this from happening. 919 920 Note that even if the `AceButton` class uses an `unsigned long` type (a 32-bit 921 integer on the Arduino), the overflow problem would still occur after `2^32` 922 milliseconds (i.e. 49.7 days). To be strictly correct, the `AceButton` class 923 would still need logic to take care of orphaned Clicked events. 924 925 ## Resource Consumption 926 927 Here are the sizes of the various classes on the 8-bit AVR microcontrollers 928 (Arduino Uno, Nano, etc): 929 930 * sizeof(AceButton): 14 931 * sizeof(ButtonConfig): 20 932 933 (An early version of `AceButton`, with only half of the functionality, consumed 934 40 bytes. It got down to 11 bytes before additional functionality increased it 935 to 14.) 936 937 **Program size:** 938 939 [LibrarySizeBenchmark](examples/LibrarySizeBenchmark/) was used to determine 940 the size of the library. For a single button, the library consumed: 941 * flash memory: 1100-1330 bytes 942 * static memory: 14-28 bytes 943 944 depending on the target board. See the README.md in the above link for more 945 details. 946 947 **CPU cycles:** 948 949 The profiling numbers for `AceButton::check()` can be found in 950 [examples/AutoBenchmark](examples/AutoBenchmark). 951 952 In summary, the average numbers for various boards are: 953 * Arduino Nano: 13-15 microsesconds 954 * Teensy 3.2: 3 microseconds 955 * ESP8266: 8-9 microseconds 956 * ESP32: 2-3 microseconds 957 958 ## System Requirements 959 960 This library was developed and tested using: 961 * [Arduino IDE 1.8.5 - 1.8.7](https://www.arduino.cc/en/Main/Software) 962 * [Teensyduino 1.41](https://www.pjrc.com/teensy/td_download.html) 963 * [ESP8266 Arduino Core 2.4.1 - 2.4.2](https://arduino-esp8266.readthedocs.io/en/2.4.2/) 964 * [arduino-esp32](https://github.com/espressif/arduino-esp32) 965 966 I used MacOS 10.13.3 and Ubuntu Linux 17.10 for most of my development. 967 968 The library has been verified to work on the following hardware: 969 970 * Arduino Nano clone (16 MHz ATmega328P) 971 * Arduino UNO R3 clone (16 MHz ATmega328P) 972 * Arduino Pro Micro clone (16 MHz ATmega32U4) 973 * Teensy LC (48 MHz ARM Cortex-M0+) 974 * Teensy 3.2 (72 MHz ARM Cortex-M4) 975 * NodeMCU 1.0 clone (ESP-12E module, 80MHz ESP8266) 976 * ESP32 Dev Module (ESP-WROOM-32 module, 240MHz dual core Tensilica LX6) 977 978 ## Background Motivation 979 980 There are numerous "button" libraries out there for the Arduino. Why write 981 another one? I wanted to add a button to an addressable strip LED controller, 982 which was being refreshed at 120 Hz. I had a number of requirements: 983 984 * the button needed to support a LongPress event, in addition to the simple 985 Press and Release events 986 * the button code must not interfere with the LED refresh code which was 987 updating the LEDs at 120 Hz 988 * well-tested, I didn't want to be hunting down random and obscure bugs 989 990 Since the LED refresh code needed to run while the button code was waiting for 991 a "LongPress" delay, it seemed that the cleanest API for a button library 992 would use an event handler callback mechanism. This reduced the number of 993 candidate libraries to a handful. Of these, only a few of them supported a 994 LongPress event. I did not find the remaining ones flexible enough for my 995 button needs in the future. Finally, I knew that it was tricky to write correct 996 code for debouncing and detecting various events (e.g. DoubleClick, LongPress, 997 RepeatPress). I looked for a library that contained unit tests, and I found 998 none. 999 1000 I decided to write my own and use the opportunity to learn how to create and 1001 publish an Arduino library. 1002 1003 ## Changelog 1004 1005 See [CHANGELOG.md](CHANGELOG.md). 1006 1007 ## License 1008 1009 * Versions 1.0 to 1.0.6: [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0) 1010 * Versions 1.1 and above: [MIT License](https://opensource.org/licenses/MIT) 1011 1012 I changed to the MIT License starting with version 1.1 because the MIT License 1013 is so simple to understand. I could not be sure that I understood what the 1014 Apache License 2.0 meant. 1015 1016 ## Feedback and Support 1017 1018 If you have any questions, comments, bug reports, or feature requests, please 1019 file a GitHub ticket or send me an email. I'd love to hear about how this 1020 software and its documentation can be improved. Instead of forking the 1021 repository to modify or add a feature for your own projects, let me have a 1022 chance to incorporate the change into the main repository so that your external 1023 dependencies are simpler and so that others can benefit. I can't promise that I 1024 will incorporate everything, but I will give your ideas serious consideration. 1025 1026 ## Author 1027 1028 Created by Brian T. Park (brian@xparks.net).