diff --git a/src/LilyGo_Button.cpp b/src/LilyGo_Button.cpp new file mode 100644 index 0000000..54d12c8 --- /dev/null +++ b/src/LilyGo_Button.cpp @@ -0,0 +1,111 @@ +/** + * @file LilyGo_Button.cpp + * @author Lewis He (lewishe@outlook.com) + * @license MIT + * @copyright Copyright (c) 2023 Shenzhen Xinyuan Electronic Technology Co., Ltd + * @date 2023-10-21 + * + */ +#include "LilyGo_Button.h" + +void LilyGo_Button::init(uint32_t gpio, uint32_t debounceTimeout ) +{ + this->gpio = gpio; + setDebounceTime(debounceTimeout); +} + + +void LilyGo_Button::setDebounceTime(uint32_t ms) +{ + debounce_time_ms = ms; +} + +void LilyGo_Button::setEventCallback(event_callback func) +{ + event_cb = func; +} + +uint32_t LilyGo_Button::wasPressedFor() +{ + return down_time_ms; +} + +uint32_t LilyGo_Button::getNumberOfClicks() +{ + return click_count; +} + + +uint32_t LilyGo_Button::getClickType() +{ + return last_click_type; +} + + +void LilyGo_Button::update() +{ + prev_state = curr_state; + + curr_state = touchInterruptGetLastStatus(gpio) == 0; + + if (prev_state == HIGH && curr_state == LOW) { + down_ms = millis(); + pressed_triggered = false; + click_count++; + click_ms = down_ms; + } else if (prev_state == LOW && curr_state == HIGH) { + down_time_ms = millis() - down_ms; + if (down_time_ms >= debounce_time_ms) { + if (event_cb) { + this->event_cb(BTN_RELEASED_EVENT); + } + if (down_time_ms >= LONGCLICK_MS) { + longclick_detected = true; + } + } + } else if (curr_state == LOW && !pressed_triggered && (millis() - down_ms >= debounce_time_ms && !long_pressed_detected)) { + long_down_ms = millis(); + if (event_cb) { + this->event_cb(BTN_PRESSED_EVENT); + } + pressed_triggered = true; + } else if (pressed_triggered && ((millis() - long_down_ms) > LONGPRESS_MS) && !long_pressed_detected) { + if (event_cb) { + this->event_cb(BTN_LONG_PRESSED_EVENT); + } + pressed_triggered = false; + long_pressed_detected = true; + } else if (curr_state == HIGH && millis() - click_ms > DOUBLECLICK_MS) { + if (long_pressed_detected) { + long_pressed_detected = false; + last_click_type = LONG_PRESS; + click_count = 0; + } + if (click_count > 0) { + long_down_ms = 0; + pressed_triggered = false; + switch (click_count) { + case 1: + last_click_type = SINGLE_CLICK; + if (event_cb) { + this->event_cb(BTN_CLICK_EVENT); + } + break; + case 2: + last_click_type = DOUBLE_CLICK; + if (event_cb) { + this->event_cb(BTN_DOUBLE_CLICK_EVENT); + } + break; + case 3: + last_click_type = TRIPLE_CLICK; + if (event_cb) { + this->event_cb(BTN_TRIPLE_CLICK_EVENT); + } + break; + } + } + click_count = 0; + click_ms = 0; + } +} diff --git a/src/LilyGo_Button.h b/src/LilyGo_Button.h new file mode 100644 index 0000000..630e7f2 --- /dev/null +++ b/src/LilyGo_Button.h @@ -0,0 +1,61 @@ +/** + * @file LilyGo_Button.h + * @author Lewis He (lewishe@outlook.com) + * @license MIT + * @copyright Copyright (c) 2023 Shenzhen Xinyuan Electronic Technology Co., Ltd + * @date 2023-10-21 + * + */ + +#pragma once + + +#include + + +#define DEBOUNCE_MS (50) +#define LONGCLICK_MS (250) +#define DOUBLECLICK_MS (400) +#define LONGPRESS_MS (1200) +#define SINGLE_CLICK (1) +#define DOUBLE_CLICK (2) +#define TRIPLE_CLICK (3) +#define LONG_PRESS (4) + +enum ButtonState { + BTN_PRESSED_EVENT, + BTN_RELEASED_EVENT, + BTN_CLICK_EVENT, + BTN_LONG_PRESSED_EVENT, + BTN_DOUBLE_CLICK_EVENT, + BTN_TRIPLE_CLICK_EVENT, +}; + +class LilyGo_Button +{ + typedef void (*event_callback) (ButtonState state); +public: + + void init(uint32_t gpio, uint32_t debounceTimeout = DEBOUNCE_MS); + void setDebounceTime(uint32_t ms); + void setEventCallback(event_callback f); + void update(); + uint32_t wasPressedFor(); + uint32_t getNumberOfClicks(); + uint32_t getClickType(); +private: + uint32_t gpio; + int prev_state; + int curr_state = HIGH; + uint8_t click_count = 0; + uint32_t last_click_type = 0; + uint64_t click_ms; + uint64_t down_ms; + uint64_t long_down_ms = 0; + uint32_t debounce_time_ms = DOUBLECLICK_MS; + uint32_t down_time_ms = 0; + bool pressed_triggered = false; + bool longclick_detected = false; + bool long_pressed_detected = false; + event_callback event_cb = NULL; +}; diff --git a/src/LilyGo_Wristband.cpp b/src/LilyGo_Wristband.cpp index 689b723..7b9d0b5 100644 --- a/src/LilyGo_Wristband.cpp +++ b/src/LilyGo_Wristband.cpp @@ -267,6 +267,8 @@ bool LilyGo_Wristband::begin() // Initialize touch button touchAttachInterrupt(BOARD_TOUCH_BUTTON, touchISR, threshold); + LilyGo_Button::init(BOARD_TOUCH_BUTTON); + // Initialize vibration motor #if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5,0,0) ledcAttach(BOARD_VIBRATION_PIN, 1000, 8); @@ -306,6 +308,12 @@ bool LilyGo_Wristband::begin() return true; } +void LilyGo_Wristband::update() +{ + SensorBHI260AP::update(); + LilyGo_Button::update(); +} + void LilyGo_Wristband::setBrightness(uint8_t level) { lcd_cmd_t t = {0x51, {level}, 1}; diff --git a/src/LilyGo_Wristband.h b/src/LilyGo_Wristband.h index b9cc5ed..8a819b8 100644 --- a/src/LilyGo_Wristband.h +++ b/src/LilyGo_Wristband.h @@ -15,6 +15,7 @@ #include #include #include "LilyGo_Display.h" +#include "LilyGo_Button.h" #define BOARD_NONE_PIN (-1) @@ -49,13 +50,17 @@ class LilyGo_Wristband : public LilyGo_Display, public SensorPCF85063, - public SensorBHI260AP + public SensorBHI260AP, + public LilyGo_Button { public: LilyGo_Wristband(); ~LilyGo_Wristband(); bool begin(); + + void update(); + void setTouchThreshold(uint32_t threshold); void detachTouch(); bool getTouched();