mirror of https://github.com/meshcore-dev/MeshCore
committed by
GitHub
5 changed files with 302 additions and 52 deletions
@ -0,0 +1,125 @@ |
|||
#include "Button.h" |
|||
|
|||
Button::Button(uint8_t pin, bool activeState) |
|||
: _pin(pin), _activeState(activeState), _isAnalog(false), _analogThreshold(20) { |
|||
_currentState = false; // Initialize as not pressed
|
|||
_lastState = _currentState; |
|||
} |
|||
|
|||
Button::Button(uint8_t pin, bool activeState, bool isAnalog, uint16_t analogThreshold) |
|||
: _pin(pin), _activeState(activeState), _isAnalog(isAnalog), _analogThreshold(analogThreshold) { |
|||
_currentState = false; // Initialize as not pressed
|
|||
_lastState = _currentState; |
|||
} |
|||
|
|||
void Button::begin() { |
|||
_currentState = readButton(); |
|||
_lastState = _currentState; |
|||
} |
|||
|
|||
void Button::update() { |
|||
uint32_t now = millis(); |
|||
|
|||
// Read button at specified interval
|
|||
if (now - _lastReadTime < BUTTON_READ_INTERVAL_MS) { |
|||
return; |
|||
} |
|||
_lastReadTime = now; |
|||
|
|||
bool newState = readButton(); |
|||
|
|||
// Check if state has changed
|
|||
if (newState != _lastState) { |
|||
_stateChangeTime = now; |
|||
} |
|||
|
|||
// Debounce check
|
|||
if ((now - _stateChangeTime) > BUTTON_DEBOUNCE_TIME_MS) { |
|||
if (newState != _currentState) { |
|||
_currentState = newState; |
|||
handleStateChange(); |
|||
} |
|||
} |
|||
|
|||
_lastState = newState; |
|||
|
|||
// Handle multi-click timeout
|
|||
if (_state == WAITING_FOR_MULTI_CLICK && (now - _releaseTime) > BUTTON_CLICK_TIMEOUT_MS) { |
|||
// Timeout reached, process the clicks
|
|||
if (_clickCount == 1) { |
|||
triggerEvent(SHORT_PRESS); |
|||
} else if (_clickCount == 2) { |
|||
triggerEvent(DOUBLE_PRESS); |
|||
} else if (_clickCount >= 3) { |
|||
triggerEvent(TRIPLE_PRESS); |
|||
} |
|||
_clickCount = 0; |
|||
_state = IDLE; |
|||
} |
|||
|
|||
// Handle long press while button is held
|
|||
if (_state == PRESSED && (now - _pressTime) > BUTTON_LONG_PRESS_TIME_MS) { |
|||
triggerEvent(LONG_PRESS); |
|||
_state = IDLE; // Prevent multiple press events
|
|||
_clickCount = 0; |
|||
} |
|||
} |
|||
|
|||
bool Button::readButton() { |
|||
if (_isAnalog) { |
|||
return (analogRead(_pin) < _analogThreshold); |
|||
} else { |
|||
return (digitalRead(_pin) == _activeState); |
|||
} |
|||
} |
|||
|
|||
void Button::handleStateChange() { |
|||
uint32_t now = millis(); |
|||
|
|||
if (_currentState) { |
|||
// Button pressed
|
|||
_pressTime = now; |
|||
_state = PRESSED; |
|||
triggerEvent(ANY_PRESS); |
|||
} else { |
|||
// Button released
|
|||
if (_state == PRESSED) { |
|||
uint32_t pressDuration = now - _pressTime; |
|||
|
|||
if (pressDuration < BUTTON_LONG_PRESS_TIME_MS) { |
|||
// Short press detected
|
|||
_clickCount++; |
|||
_releaseTime = now; |
|||
_state = WAITING_FOR_MULTI_CLICK; |
|||
} else { |
|||
// Long press already handled in update()
|
|||
_state = IDLE; |
|||
_clickCount = 0; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
void Button::triggerEvent(EventType event) { |
|||
_lastEvent = event; |
|||
|
|||
switch (event) { |
|||
case ANY_PRESS: |
|||
if (_onAnyPress) _onAnyPress(); |
|||
break; |
|||
case SHORT_PRESS: |
|||
if (_onShortPress) _onShortPress(); |
|||
break; |
|||
case DOUBLE_PRESS: |
|||
if (_onDoublePress) _onDoublePress(); |
|||
break; |
|||
case TRIPLE_PRESS: |
|||
if (_onTriplePress) _onTriplePress(); |
|||
break; |
|||
case LONG_PRESS: |
|||
if (_onLongPress) _onLongPress(); |
|||
break; |
|||
default: |
|||
break; |
|||
} |
|||
} |
|||
@ -0,0 +1,77 @@ |
|||
#pragma once |
|||
|
|||
#include <Arduino.h> |
|||
#include <functional> |
|||
|
|||
// Button timing configuration
|
|||
#define BUTTON_DEBOUNCE_TIME_MS 50 // Debounce time in ms
|
|||
#define BUTTON_CLICK_TIMEOUT_MS 500 // Max time between clicks for multi-click
|
|||
#define BUTTON_LONG_PRESS_TIME_MS 3000 // Time to trigger long press (3 seconds)
|
|||
#define BUTTON_READ_INTERVAL_MS 10 // How often to read the button
|
|||
|
|||
class Button { |
|||
public: |
|||
enum EventType { |
|||
NONE, |
|||
SHORT_PRESS, |
|||
DOUBLE_PRESS, |
|||
TRIPLE_PRESS, |
|||
LONG_PRESS, |
|||
ANY_PRESS |
|||
}; |
|||
|
|||
using EventCallback = std::function<void()>; |
|||
|
|||
Button(uint8_t pin, bool activeState = LOW); |
|||
Button(uint8_t pin, bool activeState, bool isAnalog, uint16_t analogThreshold = 20); |
|||
|
|||
void begin(); |
|||
void update(); |
|||
|
|||
// Set callbacks for different events
|
|||
void onShortPress(EventCallback callback) { _onShortPress = callback; } |
|||
void onDoublePress(EventCallback callback) { _onDoublePress = callback; } |
|||
void onTriplePress(EventCallback callback) { _onTriplePress = callback; } |
|||
void onLongPress(EventCallback callback) { _onLongPress = callback; } |
|||
void onAnyPress(EventCallback callback) { _onAnyPress = callback; } |
|||
|
|||
// State getters
|
|||
bool isPressed() const { return _currentState; } |
|||
EventType getLastEvent() const { return _lastEvent; } |
|||
|
|||
private: |
|||
enum State { |
|||
IDLE, |
|||
PRESSED, |
|||
RELEASED, |
|||
WAITING_FOR_MULTI_CLICK |
|||
}; |
|||
|
|||
uint8_t _pin; |
|||
bool _activeState; |
|||
bool _isAnalog; |
|||
uint16_t _analogThreshold; |
|||
|
|||
State _state = IDLE; |
|||
bool _currentState; |
|||
bool _lastState; |
|||
|
|||
uint32_t _stateChangeTime = 0; |
|||
uint32_t _pressTime = 0; |
|||
uint32_t _releaseTime = 0; |
|||
uint32_t _lastReadTime = 0; |
|||
|
|||
uint8_t _clickCount = 0; |
|||
EventType _lastEvent = NONE; |
|||
|
|||
// Callbacks
|
|||
EventCallback _onShortPress = nullptr; |
|||
EventCallback _onDoublePress = nullptr; |
|||
EventCallback _onTriplePress = nullptr; |
|||
EventCallback _onLongPress = nullptr; |
|||
EventCallback _onAnyPress = nullptr; |
|||
|
|||
bool readButton(); |
|||
void handleStateChange(); |
|||
void triggerEvent(EventType event); |
|||
}; |
|||
Loading…
Reference in new issue