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