mirror of
https://github.com/jaksatomovic/esp32-clickwheel.git
synced 2025-08-20 20:38:29 -04:00
first commit
This commit is contained in:
commit
868b14f8c8
286 changed files with 59925 additions and 0 deletions
1
lib/Button2/.github/FUNDING.yml
vendored
Normal file
1
lib/Button2/.github/FUNDING.yml
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
ko_fi: lennart0815
|
11
lib/Button2/.gitignore
vendored
Normal file
11
lib/Button2/.gitignore
vendored
Normal file
|
@ -0,0 +1,11 @@
|
|||
# MAC .dot folder
|
||||
.DS_Store
|
||||
# vs code files
|
||||
.vscode
|
||||
*.code-workspace
|
||||
# platformio ini file
|
||||
platformio.ini
|
||||
.pio
|
||||
# arduino_ci unit test binaries and artifacts
|
||||
*.bin
|
||||
*.bin.dSYM
|
186
lib/Button2/CHANGELOG.md
Executable file
186
lib/Button2/CHANGELOG.md
Executable file
|
@ -0,0 +1,186 @@
|
|||
# Changelog
|
||||
|
||||
**Note:** Unreleased changes are checked in but not part of an official release (available through the Arduino IDE or PlatfomIO) yet. This allows you to test WiP features and give feedback to them.
|
||||
|
||||
## Unreleased
|
||||
|
||||
- nothing, so far
|
||||
|
||||
## [2.3.1] - 2024-01-02
|
||||
|
||||
- bugfix for RP2040, as pointed out by [kilrah](https://github.com/kilrah) in issue [#60](https://github.com/LennartHennigs/Button2/issues/60)
|
||||
|
||||
## [2.3.0] - 2024-01-02
|
||||
|
||||
- renamed Button2 constants, they now start with `BTN_` (BREAKING CHANGE)
|
||||
- added `Hardware.h` – it implements hardware pin abstraction. Needed for unit testing
|
||||
- added Unit Tests
|
||||
- added `resetPressedState()` function
|
||||
- added `ESP32S2S3CapacitiveTouch.ino` suggested by [ryancasler](https://github.com/ryancasler) in PR #57
|
||||
|
||||
## [2.2.4] - 2023-06-22
|
||||
|
||||
- `getNumberOfClicks()` now works inside a callback and after the `wait()`statement(s).
|
||||
- Refactored code in `Button2.cpp`
|
||||
|
||||
## [2.2.3] - 2023-06-21
|
||||
|
||||
- Included PR for issue [#54](https://github.com/LennartHennigs/Button2/issues/54)
|
||||
|
||||
## [2.2.2] - 2022-12-16
|
||||
|
||||
- Another stab at the bug [#46](https://github.com/LennartHennigs/Button2/issues/46)
|
||||
|
||||
## [2.2.1] - 2022-12-16
|
||||
|
||||
- Fixed bug [#46](https://github.com/LennartHennigs/Button2/issues/46) that in some instances long clicks are wrongly triggered
|
||||
|
||||
## [2.2.0] - 2022-12-13
|
||||
|
||||
- Refactored the main `loop()`
|
||||
- Rewrote click detection
|
||||
- Cleaned up the long press handling
|
||||
- Removed compiler switches – they made the code unreadable and they only saved a few bytes (could be a BREAKING CHANGE)
|
||||
- Added `byte getLongClickCount()` function
|
||||
- Updated the [LongpressHandler](https://github.com/LennartHennigs/Button2/blob/master/examples/LongpressHandler/LongpressHandler.ino) example
|
||||
- Defaults (x>3)-clicks to triple
|
||||
- Fixed bug with button ID
|
||||
|
||||
## [2.1.0] - 2022-11-03
|
||||
|
||||
- Removed the capacitive touch functionality out of main library. (BREAKING CHANGE). The constructor and `begin()` lost a parameter. Instead I provide a custom handler example for cap. touch [ESP32CapacitiveTouch.ino](https://github.com/LennartHennigs/Button2/blob/master/examples/ESP32CapacitiveTouch/ESP32CapacitiveTouch.ino). For reasons, see [#45](https://github.com/LennartHennigs/Button2/issues/45).
|
||||
- Added an ESP32 timer interrupt example [ESP32TimerInterrupt.ino](https://github.com/LennartHennigs/Button2/blob/master/examples/ESP32TimerInterrupt/ESP32TimerInterrupt.ino) based on [#43](https://github.com/LennartHennigs/Button2/issues/43).
|
||||
- Added compiler switches in `Button.h` to remove click detection code, as mentioned in [#44](https://github.com/LennartHennigs/Button2/issues/44).
|
||||
- Clarified the difference between the `setLongClickHandler` and the `setLongClickDetectedHandler` in the README and the [MultiHandler](https://github.com/LennartHennigs/Button2/blob/master/examples/MultiHandler/MultiHandler.ino) example as mentioned in [#41](https://github.com/LennartHennigs/Button2/issues/41). (The handler set via `setLongClickHandler` waits until you release the button, the second one is called as soon as the defined long-click time has passed.)
|
||||
- Made `byte _getState()` into a `const` function.
|
||||
|
||||
## [2.0.3] - 2022-05-26
|
||||
|
||||
- Fixed bug with the button ID as pointed out by [Jon](https://github.com/mscreations) in [#39](https://github.com/LennartHennigs/Button2/pull/39).
|
||||
|
||||
## [2.0.2] - 2022-05-21
|
||||
|
||||
- Added example for the [M5Stack Core2](https://github.com/LennartHennigs/Button2/blob/master/examples/M5StackCore2CustomHandler/M5StackCore2CustomHandler.ino) - showing how to add a custom handler for the touch buttons.
|
||||
|
||||
## [2.0.1] - 2022-04-22
|
||||
|
||||
- Fixed bug – `longclick_detected_counter` is not properly initalized as mentioned in [#37](https://github.com/LennartHennigs/Button2/pull/37).
|
||||
|
||||
## [2.0.0] - 2022-04-04
|
||||
|
||||
- House keeping
|
||||
- Refactored `loop()` - cleaned up conditions, should be easier to understand now.
|
||||
- Renamed `getAttachedPin()`to `getPin()` (BREAKING CHANGE).
|
||||
- Fixed a bug that the first click type was falsly returned by `getClickType()`.
|
||||
- Possibility define your own "_getState" function for non standard buttons as suggested in [#32](https://github.com/LennartHennigs/Button2/issues/32).
|
||||
- Refactored `isPressedRaw()` to also use `_getState()`.
|
||||
- Introduced a `VIRTUAL_PIN` constant – using it in the constructor or `begin()` will skip pin initalization.
|
||||
- Added `setButtonStateFunction(StateCallbackFunction f)` to assign your own "_getState" function.
|
||||
- Added [CustomButtonStateHandler.ino](https://github.com/LennartHennigs/Button2/blob/master/examples/CustomButtonStateHandler/CustomButtonStateHandler.ino) example.
|
||||
- Improved click type handling.
|
||||
- Added `clickType` and removed constants for determining the click type (BREAKING CHANGE)
|
||||
- Renamed `getClickType()` to `getType()` (BREAKING CHANGE)
|
||||
- Added `clickToString` function to print the `clickType` enum value
|
||||
- Added IDs button instances
|
||||
- Added `getID()`, it returns an auto incremented `int` ID for the button, as suggest in [#34](https://github.com/LennartHennigs/Button2/pull/34)
|
||||
- Added `setID()`, it allows you to set your own IDs – but then you need to ensure its uniqeness yourself
|
||||
- Added possibility to use the button class inside your main `loop()` function (instead of using callback handlers)
|
||||
- Added `bool wasPressed()` function
|
||||
- Added `read(bool keepState = false)`, it returns the button press type (as a `clickType` enum)
|
||||
- Added `wait(bool keepState = false)`, it combines `wasPressed()` and `read()` methods and halts execution until a button press took place
|
||||
- Added `waitForClick()`, `waitForDouble()`, `waitForTriple()` and `waitForLong()` as well
|
||||
- Added [ButtonLoop.ino](https://github.com/LennartHennigs/Button2/blob/master/examples/ButtonLoop/ButtonLoop.ino) example to showcase the "loop" functions
|
||||
|
||||
## [1.6.5] - 2021-09-12
|
||||
|
||||
- Fixed problem with `std::function` as found by [ItsFlo](https://github.com/ItsFlo) in pull request [#29](https://github.com/LennartHennigs/Button2/pull/29)
|
||||
|
||||
## [1.6.4] - 2021-09-12
|
||||
|
||||
- Use `std::function` to allow C++ 11 lambda functions as suggested by [jacobdekeizer](https://github.com/jacobdekeizer) in pull request [#29](https://github.com/LennartHennigs/Button2/pull/29)
|
||||
|
||||
## [1.6.3] - 2021-09-12
|
||||
|
||||
- added two new examples: [MultiHandlerTwoButtons.ino](https://github.com/LennartHennigs/Button2/blob/master/examples/MultiHandlerTwoButtons/MultiHandlerTwoButtons.ino) and [TrackDualButtonClick.ino](https://github.com/LennartHennigs/Button2/blob/master/examples/TrackDualButtonClick/TrackDualButtonClick.ino)
|
||||
- added examples to the [README.md](https://github.com/LennartHennigs/Button2/blob/master/README.md)
|
||||
- initialized `pin` in `_getState()`
|
||||
- a bit of variable clean up
|
||||
- updated setting of inital state of `state` and `prev_state`
|
||||
|
||||
## [1.6.2] - 2021-06-22
|
||||
|
||||
- initialized `pin` property to 255 instead of -1, as pointed out by [rin67630](https://github.com/rin67630) in issue [#26](https://github.com/LennartHennigs/Button2/issues/26)
|
||||
|
||||
## [1.6.1] - 2021-03-22
|
||||
|
||||
- updated [README.md](https://github.com/LennartHennigs/Button2/blob/master/README.md)
|
||||
- added `const` to getter functions
|
||||
|
||||
## [1.6.0] - 2021-02-10
|
||||
|
||||
- added getter/setter functions for debounce, longclick and doubleclick timeouts
|
||||
- removed debounce timeout parameter from `contructor` and `begin()`
|
||||
|
||||
## [1.5.4] - 2021-02-08
|
||||
|
||||
- Added `getAttachPin()` function, as suggested by [madivad](https://github.com/madivad) in issue [#23](https://github.com/LennartHennigs/Button2/issues/23)
|
||||
|
||||
## [1.5.3] - 2021-01-26
|
||||
|
||||
- Fixed a bug in the constructor, as suggested by [alex-s-v](https://github.com/alex-s-v) in pull request [#22](https://github.com/LennartHennigs/Button2/pull/22)
|
||||
|
||||
## [1.5.2] - 2021-01-26
|
||||
|
||||
- Fixed a bug in the `isPressed()` function, as suggested by [zenturacp](https://github.com/zenturacp) in [#21](https://github.com/LennartHennigs/Button2/issues/21)
|
||||
|
||||
## [1.5.1] - 2021-01-04
|
||||
|
||||
- Fixed a bug in the `loop()` function
|
||||
|
||||
## [1.5.0] - 2021-01-03
|
||||
|
||||
- Added default constructor and `begin()` function
|
||||
- Added pull request by [skelstar](https://github.com/skelstar) to add the `setLongClickDetectedHandler()` function which is triggered as soon as the longclick timeout has passed
|
||||
|
||||
## [1.4.1] - 2020-12-19
|
||||
|
||||
- Moved activeLow outside of isCapacitive condition (as suggested by [Wai Lin](https://github.com/w4ilun) in [#18](https://github.com/LennartHennigs/Button2/pull/18)
|
||||
|
||||
## [1.4.0] - 2020-11-06
|
||||
|
||||
- Updated LongpressHandler example - changed variable name to from `button` to `button`
|
||||
- toggled `pressed` and `released` (as suggesed by [TommyC81](https://github.com/TommyC81) in [#16](https://github.com/LennartHennigs/Button2/issues/16))
|
||||
- added debug function `isPressedRaw()` (as suggesed by [TommyC81](https://github.com/TommyC81) in [#16](https://github.com/LennartHennigs/Button2/issues/16))
|
||||
- fixed bug with `click_count` (as suggesed by [TommyC81](https://github.com/TommyC81) in [#16](https://github.com/LennartHennigs/Button2/issues/16))
|
||||
- changed return types of `getNumberOfClicks()` and `getClickType()` to `byte`
|
||||
|
||||
## [1.3.0] - 2020-11-06
|
||||
|
||||
- Added capacitive touch sensor capabilties (for ESP32) (as suggested by [qubolino](https://github.com/qubolino) in [#11](https://github.com/LennartHennigs/Button2/issues/11))
|
||||
- Removed deprecated entry in the library.properties file (as suggested by [SangLe](https://github.com/SNL5943)) in [#15](https://github.com/LennartHennigs/Button2/issues/15)
|
||||
- Added `const` modifier to functions (as suggested by [Anton-V-K](https://github.com/Anton-V-K) in [#13](https://github.com/LennartHennigs/Button2/issues/13))
|
||||
|
||||
## [1.2.0] - 2020-04-16
|
||||
|
||||
- Added possibility to define your own timeouts for clicks (as suggested by [cmeldas](https://github.com/cmeldas) in [#10](https://github.com/LennartHennigs/Button2/issues/10))
|
||||
- Removed `yield()` in main `loop()` since it caused some problems
|
||||
- Created and added CHANGELOG.md
|
||||
|
||||
## [1.1.0] - 2020-03-27
|
||||
|
||||
- Changed the private functions to protected (as suggested by [Nagymadar](https://github.com/Nagymadar) in [#9](https://github.com/LennartHennigs/Button2/issues/9))
|
||||
- Added support for active high buttons (as suggested by [Nagymadar](https://github.com/Nagymadar) in [#8](https://github.com/LennartHennigs/Button2/issues/8))
|
||||
- Added `reset()` function to unset all functions (as suggested by [Nagymadar](https://github.com/Nagymadar) in [#7](https://github.com/LennartHennigs/Button2/issues/7))
|
||||
- Added a `yield()` command to the main `loop()`
|
||||
- Changed the times for double and triple click
|
||||
- Fixed error in `SingleButton.ino` (as suggested by [alexthe-red](https://github.com/alexthe-red) in [#3](https://github.com/LennartHennigs/Button2/issues/3))
|
||||
- Added the library to the Arduino IDE
|
||||
|
||||
## [1.0.0] - 2017-11-09
|
||||
|
||||
- initial release
|
||||
|
||||
## Note
|
||||
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
21
lib/Button2/LICENSE
Executable file
21
lib/Button2/LICENSE
Executable file
|
@ -0,0 +1,21 @@
|
|||
MIT License
|
||||
|
||||
Copyright (c) 2017-2022 Lennart Hennigs
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
295
lib/Button2/README.md
Executable file
295
lib/Button2/README.md
Executable file
|
@ -0,0 +1,295 @@
|
|||
# Button2
|
||||
|
||||
Arduino/ESP library to simplify working with buttons.
|
||||
|
||||
- Author: Lennart Hennigs (<https://www.lennarthennigs.de>)
|
||||
- Copyright (C) 2017-2023 Lennart Hennigs.
|
||||
- Released under the MIT license.
|
||||
|
||||
## Description
|
||||
|
||||
This library allows you to use callback functions to track single, double, triple and long clicks. Alternatively, it provides function to use in your main `loop()`.
|
||||
The library also takes care of debouncing. Using this lib will reduce and simplify your source code significantly.
|
||||
|
||||
It has been tested with Arduino, ESP8266 and ESP32 devices.
|
||||
|
||||
To see the latest changes to the library please take a look at the [Changelog](https://github.com/LennartHennigs/Button2/blob/master/CHANGELOG.md).
|
||||
|
||||
If you find this library helpful please consider giving it a ⭐️ at [GitHub](https://github.com/LennartHennigs/Button2) and/or [buy me a ☕️](https://ko-fi.com/lennart0815).
|
||||
|
||||
Thank you!
|
||||
|
||||
## How To Use
|
||||
|
||||
This library allows you to define a button and uses callback functions to detect different types of button interactions.
|
||||
If you don't want to use callback there are also functions available for using it in your code's main `loop()`.
|
||||
|
||||
### Definition
|
||||
|
||||
- Include the library on top
|
||||
|
||||
```c++
|
||||
#include "Button2.h"
|
||||
```
|
||||
|
||||
- Define the button either using the `constructor` or the `begin()` function.
|
||||
|
||||
```c++
|
||||
void begin(byte attachTo, byte buttonMode = INPUT_PULLUP, boolean activeLow = true);
|
||||
```
|
||||
|
||||
### Button Types
|
||||
|
||||
- You can use the class for "real" buttons (*pullup*, *pulldown*, and *active low*).
|
||||
- Per default the button pins are defined as `INPUT_PULLUP`. You can override this upon creation.
|
||||
|
||||
```c++
|
||||
#include "Button2.h"
|
||||
#define BUTTON_PIN D3
|
||||
|
||||
Button2 button;
|
||||
|
||||
void setup() {
|
||||
button.begin(BUTTON_PIN);
|
||||
}
|
||||
```
|
||||
|
||||
- You can also the library with other types of buttons, e.g. capacitive touch or ones handled via I2C. See the section on defining custom handlers below.
|
||||
|
||||
### Callback Handler
|
||||
|
||||
- Instead of frequently checking the button state in your main `loop()` this class allows you to assign callback functions.
|
||||
- You can define callback functions to track various types of clicks:
|
||||
- `setTapHandler()` will be be called when any click occurs. This is the most basic handler. It ignores all timings built-in the library for double or triple click detection.
|
||||
- `setClickHandler()` will be triggered after a single click occurred.
|
||||
- `setChangedHandler()`, `setPressedHandler()` and `setReleasedHandler()` allow to detect basic interactions.
|
||||
- `setLongClickDetectedHandler()` will be triggered as soon as the long click timeout has passed.
|
||||
- `setLongClickHandler()` will be triggered after the button has released.
|
||||
- `setDoubleClickHandler()` and `setTripleClickHandler()` detect complex interactions.
|
||||
|
||||
- **Note:** You will experience a short delay with `setClickHandler()` and `setLongClickHandler()` as need to check whether a long or multi-click is in progress. For immediate feedback use `setTapHandler()`or `setLongClickDetectedHandler()`
|
||||
|
||||
- You can assign callback functions for single or for multiple buttons.
|
||||
- You can track individual or multiple events with a single handler.
|
||||
- Please take a look at the included examples (see below) to get an overview over the different callback handlers and their usage.
|
||||
- All callback functions need a `Button2` reference parameter. There the reference to the triggered button is stored. This can used to call status functions, e.g. `wasPressedFor()`.
|
||||
|
||||
### Longpress Handling
|
||||
|
||||
- There are two possible callback functions: `setLongClickDetectedHandler()` and `setLongClickHandler()`.
|
||||
- `setLongClickDetectedHandler()` will be called as soon as the defined timeout has passed.
|
||||
- `setLongClickHandler()` will only be called after the button has been released.
|
||||
- `setLongClickDetectedRetriggerable(bool retriggerable)` allows you to define whether want to get multiple notifications for a **single** long click depending on the timeout.
|
||||
- `getLongClickCount()` gets you the number of long clicks – this is useful when `retriggerable` is set.
|
||||
|
||||
### The Loop
|
||||
|
||||
- For the class to work, you need to call the button's `loop()` member function in your sketch's `loop()` function.
|
||||
|
||||
```c++
|
||||
#include "Button2.h"
|
||||
#define BUTTON_PIN D3
|
||||
|
||||
Button2 button;
|
||||
|
||||
void handleTap(Button2& b) {
|
||||
// check for really long clicks
|
||||
if (b.wasPressedFor() > 1000) {
|
||||
// do something
|
||||
}
|
||||
}
|
||||
|
||||
void setup() {
|
||||
button.begin(BUTTON_PIN);
|
||||
button.setTapHandler(handleTap);
|
||||
}
|
||||
|
||||
void loop() {
|
||||
button.loop();
|
||||
}
|
||||
```
|
||||
|
||||
- As the `loop()`function needs to be called continuously, `delay()` and other blocking functions will interfere with the detection of clicks. Consider cleaning up your loop or call the `loop()` function via an interrupt.
|
||||
- Please see the *examples* below for more details.
|
||||
|
||||
### Using an timer interrupt instead
|
||||
|
||||
- Alternatively, you can call the button's `loop()` function via a timer interrupt.
|
||||
- I haven't tried this extensively, USE THIS AT YOUR OWN RISK!
|
||||
- You need make sure that the interval is quick enough that it can detect your timeouts (see below).
|
||||
- There is an example for the ESP32 [ESP32TimerInterrupt.ino](https://github.com/LennartHennigs/Button2/blob/master/examples/ESP32TimerInterrupt/ESP32TimerInterrupt.ino) that I tested.
|
||||
|
||||
### Timeouts
|
||||
|
||||
- The default timeouts for events are (in ms):
|
||||
|
||||
```c++
|
||||
#define BTN_DEBOUNCE_MS 50
|
||||
#define BTN_LONGCLICK_MS 200
|
||||
#define BTN_DOUBLECLICK_MS 300
|
||||
```
|
||||
|
||||
- You can define your own timeouts by using these setter functions:
|
||||
- `void setDebounceTime(unsigned int ms)`
|
||||
- `void setLongClickTime(unsigned int ms)`
|
||||
- `void setDoubleClickTime(unsigned int ms)`
|
||||
- There are also getter functions available, if needed.
|
||||
|
||||
### Using Button2 in the main `loop()`
|
||||
|
||||
- Even though I suggest to use handlers for tracking events, you can also use Button2 to check button's state in the main loop
|
||||
- `bool wasPressed()` allows you to check whether the button was pressed
|
||||
- `clickType read(bool keepState = false)` gives you the type of click that took place
|
||||
- `clickType wait(bool keepState = false)` combines `read()` and `wasPressed()` and halts execution until a button click was detected. Thus, it is blocking code.
|
||||
- The `clickType` is an enum defined as...
|
||||
|
||||
```c++
|
||||
enum clickType {
|
||||
single_click,
|
||||
double_click,
|
||||
triple_click,
|
||||
long_click,
|
||||
empty
|
||||
};
|
||||
```
|
||||
|
||||
- There are also dedicated waits (`waitForClick()`, `waitForDouble()`, `waitForTriple()` and `waitForLong()`) to detect a specific type
|
||||
- The `read()` and the *wait* functions will reset the state of `wasPressed()` unless specified otherwise (via a `bool` parameter)
|
||||
- `resetPressedState()` allows you to clear value returned by `wasPressed()` – it is similar to passing `keepState = false` for `read()` or `wait()`.
|
||||
- Check out the [ButtonLoop.ino](https://github.com/LennartHennigs/Button2/blob/master/examples/ButtonLoop/ButtonLoop.ino) example to see it in action
|
||||
|
||||
### Status Functions
|
||||
|
||||
- There are several status functions available to check the status of a button:
|
||||
|
||||
``` c++
|
||||
unsigned int wasPressedFor() const;
|
||||
byte getNumberOfClicks() const;
|
||||
byte getType() const;
|
||||
boolean isPressed() const;
|
||||
boolean isPressedRaw() const;
|
||||
bool wasPressed() const;
|
||||
```
|
||||
|
||||
### IDs for Button Instances
|
||||
|
||||
- Each button instance gets a unique (auto incremented) ID upon creation.
|
||||
- You can get a buttons' ID via `getID()`.
|
||||
- Alternatively, you can use `setID(int newID)` to set a new one. But then you need to make sure that they are unique.
|
||||
|
||||
### Creating A Custom Button State Handler
|
||||
|
||||
- Out of the box *Button2* supports regular hardware buttons.
|
||||
- If you want to add other button types you need to define your own function that tracks the state of the button.
|
||||
- Use `setButtonStateFunction()` to assign it to your *Button2* instance
|
||||
- Make the button pin 'VIRTUAL', i.e. by calling `button.begin(VIRTUAL_PIN);`
|
||||
- And don't forget to initialize the button as this cannot be handled by *Button2*
|
||||
- See [ESP32CapacitiveTouch.ino](https://github.com/LennartHennigs/Button2/blob/master/examples/ESP32CapacitiveTouch/ESP32CapacitiveTouch.ino), [M5StackCore2CustomHandler.ino](https://github.com/LennartHennigs/Button2/blob/master/examples/M5StackCore2CustomHandler/M5StackCore2CustomHandler.ino), and [CustomButtonStateHandler.ino](https://github.com/LennartHennigs/Button2/blob/master/examples/CustomButtonStateHandler/CustomButtonStateHandler.ino) as examples.
|
||||
|
||||
## Examples
|
||||
|
||||
- [SingleButtonSimple.ino](https://github.com/LennartHennigs/Button2/blob/master/examples/SingleButtonSimple/SingleButtonSimple.ino) – the most basic example, shows how to assign event handlers
|
||||
- [LongpressHandler.ino](https://github.com/LennartHennigs/Button2/blob/master/examples/LongpressHandler/LongpressHandler.ino) – shows how determine the time of a button press
|
||||
- [SingleButton.ino](https://github.com/LennartHennigs/Button2/blob/master/examples/SingleButton/SingleButton.ino) – shows the different event handlers
|
||||
- [MultipleButtons.ino](https://github.com/LennartHennigs/Button2/blob/master/examples/MultipleButtons/MultipleButtons.ino) – how to use two buttons
|
||||
- [MultiHandler.ino](https://github.com/LennartHennigs/Button2/blob/master/examples/MultiHandler/MultiHandler.ino) – how to use a single handler for multiple events
|
||||
- [MultiHandlerTwoButtons.ino](https://github.com/LennartHennigs/Button2/blob/master/examples/MultiHandlerTwoButtons/MultiHandlerTwoButtons.ino) – a single handler for multiple buttons
|
||||
- [TrackDualButtonClick.ino](https://github.com/LennartHennigs/Button2/blob/master/examples/TrackDualButtonClick/TrackDualButtonClick.ino) – how to detect when two buttons are clicked at the same time
|
||||
- [CustomButtonStateHandler.ino](https://github.com/LennartHennigs/Button2/blob/master/examples/CustomButtonStateHandler/CustomButtonStateHandler.ino) - how to assign your own button handler
|
||||
- [ESP32CapacitiveTouch.ino](https://github.com/LennartHennigs/Button2/blob/master/examples/ESP32CapacitiveTouch/ESP32CapacitiveTouch.ino) – how to access the ESP32s capacitive touch handlers
|
||||
- [M5StackCore2CustomHandler.ino](https://github.com/LennartHennigs/Button2/blob/master/examples/M5StackCore2CustomHandler/M5StackCore2CustomHandler.ino) - example for the M5Stack Core2 touch buttons
|
||||
- [ESP32TimerInterrupt.ino](https://github.com/LennartHennigs/Button2/blob/master/examples/ESP32TimerInterrupt/ESP32TimerInterrupt.ino) - how to use a timer interrupt with the library.
|
||||
- [ButtonLoop.ino](https://github.com/LennartHennigs/Button2/blob/master/examples/ButtonLoop/ButtonLoop.ino) – how to use the button class in the main loop (I recommend using handlers, but well...)
|
||||
|
||||
## Class Definition
|
||||
|
||||
The button class offers a few additional functions, please take a look at the *Class Definition* below.
|
||||
|
||||
See below the constructors and member functions the library provides:
|
||||
|
||||
```c++
|
||||
Button2();
|
||||
Button2(byte attachTo, byte buttonMode = INPUT_PULLUP, boolean activeLow = true);
|
||||
|
||||
void begin(byte attachTo, byte buttonMode = INPUT_PULLUP, boolean activeLow = true);
|
||||
|
||||
void setDebounceTime(unsigned int ms);
|
||||
void setLongClickTime(unsigned int ms);
|
||||
void setDoubleClickTime(unsigned int ms);
|
||||
|
||||
unsigned int getDebounceTime();
|
||||
unsigned int getLongClickTime();
|
||||
unsigned int getDoubleClickTime();
|
||||
byte getPin();
|
||||
|
||||
void reset();
|
||||
|
||||
void setButtonStateFunction(StateCallbackFunction f);
|
||||
|
||||
void setChangedHandler(CallbackFunction f);
|
||||
void setPressedHandler(CallbackFunction f);
|
||||
void setReleasedHandler(CallbackFunction f);
|
||||
|
||||
void setTapHandler(CallbackFunction f);
|
||||
void setClickHandler(CallbackFunction f);
|
||||
void setDoubleClickHandler(CallbackFunction f);
|
||||
void setTripleClickHandler(CallbackFunction f);
|
||||
|
||||
void setLongClickHandler(CallbackFunction f);
|
||||
void setLongClickDetectedHandler(CallbackFunction f);
|
||||
void setLongClickDetectedRetriggerable(bool retriggerable);
|
||||
void byte getLongClickCount() const;
|
||||
|
||||
unsigned int wasPressedFor() const;
|
||||
void resetPressedState();
|
||||
boolean isPressed() const;
|
||||
boolean isPressedRaw() const;
|
||||
|
||||
bool wasPressed() const;
|
||||
clickType read(bool keepState = false);
|
||||
clickType wait(bool keepState = false);
|
||||
void waitForClick(bool keepState = false);
|
||||
void waitForDouble(bool keepState = false);
|
||||
void waitForTriple(bool keepState = false);
|
||||
void waitForLong(bool keepState = false);
|
||||
|
||||
byte getNumberOfClicks() const;
|
||||
byte getType() const;
|
||||
String clickToString(clickType type) const;
|
||||
|
||||
int getID() const;
|
||||
void setID(int newID);
|
||||
|
||||
bool operator == (Button2 &rhs);
|
||||
|
||||
void loop();
|
||||
```
|
||||
|
||||
## Installation
|
||||
|
||||
Open the Arduino IDE choose "Sketch > Include Library" and search for "Button2".
|
||||
Or download the ZIP archive (<https://github.com/lennarthennigs/Button2/zipball/master>), and choose "Sketch > Include Library > Add .ZIP Library..." and select the downloaded file.
|
||||
|
||||
## License
|
||||
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2017-2023 Lennart Hennigs
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
35
lib/Button2/examples/ButtonLoop/ButtonLoop.ino
Normal file
35
lib/Button2/examples/ButtonLoop/ButtonLoop.ino
Normal file
|
@ -0,0 +1,35 @@
|
|||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "Button2.h"
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
#define BUTTON_PIN 2
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
Button2 button;
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
void setup() {
|
||||
Serial.begin(9600);
|
||||
delay(50);
|
||||
Serial.println("\n\nButton Loop Demo");
|
||||
|
||||
button.begin(BUTTON_PIN);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
void loop() {
|
||||
button.loop();
|
||||
|
||||
|
||||
Serial.println(button.clickToString(button.wait()));
|
||||
Serial.println(button.getNumberOfClicks());
|
||||
|
||||
|
||||
|
||||
}
|
||||
/////////////////////////////////////////////////////////////////
|
|
@ -0,0 +1,39 @@
|
|||
/////////////////////////////////////////////////////////////////
|
||||
#include "Button2.h"
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
Button2 button;
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
byte myButtonStateHandler() {
|
||||
return digitalRead(39);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
void myTapHandler(Button2 &b) {
|
||||
Serial.println("tap");
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
void setup() {
|
||||
Serial.begin(9600);
|
||||
delay(100);
|
||||
Serial.println("\n\nCustom Buttom Test");
|
||||
button.begin(VIRTUAL_PIN);
|
||||
|
||||
pinMode(39, INPUT_PULLUP);
|
||||
|
||||
button.setButtonStateFunction(myButtonStateHandler);
|
||||
button.setTapHandler(myTapHandler);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
void loop() {
|
||||
button.loop();
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
|
@ -0,0 +1,50 @@
|
|||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
#if !defined(ESP32)
|
||||
#error This sketch needs an ESP32
|
||||
#else
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "Button2.h"
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
Button2 button;
|
||||
byte pin = 4;
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
byte capStateHandler() {
|
||||
int capa = touchRead(pin);
|
||||
return capa < button.getDebounceTime() ? LOW : HIGH;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
void setup() {
|
||||
Serial.begin(9600);
|
||||
delay(50);
|
||||
Serial.println("\n\nCapacitive Touch Demo");
|
||||
|
||||
button.setDebounceTime(35);
|
||||
button.setButtonStateFunction(capStateHandler);
|
||||
button.setClickHandler(click);
|
||||
button.begin(VIRTUAL_PIN);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
void loop() {
|
||||
button.loop();
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
void click(Button2& btn) {
|
||||
Serial.println("click\n");
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
#endif
|
||||
/////////////////////////////////////////////////////////////////
|
|
@ -0,0 +1,66 @@
|
|||
/////////////////////////////////////////////////////////////////
|
||||
// see https://github.com/LennartHennigs/Button2/pull/57
|
||||
/////////////////////////////////////////////////////////////////
|
||||
#if !defined(ESP32)
|
||||
#error This sketch needs an ESP32 S2 or S3
|
||||
#else
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "Button2.h"
|
||||
|
||||
#define TOUCH_PIN T5 // Must declare the touch assignment, not the pin.
|
||||
|
||||
int threshold = 1500; // ESP32S2
|
||||
bool touchdetected = false;
|
||||
byte buttonState = HIGH;// HIGH is for unpressed, pressed = LOW
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
Button2 button;
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
void gotTouch() {
|
||||
touchdetected = true;
|
||||
}
|
||||
|
||||
|
||||
byte capStateHandler() {
|
||||
return buttonState;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
delay(50);
|
||||
Serial.println("\n\nCapacitive Touch Demo");
|
||||
touchAttachInterrupt(TOUCH_PIN, gotTouch, threshold);
|
||||
button.setDebounceTime(35);
|
||||
button.setButtonStateFunction(capStateHandler);
|
||||
button.setClickHandler(click);
|
||||
button.begin(BTN_VIRTUAL_PIN);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
void loop() {
|
||||
button.loop();
|
||||
if (touchdetected) {
|
||||
touchdetected = false;
|
||||
if (touchInterruptGetLastStatus(TOUCH_PIN)) {
|
||||
buttonState = LOW;
|
||||
} else {
|
||||
buttonState = HIGH;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
void click(Button2& btn) {
|
||||
Serial.println("click\n");
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
#endif
|
||||
/////////////////////////////////////////////////////////////////
|
|
@ -0,0 +1,51 @@
|
|||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
#if !defined(ESP32)
|
||||
#error This sketch needs an ESP32
|
||||
#else
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
#include "Button2.h"
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
#define BUTTON_PIN 39
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
Button2 btn;
|
||||
hw_timer_t *timer = NULL;
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
void IRAM_ATTR onTimer() {
|
||||
btn.loop();
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
void click(Button2 &b) {
|
||||
Serial.println("click");
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
void setup() {
|
||||
Serial.begin(9600);
|
||||
|
||||
btn.begin(BUTTON_PIN);
|
||||
btn.setTapHandler(click);
|
||||
|
||||
timer = timerBegin(0, 80, true);
|
||||
timerAttachInterrupt(timer, &onTimer, true);
|
||||
timerAlarmWrite(timer, 10000, true); // every 0.1 seconds
|
||||
timerAlarmEnable(timer);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
void loop() {
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
#endif
|
||||
/////////////////////////////////////////////////////////////////
|
|
@ -0,0 +1,76 @@
|
|||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
#if !defined(ESP32)
|
||||
#error This sketch needs an ESP32 Classic
|
||||
#else
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "Button2.h"
|
||||
|
||||
#define TOUCH_PIN T0 // Must declare the touch assignment, not the pin. For example, T0 is GPIO4 and T3 is GPIO 15.
|
||||
// You can look up the touch assignment in the datasheet: https://www.espressif.com/sites/default/files/documentation/esp32_datasheet_en.pdf
|
||||
|
||||
int threshold = 40; // ESP32
|
||||
bool touchActive = false;
|
||||
bool lastTouchActive = false;
|
||||
bool testingLower = true;
|
||||
byte buttonState = HIGH;// HIGH is for unpressed, pressed = LOW
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
Button2 button;
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
void gotTouchEvent(){
|
||||
if (lastTouchActive != testingLower) {
|
||||
touchActive = !touchActive;
|
||||
testingLower = !testingLower;
|
||||
// Touch ISR will be inverted: Lower <--> Higher than the Threshold after ISR event is noticed
|
||||
touchInterruptSetThresholdDirection(testingLower);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
byte capStateHandler() {
|
||||
return buttonState;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
delay(50);
|
||||
Serial.println("\n\nCapacitive Touch Demo");
|
||||
touchAttachInterrupt(TOUCH_PIN, gotTouchEvent, threshold);
|
||||
|
||||
// Touch ISR will be activated when touchRead is lower than the Threshold
|
||||
touchInterruptSetThresholdDirection(testingLower);
|
||||
button.setDebounceTime(35);
|
||||
button.setButtonStateFunction(capStateHandler);
|
||||
button.setClickHandler(click);
|
||||
button.begin(VIRTUAL_PIN);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
void loop() {
|
||||
button.loop();
|
||||
if(lastTouchActive != touchActive){
|
||||
lastTouchActive = touchActive;
|
||||
if (touchActive) {
|
||||
buttonState = LOW;
|
||||
} else {
|
||||
buttonState = HIGH;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
void click(Button2& btn) {
|
||||
Serial.println("click\n");
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
#endif
|
||||
/////////////////////////////////////////////////////////////////
|
62
lib/Button2/examples/LongpressHandler/LongpressHandler.ino
Normal file
62
lib/Button2/examples/LongpressHandler/LongpressHandler.ino
Normal file
|
@ -0,0 +1,62 @@
|
|||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "Button2.h"
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
#define BUTTON_PIN 2
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
Button2 button;
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
void setup() {
|
||||
Serial.begin(9600);
|
||||
while (!Serial) {
|
||||
delay(20);
|
||||
}
|
||||
Serial.println("\n\nLongpress Handler Demo");
|
||||
button.begin(BUTTON_PIN);
|
||||
|
||||
// button.setLongClickDetectedRetriggerable(true);
|
||||
|
||||
button.setLongClickHandler(longClick);
|
||||
button.setLongClickDetectedHandler(longClickDetected);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
void loop() {
|
||||
button.loop();
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
void longClick(Button2& btn) {
|
||||
unsigned int time = btn.wasPressedFor();
|
||||
Serial.print("You clicked ");
|
||||
if (time > 1500) {
|
||||
Serial.print("a really really long time.");
|
||||
} else if (time > 1000) {
|
||||
Serial.print("a really long time.");
|
||||
} else if (time > 500) {
|
||||
Serial.print("a long time.");
|
||||
} else {
|
||||
Serial.print("long.");
|
||||
}
|
||||
Serial.print(" (");
|
||||
Serial.print(time);
|
||||
Serial.println(" ms)");
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
void longClickDetected(Button2& btn) {
|
||||
Serial.print("long click #");
|
||||
Serial.print(btn.getLongClickCount());
|
||||
Serial.println(" detected");
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
|
@ -0,0 +1,98 @@
|
|||
#include "M5Core2.h"
|
||||
#include "Button2.h"
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
Button2 button;
|
||||
bool cleared = false;
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
byte myButtonStateHandler() {
|
||||
return !(M5.BtnA.isPressed());
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
void setup() {
|
||||
M5.begin();
|
||||
|
||||
button.setDoubleClickTime(300);
|
||||
|
||||
// button.setChangedHandler(changed);
|
||||
// button.setPressedHandler(pressed);
|
||||
button.setReleasedHandler(released);
|
||||
|
||||
// button.setTapHandler(tap);
|
||||
button.setClickHandler(click);
|
||||
button.setLongClickDetectedHandler(longClickDetected);
|
||||
// button.setLongClickHandler(longClick);
|
||||
|
||||
button.setDoubleClickHandler(doubleClick);
|
||||
button.setTripleClickHandler(tripleClick);
|
||||
|
||||
button.setButtonStateFunction(myButtonStateHandler);
|
||||
button.begin(VIRTUAL_PIN);
|
||||
|
||||
M5.Lcd.clear();
|
||||
M5.Lcd.setTextSize(2);
|
||||
M5.Lcd.setTextWrap(true, true);
|
||||
M5.Lcd.print("Button A Test");
|
||||
M5.Lcd.print("\n");
|
||||
M5.Lcd.print("\n");
|
||||
}
|
||||
|
||||
void loop() {
|
||||
button.loop();
|
||||
// clear screen if wrap happened
|
||||
if (M5.Lcd.getCursorY() <= 16) {
|
||||
if (!cleared) {
|
||||
M5.Lcd.clear();
|
||||
Serial.println("now");
|
||||
cleared = true;
|
||||
}
|
||||
} else {
|
||||
cleared = false;
|
||||
}
|
||||
M5.update();
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
void pressed(Button2& btn) {
|
||||
M5.Lcd.print("pressed");
|
||||
M5.Lcd.print("\n");
|
||||
}
|
||||
void released(Button2& btn) {
|
||||
M5.Lcd.print("released: ");
|
||||
M5.Lcd.print(btn.wasPressedFor());
|
||||
M5.Lcd.print("\n");
|
||||
}
|
||||
void changed(Button2& btn) {
|
||||
M5.Lcd.print("changed");
|
||||
M5.Lcd.print("\n");
|
||||
}
|
||||
void click(Button2& btn) {
|
||||
M5.Lcd.print("click");
|
||||
M5.Lcd.print("\n");
|
||||
}
|
||||
void longClickDetected(Button2& btn) {
|
||||
M5.Lcd.print("long click detected");
|
||||
M5.Lcd.print("\n");
|
||||
}
|
||||
void longClick(Button2& btn) {
|
||||
M5.Lcd.print("long click");
|
||||
M5.Lcd.print("\n");
|
||||
}
|
||||
void doubleClick(Button2& btn) {
|
||||
M5.Lcd.print("double click");
|
||||
M5.Lcd.print("\n");
|
||||
}
|
||||
void tripleClick(Button2& btn) {
|
||||
M5.Lcd.print("triple click\n");
|
||||
M5.Lcd.print("\n");
|
||||
}
|
||||
void tap(Button2& btn) {
|
||||
M5.Lcd.print("tap");
|
||||
M5.Lcd.print("\n");
|
||||
}
|
55
lib/Button2/examples/MultiHandler/MultiHandler.ino
Normal file
55
lib/Button2/examples/MultiHandler/MultiHandler.ino
Normal file
|
@ -0,0 +1,55 @@
|
|||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "Button2.h"
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
#define BUTTON_PIN 2
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
Button2 button;
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
void setup() {
|
||||
Serial.begin(9600);
|
||||
delay(50);
|
||||
Serial.println("\n\nMulti Handler Demo");
|
||||
|
||||
button.begin(BUTTON_PIN);
|
||||
button.setClickHandler(handler);
|
||||
// button.setLongClickHandler(handler); // this will only be called upon release
|
||||
button.setLongClickDetectedHandler(handler); // this will only be called upon detection
|
||||
button.setDoubleClickHandler(handler);
|
||||
button.setTripleClickHandler(handler);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
void loop() {
|
||||
button.loop();
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
void handler(Button2& btn) {
|
||||
switch (btn.getType()) {
|
||||
case single_click:
|
||||
break;
|
||||
case double_click:
|
||||
Serial.print("double ");
|
||||
break;
|
||||
case triple_click:
|
||||
Serial.print("triple ");
|
||||
break;
|
||||
case long_click:
|
||||
Serial.print("long");
|
||||
break;
|
||||
}
|
||||
Serial.print("click");
|
||||
Serial.print(" (");
|
||||
Serial.print(btn.getNumberOfClicks());
|
||||
Serial.println(")");
|
||||
}
|
||||
/////////////////////////////////////////////////////////////////
|
|
@ -0,0 +1,53 @@
|
|||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "Button2.h"
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
#define BUTTON_PIN_1 3
|
||||
#define BUTTON_PIN_2 4
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
Button2 button_1, button_2;
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
void setup() {
|
||||
Serial.begin(9600);
|
||||
delay(50);
|
||||
Serial.println("\n\nMulti Handler Demo w/ 2 buttons");
|
||||
|
||||
button_1.begin(BUTTON_PIN_1);
|
||||
button_1.setClickHandler(handler);
|
||||
button_1.setDoubleClickHandler(handler);
|
||||
|
||||
button_2.begin(BUTTON_PIN_2);
|
||||
button_2.setClickHandler(handler);
|
||||
button_2.setDoubleClickHandler(handler);
|
||||
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
void loop() {
|
||||
button_1.loop();
|
||||
button_2.loop();
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
void handler(Button2& btn) {
|
||||
switch (btn.getType()) {
|
||||
case single_click:
|
||||
break;
|
||||
case double_click:
|
||||
Serial.print("double ");
|
||||
break;
|
||||
}
|
||||
Serial.print("click ");
|
||||
Serial.print("on button #");
|
||||
Serial.print((btn == button_1) ? "1" : "2");
|
||||
Serial.println();
|
||||
}
|
||||
/////////////////////////////////////////////////////////////////
|
45
lib/Button2/examples/MultipleButtons/MultipleButtons.ino
Normal file
45
lib/Button2/examples/MultipleButtons/MultipleButtons.ino
Normal file
|
@ -0,0 +1,45 @@
|
|||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "Button2.h"
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
#define BUTTON_A_PIN 2
|
||||
#define BUTTON_B_PIN 0
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
Button2 buttonA, buttonB;
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
void setup() {
|
||||
Serial.begin(9600);
|
||||
delay(50);
|
||||
Serial.println("\n\nMultiple Buttons Demo");
|
||||
|
||||
buttonA.begin(BUTTON_A_PIN);
|
||||
buttonA.setClickHandler(click);
|
||||
|
||||
buttonB.begin(BUTTON_B_PIN);
|
||||
buttonB.setClickHandler(click);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
void loop() {
|
||||
buttonA.loop();
|
||||
buttonB.loop();
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
void click(Button2& btn) {
|
||||
if (btn == buttonA) {
|
||||
Serial.println("A clicked");
|
||||
} else if (btn == buttonB) {
|
||||
Serial.println("B clicked");
|
||||
}
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
80
lib/Button2/examples/SingleButton/SingleButton.ino
Normal file
80
lib/Button2/examples/SingleButton/SingleButton.ino
Normal file
|
@ -0,0 +1,80 @@
|
|||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "Button2.h"
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
#define BUTTON_PIN 37
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
Button2 button;
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
void setup() {
|
||||
Serial.begin(9600);
|
||||
delay(50);
|
||||
Serial.println("\n\nButton Demo");
|
||||
|
||||
button.begin(BUTTON_PIN);
|
||||
// button.setLongClickTime(1000);
|
||||
// button.setDoubleClickTime(400);
|
||||
|
||||
Serial.println(" Longpress Time:\t" + String(button.getLongClickTime()) + "ms");
|
||||
Serial.println(" DoubleClick Time:\t" + String(button.getDoubleClickTime()) + "ms");
|
||||
Serial.println();
|
||||
|
||||
// button.setChangedHandler(changed);
|
||||
// button.setPressedHandler(pressed);
|
||||
button.setReleasedHandler(released);
|
||||
|
||||
// button.setTapHandler(tap);
|
||||
button.setClickHandler(click);
|
||||
button.setLongClickDetectedHandler(longClickDetected);
|
||||
button.setLongClickHandler(longClick);
|
||||
button.setLongClickDetectedRetriggerable(false);
|
||||
|
||||
button.setDoubleClickHandler(doubleClick);
|
||||
button.setTripleClickHandler(tripleClick);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
void loop() {
|
||||
button.loop();
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
void pressed(Button2& btn) {
|
||||
Serial.println("pressed");
|
||||
}
|
||||
void released(Button2& btn) {
|
||||
Serial.print("released: ");
|
||||
Serial.println(btn.wasPressedFor());
|
||||
}
|
||||
void changed(Button2& btn) {
|
||||
Serial.println("changed");
|
||||
}
|
||||
void click(Button2& btn) {
|
||||
Serial.println("click\n");
|
||||
}
|
||||
void longClickDetected(Button2& btn) {
|
||||
Serial.println("long click detected");
|
||||
}
|
||||
void longClick(Button2& btn) {
|
||||
Serial.println("long click\n");
|
||||
}
|
||||
void doubleClick(Button2& btn) {
|
||||
Serial.println("double click\n");
|
||||
}
|
||||
void tripleClick(Button2& btn) {
|
||||
Serial.println("triple click\n");
|
||||
Serial.println(btn.getNumberOfClicks());
|
||||
}
|
||||
void tap(Button2& btn) {
|
||||
Serial.println("tap");
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
|
@ -0,0 +1,51 @@
|
|||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "Button2.h"
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
#define BUTTON_PIN 2
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
Button2 button;
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
void setup() {
|
||||
Serial.begin(9600);
|
||||
delay(50);
|
||||
Serial.println("\n\nButton Demo");
|
||||
|
||||
button.begin(BUTTON_PIN);
|
||||
button.setChangedHandler(changed);
|
||||
//button.setPressedHandler(pressed);
|
||||
//button.setReleasedHandler(released);
|
||||
|
||||
// setTapHandler() is called by any type of click, longpress or shortpress
|
||||
button.setTapHandler(tap);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
void loop() {
|
||||
button.loop();
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
void pressed(Button2& btn) {
|
||||
Serial.println("pressed");
|
||||
}
|
||||
void released(Button2& btn) {
|
||||
Serial.print("released: ");
|
||||
Serial.println(btn.wasPressedFor());
|
||||
}
|
||||
void changed(Button2& btn) {
|
||||
Serial.println("changed");
|
||||
}
|
||||
void tap(Button2& btn) {
|
||||
Serial.println("tap");
|
||||
}
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
|
@ -0,0 +1,64 @@
|
|||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "Button2.h"
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
#define BUTTON_PIN_1 3
|
||||
#define BUTTON_PIN_2 4
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
Button2 button_1, button_2;
|
||||
|
||||
unsigned long now = 0;
|
||||
byte counter = 0;
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
void setup() {
|
||||
Serial.begin(9600);
|
||||
delay(50);
|
||||
Serial.println("\n\nTrack dual button press & release");
|
||||
|
||||
button_1.begin(BUTTON_PIN_1);
|
||||
button_1.setPressedHandler(pressed);
|
||||
button_1.setReleasedHandler(released);
|
||||
|
||||
button_2.begin(BUTTON_PIN_2);
|
||||
button_2.setPressedHandler(pressed);
|
||||
button_2.setReleasedHandler(released);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
void loop() {
|
||||
button_1.loop();
|
||||
button_2.loop();
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
void pressed(Button2& btn) {
|
||||
counter++;
|
||||
if (counter == 2) {
|
||||
now = millis();
|
||||
Serial.println("now!");
|
||||
}
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
void released(Button2& btn) {
|
||||
counter--;
|
||||
if (counter == 0) {
|
||||
if (now != 0) {
|
||||
Serial.print("Pressed for: ");
|
||||
Serial.print(millis() - now);
|
||||
Serial.println("ms");
|
||||
}
|
||||
now = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
44
lib/Button2/keywords.txt
Executable file
44
lib/Button2/keywords.txt
Executable file
|
@ -0,0 +1,44 @@
|
|||
Button2 KEYWORD1
|
||||
begin KEYWORD2
|
||||
setDebounceTime KEYWORD2
|
||||
setLongClickTime KEYWORD2
|
||||
setDoubleClickTime KEYWORD2
|
||||
getDebounceTime KEYWORD2
|
||||
getLongClickTime KEYWORD2
|
||||
getDoubleClickTime KEYWORD2
|
||||
getPin KEYWORD2
|
||||
setLongClickDetectedRetriggerable KEYWORD2
|
||||
reset KEYWORD2
|
||||
setChangedHandler KEYWORD2
|
||||
setPressedHandler KEYWORD2
|
||||
setReleasedHandler KEYWORD2
|
||||
setTapHandler KEYWORD2
|
||||
setClickHandler KEYWORD2
|
||||
setDoubleClickHandler KEYWORD2
|
||||
setTripleClickHandler KEYWORD2
|
||||
setLongClickHandler KEYWORD2
|
||||
setLongClickDetectedHandler KEYWORD2
|
||||
wasPressedFor KEYWORD2
|
||||
isPressed KEYWORD2
|
||||
isPressedRaw KEYWORD2
|
||||
getNumberOfClicks KEYWORD2
|
||||
getType KEYWORD2
|
||||
clickToString KEYWORD2
|
||||
getID KEYWORD2
|
||||
setID KEYWORD2
|
||||
wasPressed KEYWORD2
|
||||
resetPressedState KEYWORD2
|
||||
read KEYWORD2
|
||||
getLongClickCount KEYWORD2
|
||||
wait KEYWORD2
|
||||
waitForClick KEYWORD2
|
||||
waitForDouble KEYWORD2
|
||||
waitForTriple KEYWORD2
|
||||
waitForLong KEYWORD2
|
||||
loop KEYWORD2
|
||||
BTN_DEBOUNCE_MS LITERAL1
|
||||
BTN_LONGCLICK_MS LITERAL1
|
||||
BTN_DOUBLECLICK_MS LITERAL1
|
||||
BTN_UNDEFINED_PIN LITERAL1
|
||||
BTN_VIRTUAL_PIN LITERAL1
|
||||
clickType LITERAL1
|
17
lib/Button2/library.json
Normal file
17
lib/Button2/library.json
Normal file
|
@ -0,0 +1,17 @@
|
|||
{
|
||||
"name": "Button2",
|
||||
"version": "2.3.1",
|
||||
"keywords": "button",
|
||||
"description": "Arduino/ESP Library to simplify working with buttons. It allows you to use callback functions to track single, double, triple and long clicks. Alternatively, it provides function to use in your main loop(). The library also takes care of debouncing. Using this lib will reduce and simplify your source code significantly.",
|
||||
"homepage": "https://github.com/LennartHennigs/Button2",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/LennartHennigs/Button2"
|
||||
},
|
||||
"authors": {
|
||||
"name": "Lennart Hennigs",
|
||||
"url": "https://lennarthennigs.de"
|
||||
},
|
||||
"frameworks": "arduino",
|
||||
"platforms": "*"
|
||||
}
|
9
lib/Button2/library.properties
Normal file
9
lib/Button2/library.properties
Normal file
|
@ -0,0 +1,9 @@
|
|||
name=Button2
|
||||
version=2.3.1
|
||||
author=Lennart Hennigs
|
||||
maintainer=Lennart Hennigs <mail@lennarthennigs.de>
|
||||
sentence=Arduino/ESP library to simplify working with buttons.
|
||||
paragraph=It allows you to use callback functions to track single, double, triple and long clicks. Alternatively, it provides function to use in your main loop(). The library also takes care of debouncing. Using this lib will reduce and simplify your source code significantly.
|
||||
category=Communication
|
||||
url=https://github.com/LennartHennigs/Button2
|
||||
architectures=*
|
477
lib/Button2/src/Button2.cpp
Executable file
477
lib/Button2/src/Button2.cpp
Executable file
|
@ -0,0 +1,477 @@
|
|||
/////////////////////////////////////////////////////////////////
|
||||
/*
|
||||
Button2.cpp - Arduino Library to simplify working with buttons.
|
||||
Copyright (C) 2017-2023 Lennart Hennigs.
|
||||
Released under the MIT license.
|
||||
*/
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "Button2.h"
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// initialize static counter for the IDs
|
||||
|
||||
int Button2::_nextID = 0;
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// default constructor
|
||||
|
||||
Button2::Button2() {
|
||||
pin = BTN_UNDEFINED_PIN;
|
||||
_setID();
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// constructor
|
||||
|
||||
Button2::Button2(byte attachTo, byte buttonMode /* = INPUT_PULLUP */, boolean activeLow /* = true */, Hardware *hardware /* = ArduinoHardware() */) {
|
||||
begin(attachTo, buttonMode, activeLow, hardware);
|
||||
_setID();
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
void Button2::begin(byte attachTo, byte buttonMode /* = INPUT_PULLUP */, boolean activeLow /* = true */, Hardware *hardware /* = ArduinoHardware() */) {
|
||||
hw = hardware;
|
||||
pin = attachTo;
|
||||
longclick_counter = 0;
|
||||
longclick_retriggerable = false;
|
||||
_pressedState = activeLow ? LOW : HIGH;
|
||||
|
||||
if (attachTo != BTN_VIRTUAL_PIN) {
|
||||
hw->pinMode(attachTo, buttonMode);
|
||||
}
|
||||
// state = activeLow ? HIGH : LOW;
|
||||
state = _getState();
|
||||
prev_state = state;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
void Button2::setDebounceTime(unsigned int ms) {
|
||||
debounce_time_ms = ms;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
void Button2::setLongClickTime(unsigned int ms) {
|
||||
longclick_time_ms = ms;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
void Button2::setDoubleClickTime(unsigned int ms) {
|
||||
doubleclick_time_ms = ms;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
unsigned int Button2::getDebounceTime() const {
|
||||
return debounce_time_ms;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
unsigned int Button2::getLongClickTime() const {
|
||||
return longclick_time_ms;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
unsigned int Button2::getDoubleClickTime() const {
|
||||
return doubleclick_time_ms;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
byte Button2::getPin() const {
|
||||
return pin;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
void Button2::setButtonStateFunction(StateCallbackFunction f) {
|
||||
get_state_cb = f;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
bool Button2::operator==(Button2 &rhs) {
|
||||
return (this == &rhs);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
void Button2::setChangedHandler(CallbackFunction f) {
|
||||
change_cb = f;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
void Button2::setPressedHandler(CallbackFunction f) {
|
||||
pressed_cb = f;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
void Button2::setReleasedHandler(CallbackFunction f) {
|
||||
released_cb = f;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
void Button2::setClickHandler(CallbackFunction f) {
|
||||
click_cb = f;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
void Button2::setTapHandler(CallbackFunction f) {
|
||||
tap_cb = f;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
void Button2::setLongClickHandler(CallbackFunction f) {
|
||||
long_cb = f;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
void Button2::setLongClickDetectedRetriggerable(bool retriggerable) {
|
||||
longclick_retriggerable = retriggerable;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
void Button2::setLongClickDetectedHandler(CallbackFunction f) {
|
||||
longclick_detected_cb = f;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
void Button2::setDoubleClickHandler(CallbackFunction f) {
|
||||
double_cb = f;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
void Button2::setTripleClickHandler(CallbackFunction f) {
|
||||
triple_cb = f;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
unsigned int Button2::wasPressedFor() const {
|
||||
return down_time_ms;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
boolean Button2::isPressed() const {
|
||||
return (state == _pressedState);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
boolean Button2::isPressedRaw() const {
|
||||
return (_getState() == _pressedState);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
byte Button2::getNumberOfClicks() const {
|
||||
return last_click_count;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
clickType Button2::getType() const {
|
||||
return last_click_type;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
int Button2::getID() const {
|
||||
return id;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
void Button2::setID(int newID) {
|
||||
id = newID;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
String Button2::clickToString(clickType type) const {
|
||||
if (type == single_click) return "single click";
|
||||
if (type == double_click) return "double click";
|
||||
if (type == triple_click) return "triple click";
|
||||
if (type == long_click) return "long click";
|
||||
return "none";
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
bool Button2::wasPressed() const {
|
||||
return was_pressed;
|
||||
}
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
void Button2::resetPressedState() {
|
||||
last_click_count = 0;
|
||||
was_pressed = false;
|
||||
last_click_type = empty;
|
||||
click_count = 0;
|
||||
down_time_ms = 0;
|
||||
pressed_triggered = false;
|
||||
longclick_detected = false;
|
||||
longclick_reported = false;
|
||||
longclick_counter = 0;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
clickType Button2::read(bool keepState /* = false */) {
|
||||
if (keepState) return last_click_type;
|
||||
|
||||
clickType res = last_click_type;
|
||||
resetPressedState();
|
||||
return res;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
clickType Button2::wait(bool keepState /* = false */) {
|
||||
while (!wasPressed()) {
|
||||
loop();
|
||||
}
|
||||
return read(keepState);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
void Button2::waitForClick(bool keepState /* = false */) {
|
||||
do {
|
||||
while (!wasPressed()) {
|
||||
loop();
|
||||
}
|
||||
} while (read() != single_click);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
void Button2::waitForDouble(bool keepState /* = false */) {
|
||||
do {
|
||||
while (!wasPressed()) {
|
||||
loop();
|
||||
}
|
||||
} while (read() != double_click);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
void Button2::waitForTriple(bool keepState /* = false */) {
|
||||
do {
|
||||
while (!wasPressed()) {
|
||||
loop();
|
||||
}
|
||||
} while (read() != triple_click);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
void Button2::waitForLong(bool keepState /* = false */) {
|
||||
do {
|
||||
while (!wasPressed()) {
|
||||
loop();
|
||||
}
|
||||
} while (read() != long_click);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
void Button2::reset() {
|
||||
pin = BTN_UNDEFINED_PIN;
|
||||
|
||||
resetPressedState();
|
||||
|
||||
pressed_cb = NULL;
|
||||
released_cb = NULL;
|
||||
change_cb = NULL;
|
||||
tap_cb = NULL;
|
||||
click_cb = NULL;
|
||||
long_cb = NULL;
|
||||
longclick_detected_cb = NULL;
|
||||
double_cb = NULL;
|
||||
triple_cb = NULL;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
void Button2::loop() {
|
||||
if (pin == BTN_UNDEFINED_PIN) return;
|
||||
|
||||
prev_state = state;
|
||||
state = _getState();
|
||||
|
||||
if (state == _pressedState) {
|
||||
_handlePress(millis());
|
||||
} else {
|
||||
_handleRelease(millis());
|
||||
}
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
void Button2::_handlePress(long now) {
|
||||
// is it pressed now?
|
||||
if (prev_state != _pressedState) {
|
||||
_pressedNow(now);
|
||||
return;
|
||||
}
|
||||
// is it pressed for a while?
|
||||
if (!pressed_triggered) {
|
||||
if (now - down_ms >= debounce_time_ms) {
|
||||
pressed_triggered = true;
|
||||
_validKeypress();
|
||||
}
|
||||
}
|
||||
// only check for long press on the first click
|
||||
if (click_count == 1) {
|
||||
_checkForLongClick(now);
|
||||
}
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
void Button2::_setID() {
|
||||
id = _nextID;
|
||||
_nextID++;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
void Button2::_handleRelease(long now) {
|
||||
// is it released right now?
|
||||
if (prev_state == _pressedState) {
|
||||
_releasedNow(now);
|
||||
return;
|
||||
}
|
||||
// report click after double click time has passed
|
||||
if (now - click_ms > doubleclick_time_ms) {
|
||||
_reportClicks();
|
||||
}
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
void Button2::_pressedNow(long now) {
|
||||
down_ms = now;
|
||||
pressed_triggered = false;
|
||||
click_ms = down_ms;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
void Button2::_validKeypress() {
|
||||
click_count++;
|
||||
if (change_cb != NULL) change_cb(*this);
|
||||
if (pressed_cb != NULL) pressed_cb(*this);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
void Button2::_checkForLongClick(long now) {
|
||||
if (longclick_detected_cb == NULL) return;
|
||||
if (longclick_reported) return;
|
||||
|
||||
// has the longclick_ms period has been exceeded?
|
||||
if (now - down_ms < (longclick_time_ms * (longclick_counter + 1))) return;
|
||||
// report multiple?
|
||||
|
||||
if (!longclick_retriggerable) {
|
||||
longclick_reported = true;
|
||||
}
|
||||
|
||||
longclick_counter++;
|
||||
longclick_detected_cb(*this);
|
||||
longclick_detected = true;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
byte Button2::getLongClickCount() const {
|
||||
return longclick_counter;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
void Button2::_reportClicks() {
|
||||
// no click
|
||||
if (click_count == 0) return;
|
||||
|
||||
last_click_count = click_count;
|
||||
|
||||
// single or long press
|
||||
if (click_count == 1) {
|
||||
// long press
|
||||
if (longclick_detected) {
|
||||
last_click_type = long_click;
|
||||
if (long_cb != NULL) long_cb(*this);
|
||||
longclick_counter = 0;
|
||||
// single click
|
||||
} else {
|
||||
last_click_type = single_click;
|
||||
if (click_cb != NULL) click_cb (*this);
|
||||
}
|
||||
|
||||
// double click
|
||||
} else if (click_count == 2) {
|
||||
last_click_type = double_click;
|
||||
if (double_cb != NULL) double_cb(*this);
|
||||
|
||||
// triple or x-clicks
|
||||
} else {
|
||||
last_click_type = triple_click;
|
||||
if (triple_cb != NULL) triple_cb(*this);
|
||||
}
|
||||
|
||||
was_pressed = true;
|
||||
click_count = 0;
|
||||
click_ms = 0;
|
||||
longclick_detected = false;
|
||||
longclick_reported = false;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
void Button2::_releasedNow(long now) {
|
||||
down_time_ms = now - down_ms;
|
||||
// is it beyond debounce time?
|
||||
if (down_time_ms < debounce_time_ms) return;
|
||||
// trigger release
|
||||
if (change_cb != NULL) change_cb(*this);
|
||||
if (released_cb != NULL) released_cb(*this);
|
||||
// trigger tap
|
||||
if (tap_cb != NULL) tap_cb(*this);
|
||||
// was it a longclick? (precedes single / double / triple clicks)
|
||||
if (down_time_ms >= longclick_time_ms) {
|
||||
longclick_detected = true;
|
||||
}
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
byte Button2::_getState() const {
|
||||
if (get_state_cb != NULL) {
|
||||
return get_state_cb();
|
||||
} else {
|
||||
return hw->digitalRead(pin);
|
||||
}
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
165
lib/Button2/src/Button2.h
Executable file
165
lib/Button2/src/Button2.h
Executable file
|
@ -0,0 +1,165 @@
|
|||
/////////////////////////////////////////////////////////////////
|
||||
/*
|
||||
Button2.h - Arduino Library to simplify working with buttons.
|
||||
Copyright (C) 2017-2023 Lennart Hennigs.
|
||||
Released under the MIT license.
|
||||
|
||||
*/
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef Button2_h
|
||||
#define Button2_h
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
#if defined(ARDUINO_ARCH_ESP32) || defined(ESP8266)
|
||||
#include <functional>
|
||||
#endif
|
||||
#include <Arduino.h>
|
||||
|
||||
#include "Hardware.h"
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
const unsigned int BTN_DEBOUNCE_MS = 50;
|
||||
const unsigned int BTN_LONGCLICK_MS = 200;
|
||||
const unsigned int BTN_DOUBLECLICK_MS = 300;
|
||||
|
||||
const unsigned int BTN_UNDEFINED_PIN = 255;
|
||||
const unsigned int BTN_VIRTUAL_PIN = 254;
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
enum clickType {
|
||||
single_click,
|
||||
double_click,
|
||||
triple_click,
|
||||
long_click,
|
||||
empty
|
||||
};
|
||||
|
||||
class Button2 {
|
||||
protected:
|
||||
int id;
|
||||
byte pin;
|
||||
byte state;
|
||||
byte prev_state;
|
||||
byte click_count = 0;
|
||||
byte last_click_count = 0;
|
||||
clickType last_click_type = empty;
|
||||
bool was_pressed = false;
|
||||
unsigned long click_ms;
|
||||
unsigned long down_ms;
|
||||
|
||||
bool longclick_retriggerable;
|
||||
uint16_t longclick_counter = 0;
|
||||
bool longclick_detected = false;
|
||||
bool longclick_reported = false;
|
||||
|
||||
unsigned int debounce_time_ms = BTN_DEBOUNCE_MS;
|
||||
unsigned int longclick_time_ms = BTN_LONGCLICK_MS;
|
||||
unsigned int doubleclick_time_ms = BTN_DOUBLECLICK_MS;
|
||||
|
||||
unsigned int down_time_ms = 0;
|
||||
bool pressed_triggered = false;
|
||||
|
||||
#if defined(ARDUINO_ARCH_ESP32) || defined(ESP8266)
|
||||
typedef std::function<void(Button2 &btn)> CallbackFunction;
|
||||
typedef std::function<byte()> StateCallbackFunction;
|
||||
#else
|
||||
typedef void (*CallbackFunction)(Button2 &);
|
||||
typedef byte (*StateCallbackFunction)();
|
||||
#endif
|
||||
|
||||
StateCallbackFunction get_state_cb = NULL;
|
||||
|
||||
CallbackFunction pressed_cb = NULL;
|
||||
CallbackFunction released_cb = NULL;
|
||||
CallbackFunction change_cb = NULL;
|
||||
CallbackFunction tap_cb = NULL;
|
||||
CallbackFunction click_cb = NULL;
|
||||
CallbackFunction long_cb = NULL;
|
||||
CallbackFunction longclick_detected_cb = NULL;
|
||||
CallbackFunction double_cb = NULL;
|
||||
CallbackFunction triple_cb = NULL;
|
||||
|
||||
void _handlePress(long now);
|
||||
void _handleRelease(long now);
|
||||
void _releasedNow(long now);
|
||||
void _pressedNow(long now);
|
||||
void _validKeypress();
|
||||
void _checkForLongClick(long now);
|
||||
void _reportClicks();
|
||||
void _setID();
|
||||
|
||||
public:
|
||||
Button2();
|
||||
Button2(byte attachTo, byte buttonMode = INPUT_PULLUP, boolean activeLow = true, Hardware* hardware = new ArduinoHardware());
|
||||
|
||||
void begin(byte attachTo, byte buttonMode = INPUT_PULLUP, boolean activeLow = true, Hardware* hardware = new ArduinoHardware());
|
||||
|
||||
void setDebounceTime(unsigned int ms);
|
||||
void setLongClickTime(unsigned int ms);
|
||||
void setDoubleClickTime(unsigned int ms);
|
||||
|
||||
unsigned int getDebounceTime() const;
|
||||
unsigned int getLongClickTime() const;
|
||||
unsigned int getDoubleClickTime() const;
|
||||
byte getPin() const;
|
||||
|
||||
void reset();
|
||||
|
||||
void setButtonStateFunction(StateCallbackFunction f);
|
||||
|
||||
void setChangedHandler(CallbackFunction f);
|
||||
void setPressedHandler(CallbackFunction f);
|
||||
void setReleasedHandler(CallbackFunction f);
|
||||
|
||||
void setTapHandler(CallbackFunction f);
|
||||
void setClickHandler(CallbackFunction f);
|
||||
void setDoubleClickHandler(CallbackFunction f);
|
||||
void setTripleClickHandler(CallbackFunction f);
|
||||
|
||||
void setLongClickHandler(CallbackFunction f);
|
||||
void setLongClickDetectedHandler(CallbackFunction f);
|
||||
|
||||
void setLongClickDetectedRetriggerable(bool retriggerable);
|
||||
|
||||
unsigned int wasPressedFor() const;
|
||||
boolean isPressed() const;
|
||||
boolean isPressedRaw() const;
|
||||
void resetPressedState();
|
||||
|
||||
bool wasPressed() const;
|
||||
clickType read(bool keepState = false);
|
||||
clickType wait(bool keepState = false);
|
||||
void waitForClick(bool keepState = false);
|
||||
void waitForDouble(bool keepState = false);
|
||||
void waitForTriple(bool keepState = false);
|
||||
void waitForLong(bool keepState = false);
|
||||
|
||||
byte getNumberOfClicks() const;
|
||||
byte getLongClickCount() const;
|
||||
|
||||
clickType getType() const;
|
||||
String clickToString(clickType type) const;
|
||||
|
||||
int getID() const;
|
||||
void setID(int newID);
|
||||
|
||||
bool operator==(Button2 &rhs);
|
||||
|
||||
void loop();
|
||||
|
||||
private:
|
||||
static int _nextID;
|
||||
byte _pressedState;
|
||||
byte _getState() const;
|
||||
Hardware* hw;
|
||||
|
||||
};
|
||||
/////////////////////////////////////////////////////////////////
|
||||
#endif
|
||||
/////////////////////////////////////////////////////////////////
|
99
lib/Button2/src/Hardware.h
Normal file
99
lib/Button2/src/Hardware.h
Normal file
|
@ -0,0 +1,99 @@
|
|||
/////////////////////////////////////////////////////////////////
|
||||
/*
|
||||
Hardware.h - Implements Arduino Hardware Abstraction Layer.
|
||||
Part or Button2 library for Arduino.
|
||||
Copyright (C) 2017-2023 Lennart Hennigs.
|
||||
Released under the MIT license.
|
||||
*/
|
||||
/////////////////////////////////////////////////////////////////
|
||||
#include <Arduino.h>
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef AbstractHardware_h
|
||||
#define AbstractHardware_h
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// disable warnings for unused parameters
|
||||
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wunused-parameter"
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// virtual class for hardware abstraction
|
||||
|
||||
class Hardware {
|
||||
public:
|
||||
virtual int digitalRead(int pin) = 0;
|
||||
virtual void pinMode(int pin, int mode) = 0;
|
||||
virtual void digitalWrite(int pin, int value) = 0;
|
||||
};
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// implementation for Arduino
|
||||
|
||||
#ifdef ARDUINO_ARCH_RP2040
|
||||
class ArduinoHardware : public Hardware {
|
||||
public:
|
||||
int digitalRead(int pin) {
|
||||
return ::digitalRead(pin);
|
||||
}
|
||||
|
||||
void pinMode(int pin, int mode) {
|
||||
::pinMode(pin, static_cast<PinMode>(mode));
|
||||
}
|
||||
|
||||
void digitalWrite(int pin, int value) {
|
||||
::digitalWrite(pin, static_cast<PinStatus>(value));
|
||||
}
|
||||
};
|
||||
#else
|
||||
class ArduinoHardware : public Hardware {
|
||||
public:
|
||||
int digitalRead(int pin) {
|
||||
|
||||
return ::digitalRead(pin);
|
||||
}
|
||||
void pinMode(int pin, int mode) {
|
||||
::pinMode(pin, mode);
|
||||
}
|
||||
void digitalWrite(int pin, int value) {
|
||||
::digitalWrite(pin, value);
|
||||
}
|
||||
};
|
||||
#endif
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// implementation for testing
|
||||
|
||||
class MockHardware : public Hardware {
|
||||
private:
|
||||
int pin_state[255];
|
||||
int pin_mode[255];
|
||||
|
||||
public:
|
||||
MockHardware() {
|
||||
for(int i = 0; i < 255; i++) {
|
||||
pin_state[i] = HIGH;
|
||||
pin_mode[i] = OUTPUT;
|
||||
}
|
||||
}
|
||||
|
||||
int digitalRead(int pin) override {
|
||||
return pin_state[pin];
|
||||
}
|
||||
void pinMode(int pin, int mode) override {
|
||||
pin_mode[pin] = mode;
|
||||
}
|
||||
void digitalWrite(int pin, int value) override {
|
||||
pin_state[pin] = value;
|
||||
}
|
||||
int getPinMode(int pin) {
|
||||
return pin_mode[pin];
|
||||
}
|
||||
};
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
/////////////////////////////////////////////////////////////////
|
498
lib/Button2/test/Button2Test/Button2Test.ino
Normal file
498
lib/Button2/test/Button2Test/Button2Test.ino
Normal file
|
@ -0,0 +1,498 @@
|
|||
#line 2 "Button2Test.ino"
|
||||
/////////////////////////////////////////////////////////////////
|
||||
/*
|
||||
Unit tests for Button2 library.
|
||||
Arduino Library to simplify working with buttons.
|
||||
|
||||
Created by Lennart Hennigs
|
||||
Tested on Wemos D1 Mini, M5Stack ESP32, Arduino UNO
|
||||
*/
|
||||
/////////////////////////////////////////////////////////////////
|
||||
/*
|
||||
To add:
|
||||
- check retriggerable long-clicks (setLongClickDetectedRetriggerable getLongClickCount())
|
||||
- check loop functions (read(), wait(), waitForClick(), waitForDouble(), waitForTriple())
|
||||
- check custom handler
|
||||
*/
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "AUnitVerbose.h"
|
||||
// #include "AUnit.h"
|
||||
#include "Button2.h"
|
||||
|
||||
using namespace aunit;
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
#define SERIAL_SPEED 115200
|
||||
|
||||
#define VERBOSE_CHANGED false
|
||||
#define VERBOSE_PRESS_RELEASE false
|
||||
#define VERBOSE_MAIN_EVENTS false // clicks, long presses
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
#define BUTTON_PIN 37
|
||||
#define BUTTON_MODE INPUT_PULLUP
|
||||
#define BUTTON_ACTIVE LOW
|
||||
|
||||
#define DEBOUNCE_MS BTN_DEBOUNCE_MS + 5
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
MockHardware hw;
|
||||
Button2 button;
|
||||
|
||||
bool pressed = false;
|
||||
bool released = false;
|
||||
bool tap = false;
|
||||
bool longclick = false;
|
||||
bool long_detected = false;
|
||||
int long_detected_count = 0;
|
||||
bool changed = false;
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
void setup_test_runner() {
|
||||
TestRunner::setVerbosity(Verbosity::kDefault);
|
||||
// TestRunner::setVerbosity(Verbosity::kAssertionFailed);
|
||||
// TestRunner::setVerbosityVerbosity::kAll);
|
||||
|
||||
TestRunner::list();
|
||||
/*
|
||||
TestRunner::exclude("*");
|
||||
// TestRunner::include("basics_*");
|
||||
// TestRunner::include("defaults_*");
|
||||
// TestRunner::include("settings_*");
|
||||
// TestRunner::include("clicks_*");
|
||||
// TestRunner::include("other_*");
|
||||
*/
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// helper functions
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
// pressing the button
|
||||
void press() {
|
||||
hw.digitalWrite(BUTTON_PIN, BUTTON_ACTIVE);
|
||||
button.loop();
|
||||
}
|
||||
|
||||
// letting it go
|
||||
void release() {
|
||||
hw.digitalWrite(BUTTON_PIN, !BUTTON_ACTIVE);
|
||||
button.loop();
|
||||
}
|
||||
|
||||
// emulate a button click
|
||||
void click(unsigned long duration) {
|
||||
press();
|
||||
delay(duration);
|
||||
button.loop();
|
||||
release();
|
||||
}
|
||||
|
||||
// resets all handler vars
|
||||
void resetHandlerVars() {
|
||||
pressed = false;
|
||||
released = false;
|
||||
tap = false;
|
||||
longclick = false;
|
||||
long_detected = false;
|
||||
changed = false;
|
||||
long_detected_count = 0;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// BASICS
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
test(basics, loop) {
|
||||
resetHandlerVars();
|
||||
button.resetPressedState();
|
||||
// press the button down
|
||||
hw.digitalWrite(BUTTON_PIN, BUTTON_ACTIVE);
|
||||
button.loop();
|
||||
// wait a while
|
||||
delay(DEBOUNCE_MS);
|
||||
// is there an update without the loop?
|
||||
assertFalse(pressed);
|
||||
// there should be one now
|
||||
button.loop();
|
||||
assertTrue(pressed);
|
||||
|
||||
// release the button
|
||||
hw.digitalWrite(BUTTON_PIN, !BUTTON_ACTIVE);
|
||||
// wait a while
|
||||
delay(DEBOUNCE_MS);
|
||||
// is there an update without the loop?
|
||||
assertFalse(released);
|
||||
// there should be one now
|
||||
button.loop();
|
||||
assertTrue(released);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
test(basics, equal_operator) {
|
||||
Button2 b;
|
||||
assertTrue(button == button);
|
||||
assertTrue(b == b);
|
||||
assertFalse(button == b);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// BASICS
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
test(clicks, changed_handler) {
|
||||
button.resetPressedState();
|
||||
changed = false;
|
||||
|
||||
press();
|
||||
// wait a bit
|
||||
delay(DEBOUNCE_MS);
|
||||
button.loop();
|
||||
// test
|
||||
assertTrue(changed);
|
||||
changed = false;
|
||||
// let go
|
||||
release();
|
||||
// test
|
||||
assertTrue(changed);
|
||||
// clean up
|
||||
changed = false;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
test(clicks, is_not_pressed) {
|
||||
release();
|
||||
button.resetPressedState();
|
||||
// run the tests
|
||||
assertFalse(button.isPressed());
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
test(clicks, is_pressed) {
|
||||
release();
|
||||
button.resetPressedState();
|
||||
press();
|
||||
// wait a bit
|
||||
delay(DEBOUNCE_MS);
|
||||
button.loop();
|
||||
// test
|
||||
assertTrue(button.isPressed());
|
||||
assertTrue(pressed);
|
||||
release();
|
||||
// clean up
|
||||
pressed = false;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
test(clicks, is_pressed_raw) {
|
||||
button.resetPressedState();
|
||||
press();
|
||||
// wait a bit
|
||||
delay(BTN_DEBOUNCE_MS);
|
||||
button.loop();
|
||||
// test
|
||||
assertTrue(button.isPressedRaw());
|
||||
release();
|
||||
// clean up
|
||||
assertFalse(button.isPressedRaw());
|
||||
pressed = false;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
test(clicks, not_a_click) {
|
||||
resetHandlerVars();
|
||||
button.resetPressedState();
|
||||
// click, but too short
|
||||
click(BTN_DEBOUNCE_MS - 10);
|
||||
delay(BTN_DOUBLECLICK_MS);
|
||||
button.loop();
|
||||
// run the tests
|
||||
assertFalse(button.wasPressed());
|
||||
assertFalse(tap);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
test(clicks, single_click) {
|
||||
resetHandlerVars();
|
||||
button.resetPressedState();
|
||||
// click
|
||||
int time = DEBOUNCE_MS;
|
||||
click(time);
|
||||
// wait out the double click time
|
||||
delay(BTN_DOUBLECLICK_MS);
|
||||
button.loop();
|
||||
int pressedFor = button.wasPressedFor();
|
||||
// run the tests
|
||||
assertTrue(button.wasPressed());
|
||||
assertNear(time, pressedFor, 10);
|
||||
assertEqual(button.getType(), single_click);
|
||||
assertEqual(button.getNumberOfClicks(), 1);
|
||||
assertTrue(tap);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
test(clicks, long_click) {
|
||||
resetHandlerVars();
|
||||
button.resetPressedState();
|
||||
// long click
|
||||
int time = BTN_LONGCLICK_MS + 10;
|
||||
click(time);
|
||||
// wait out the double click time
|
||||
delay(BTN_DOUBLECLICK_MS);
|
||||
button.loop();
|
||||
int pressedFor = button.wasPressedFor();
|
||||
// run the tests
|
||||
assertTrue(button.wasPressed());
|
||||
assertNear(time, pressedFor, 10);
|
||||
assertEqual(button.getType(), long_click);
|
||||
assertEqual(button.getNumberOfClicks(), 1);
|
||||
assertTrue(long_detected);
|
||||
assertTrue(longclick);
|
||||
assertTrue(tap);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
test(clicks, double_click) {
|
||||
button.resetPressedState();
|
||||
// 2x click
|
||||
int time = DEBOUNCE_MS;
|
||||
click(time);
|
||||
click(time);
|
||||
// wait out the double click time
|
||||
delay(BTN_DOUBLECLICK_MS);
|
||||
button.loop();
|
||||
// run the tests
|
||||
assertTrue(button.wasPressed());
|
||||
assertEqual(button.getType(), double_click);
|
||||
assertEqual(button.getNumberOfClicks(), 2);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
test(clicks, triple_click) {
|
||||
button.resetPressedState();
|
||||
// 3x click
|
||||
int time = DEBOUNCE_MS;
|
||||
click(time);
|
||||
click(time);
|
||||
click(time);
|
||||
// wait out the double click time
|
||||
delay(BTN_DOUBLECLICK_MS);
|
||||
button.loop();
|
||||
// run the tests
|
||||
assertTrue(button.wasPressed());
|
||||
assertEqual(button.getType(), triple_click);
|
||||
assertEqual(button.getNumberOfClicks(), 3);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
test(clicks, more_than_3_click) {
|
||||
button.resetPressedState();
|
||||
// 4x click
|
||||
int time = DEBOUNCE_MS;
|
||||
click(time);
|
||||
click(time);
|
||||
click(time);
|
||||
click(time);
|
||||
|
||||
delay(BTN_DOUBLECLICK_MS);
|
||||
button.loop();
|
||||
// run the tests
|
||||
assertTrue(button.wasPressed());
|
||||
assertEqual(button.getType(), triple_click);
|
||||
assertEqual(button.getNumberOfClicks(), 4);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
test (clicks, reset) {
|
||||
button.resetPressedState();
|
||||
// single click
|
||||
int time = DEBOUNCE_MS;
|
||||
click(time);
|
||||
// wait out the double click time
|
||||
delay(BTN_DOUBLECLICK_MS);
|
||||
button.loop();
|
||||
// run the tests
|
||||
assertTrue(button.wasPressed());
|
||||
assertEqual(button.getNumberOfClicks(), 1);
|
||||
// now reset the "click memory"
|
||||
button.resetPressedState();
|
||||
assertFalse(button.wasPressed());
|
||||
assertEqual(button.getNumberOfClicks(), 0);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// DEFAULTS
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
test(defaults, doubleclick_time) {
|
||||
assertEqual(button.getDoubleClickTime(), BTN_DOUBLECLICK_MS);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
test(defaults, debounce_time) {
|
||||
assertEqual(button.getDebounceTime(), BTN_DEBOUNCE_MS);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
test(defaults, longclick_time) {
|
||||
assertEqual(button.getLongClickTime(), BTN_LONGCLICK_MS);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
test(defaults, id) {
|
||||
assertTrue(button.getID() == 0);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
test(defaults, pin) {
|
||||
assertTrue(button.getPin() == BUTTON_PIN);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// SETTING
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
test(settings, id) {
|
||||
int id = 10;
|
||||
button.setID(id);
|
||||
// run the tests
|
||||
assertTrue(button.getID() == id);
|
||||
// clean up
|
||||
button.setID(0);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
test(settings, additional_ids) {
|
||||
Button2 b;
|
||||
assertNotEqual(b.getID(), button.getID());
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
test(settings, doubleclick_time) {
|
||||
unsigned int dc_time = BTN_DOUBLECLICK_MS + 1;
|
||||
button.setDoubleClickTime(dc_time);
|
||||
// run the tests
|
||||
assertEqual(button.getDoubleClickTime(), dc_time);
|
||||
// clean up
|
||||
button.setDoubleClickTime(BTN_DOUBLECLICK_MS);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
test(settings, longclick_time) {
|
||||
unsigned int lc_time = BTN_LONGCLICK_MS + 1;
|
||||
button.setLongClickTime(lc_time);
|
||||
// run the tests
|
||||
assertEqual(button.getLongClickTime(), lc_time);
|
||||
// clean up
|
||||
button.setLongClickTime(BTN_LONGCLICK_MS);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
test(settings, debounce_time) {
|
||||
unsigned int debounce_time = BTN_DEBOUNCE_MS + 1;
|
||||
button.setDebounceTime(debounce_time);
|
||||
// run the tests
|
||||
assertEqual(button.getDebounceTime(), debounce_time);
|
||||
// clean up
|
||||
button.setDebounceTime(BTN_DEBOUNCE_MS);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// OTHER
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
test(other, to_string) {
|
||||
assertStringCaseEqual(button.clickToString(clickType::single_click), String("single click"));
|
||||
assertStringCaseEqual(button.clickToString(clickType::double_click), String("double click"));
|
||||
assertStringCaseEqual(button.clickToString(clickType::triple_click), String("triple click"));
|
||||
assertStringCaseEqual(button.clickToString(clickType::long_click), String("long click"));
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
// ignore unused params in the lamda functions
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wunused-parameter"
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
void setup() {
|
||||
setup_test_runner();
|
||||
|
||||
// setup serial
|
||||
delay(1000);
|
||||
Serial.begin(SERIAL_SPEED);
|
||||
while(!Serial) {}
|
||||
Serial.println(F("\n\nButton2 Unit Tests"));
|
||||
// set up button
|
||||
button.begin(BUTTON_PIN, BUTTON_MODE, BUTTON_ACTIVE == LOW, &hw);
|
||||
|
||||
button.setPressedHandler([](Button2& b) {
|
||||
if (VERBOSE_PRESS_RELEASE) Serial.println(F("-- PRESSED"));
|
||||
released = false;
|
||||
pressed = true;
|
||||
});
|
||||
button.setReleasedHandler([](Button2& b) {
|
||||
if (VERBOSE_PRESS_RELEASE) Serial.println(F("-- RELEASED"));
|
||||
released = true;
|
||||
pressed = false;
|
||||
tap = true;
|
||||
});
|
||||
button.setChangedHandler([](Button2& b) {
|
||||
if (VERBOSE_CHANGED) Serial.println(F("-- CHANGED"));
|
||||
changed = true;
|
||||
});
|
||||
button.setClickHandler([](Button2& b) {
|
||||
if (VERBOSE_MAIN_EVENTS) Serial.println(F(" -- CLICK"));
|
||||
});
|
||||
button.setLongClickHandler([](Button2& b) {
|
||||
if (VERBOSE_MAIN_EVENTS) Serial.println(F(" -- LONG"));
|
||||
longclick = true;
|
||||
});
|
||||
button.setLongClickDetectedHandler([](Button2& b) {
|
||||
if (VERBOSE_MAIN_EVENTS) Serial.println(" -- LONG DETECTED");
|
||||
long_detected = true;
|
||||
long_detected_count = long_detected_count + 1;
|
||||
});
|
||||
button.setDoubleClickHandler([](Button2& b) {
|
||||
if (VERBOSE_MAIN_EVENTS) Serial.println(" -- DOUBLE");
|
||||
});
|
||||
button.setTripleClickHandler([](Button2& b) {
|
||||
if (VERBOSE_MAIN_EVENTS) Serial.println(" -- TRIPLE ");
|
||||
});
|
||||
}
|
||||
#pragma GCC diagnostic push
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
void loop() {
|
||||
button.loop();
|
||||
aunit::TestRunner::run();
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
Loading…
Add table
Add a link
Reference in a new issue