Merge pull request #3 from open-x4-epaper/feature/input-manager-hold-time
Update InputManager to record any button hold time
This commit is contained in:
commit
8224d278c5
@ -1,5 +1,4 @@
|
||||
#ifndef INPUT_MANAGER_H
|
||||
#define INPUT_MANAGER_H
|
||||
#pragma once
|
||||
|
||||
#include <Arduino.h>
|
||||
|
||||
@ -8,52 +7,100 @@ class InputManager {
|
||||
InputManager();
|
||||
void begin();
|
||||
uint8_t getState();
|
||||
|
||||
/**
|
||||
* Updates the button states. Should be called regularly in the main loop.
|
||||
*/
|
||||
void update();
|
||||
bool isPressed(uint8_t buttonIndex);
|
||||
bool wasPressed(uint8_t buttonIndex);
|
||||
bool wasReleased(uint8_t buttonIndex);
|
||||
|
||||
/**
|
||||
* Returns true if the button was being held at the time of the last #update() call.
|
||||
*
|
||||
* @param buttonIndex the button indexes
|
||||
* @return the button current press state
|
||||
*/
|
||||
bool isPressed(uint8_t buttonIndex) const;
|
||||
|
||||
/**
|
||||
* Returns true if the button went from unpressed to pressed between the last two #update() calls.
|
||||
*
|
||||
* This differs from #isPressed() in that pressing and holding a button will cause this function
|
||||
* to return true after the first #update() call, but false on subsequent calls, whereas #isPressed()
|
||||
* will continue to return true.
|
||||
*
|
||||
* @param buttonIndex
|
||||
* @return the button pressed state
|
||||
*/
|
||||
bool wasPressed(uint8_t buttonIndex) const;
|
||||
|
||||
/**
|
||||
* Returns true if any button started being pressed between the last two #update() calls
|
||||
*
|
||||
* @return true if any button started being pressed between the last two #update() calls
|
||||
*/
|
||||
bool wasAnyPressed() const;
|
||||
|
||||
/**
|
||||
* Returns true if the button went from pressed to unpressed between the last two #update() calls
|
||||
*
|
||||
* @param buttonIndex the button indexes
|
||||
* @return the button release state
|
||||
*/
|
||||
bool wasReleased(uint8_t buttonIndex) const;
|
||||
|
||||
/**
|
||||
* Returns true if any button was released between the last two #update() calls
|
||||
*
|
||||
* @return true if any button was released between the last two #update() calls
|
||||
*/
|
||||
bool wasAnyReleased() const;
|
||||
|
||||
/**
|
||||
* Returns the time between any button starting to be depressed and all buttons between released
|
||||
*
|
||||
* @return duration in milliseconds
|
||||
*/
|
||||
unsigned long getHeldTime() const;
|
||||
|
||||
// Button indices
|
||||
static const uint8_t BTN_BACK = 0;
|
||||
static const uint8_t BTN_CONFIRM = 1;
|
||||
static const uint8_t BTN_LEFT = 2;
|
||||
static const uint8_t BTN_RIGHT = 3;
|
||||
static const uint8_t BTN_UP = 4;
|
||||
static const uint8_t BTN_DOWN = 5;
|
||||
static const uint8_t BTN_POWER = 6;
|
||||
static constexpr uint8_t BTN_BACK = 0;
|
||||
static constexpr uint8_t BTN_CONFIRM = 1;
|
||||
static constexpr uint8_t BTN_LEFT = 2;
|
||||
static constexpr uint8_t BTN_RIGHT = 3;
|
||||
static constexpr uint8_t BTN_UP = 4;
|
||||
static constexpr uint8_t BTN_DOWN = 5;
|
||||
static constexpr uint8_t BTN_POWER = 6;
|
||||
|
||||
// Pins
|
||||
static constexpr int BUTTON_ADC_PIN_1 = 1;
|
||||
static constexpr int BUTTON_ADC_PIN_2 = 2;
|
||||
static constexpr int POWER_BUTTON_PIN = 3;
|
||||
|
||||
// Power button methods
|
||||
bool isPowerButtonPressed();
|
||||
bool isPowerButtonPressed() const;
|
||||
|
||||
// Button names
|
||||
static const char* getButtonName(uint8_t buttonIndex);
|
||||
|
||||
private:
|
||||
int getButtonFromADC(int adcValue, const int thresholds[], int numButtons);
|
||||
int getButtonFromADC(int adcValue, const int ranges[], int numButtons);
|
||||
|
||||
uint8_t currentState;
|
||||
uint8_t lastState;
|
||||
uint8_t pressedEvents;
|
||||
uint8_t releasedEvents;
|
||||
unsigned long lastDebounceTime;
|
||||
unsigned long powerButtonPressStart;
|
||||
bool powerButtonWasPressed;
|
||||
unsigned long buttonPressStart;
|
||||
unsigned long buttonPressFinish;
|
||||
|
||||
static const int BUTTON_ADC_PIN_1 = 1;
|
||||
static const int NUM_BUTTONS_1 = 4;
|
||||
static const int ADC_THRESHOLDS_1[];
|
||||
static constexpr int NUM_BUTTONS_1 = 4;
|
||||
static const int ADC_RANGES_1[];
|
||||
|
||||
static const int POWER_BUTTON_PIN = 3;
|
||||
static constexpr int NUM_BUTTONS_2 = 2;
|
||||
static const int ADC_RANGES_2[];
|
||||
|
||||
static const int BUTTON_ADC_PIN_2 = 2;
|
||||
static const int NUM_BUTTONS_2 = 2;
|
||||
static const int ADC_THRESHOLDS_2[];
|
||||
|
||||
static const int ADC_TOLERANCE = 200;
|
||||
static const int ADC_NO_BUTTON = 3800;
|
||||
static const unsigned long DEBOUNCE_DELAY = 5;
|
||||
static constexpr int ADC_NO_BUTTON = 3800;
|
||||
static constexpr unsigned long DEBOUNCE_DELAY = 5;
|
||||
|
||||
static const char* BUTTON_NAMES[];
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "InputManager",
|
||||
"version": "1.0.0",
|
||||
"version": "1.1.0",
|
||||
"description": "Button inputs",
|
||||
"authors": [
|
||||
{
|
||||
|
||||
@ -1,7 +1,21 @@
|
||||
#include "InputManager.h"
|
||||
|
||||
const int InputManager::ADC_THRESHOLDS_1[] = {3470, 2655, 1470, 3};
|
||||
const int InputManager::ADC_THRESHOLDS_2[] = {2205, 3};
|
||||
// Recorded ADC values from real devices
|
||||
// BACK CONF LEFT RGHT UP DOWN
|
||||
// 3597 2760 1530 6 2300 6
|
||||
// 3470 2666 1480 6 2222 5
|
||||
// 3470 2655 1470 3 2205 3
|
||||
|
||||
// Averages
|
||||
// BACK CONF LEFT RGHT UP DOWN
|
||||
// 3512 2694 1493 5 2242 5
|
||||
|
||||
// Setup ranges, if ADC value is between value `i` and `i + 1`, button `i` is being pressed
|
||||
// These ranges are based on real world values above, and are much more tolerant of different
|
||||
// devices than a fixed threshold check
|
||||
// These values are calculated by taking the midpoint of the pairs of averaged values above
|
||||
const int InputManager::ADC_RANGES_1[] = {ADC_NO_BUTTON, 3100, 2090, 750, INT32_MIN};
|
||||
const int InputManager::ADC_RANGES_2[] = {ADC_NO_BUTTON, 1120, INT32_MIN};
|
||||
const char* InputManager::BUTTON_NAMES[] = {"Back", "Confirm", "Left", "Right", "Up", "Down", "Power"};
|
||||
|
||||
InputManager::InputManager()
|
||||
@ -10,8 +24,8 @@ InputManager::InputManager()
|
||||
pressedEvents(0),
|
||||
releasedEvents(0),
|
||||
lastDebounceTime(0),
|
||||
powerButtonPressStart(0),
|
||||
powerButtonWasPressed(false) {}
|
||||
buttonPressStart(0),
|
||||
buttonPressFinish(0) {}
|
||||
|
||||
void InputManager::begin() {
|
||||
pinMode(BUTTON_ADC_PIN_1, INPUT);
|
||||
@ -20,13 +34,9 @@ void InputManager::begin() {
|
||||
analogSetAttenuation(ADC_11db);
|
||||
}
|
||||
|
||||
int InputManager::getButtonFromADC(int adcValue, const int thresholds[], int numButtons) {
|
||||
if (adcValue > ADC_NO_BUTTON) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
int InputManager::getButtonFromADC(const int adcValue, const int ranges[], const int numButtons) {
|
||||
for (int i = 0; i < numButtons; i++) {
|
||||
if (abs(adcValue - thresholds[i]) < ADC_TOLERANCE) {
|
||||
if (ranges[i + 1] < adcValue && adcValue <= ranges[i]) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
@ -38,15 +48,15 @@ uint8_t InputManager::getState() {
|
||||
uint8_t state = 0;
|
||||
|
||||
// Read GPIO1 buttons
|
||||
int adcValue1 = analogRead(BUTTON_ADC_PIN_1);
|
||||
int button1 = getButtonFromADC(adcValue1, ADC_THRESHOLDS_1, NUM_BUTTONS_1);
|
||||
const int adcValue1 = analogRead(BUTTON_ADC_PIN_1);
|
||||
const int button1 = getButtonFromADC(adcValue1, ADC_RANGES_1, NUM_BUTTONS_1);
|
||||
if (button1 >= 0) {
|
||||
state |= (1 << button1);
|
||||
}
|
||||
|
||||
// Read GPIO2 buttons
|
||||
int adcValue2 = analogRead(BUTTON_ADC_PIN_2);
|
||||
int button2 = getButtonFromADC(adcValue2, ADC_THRESHOLDS_2, NUM_BUTTONS_2);
|
||||
const int adcValue2 = analogRead(BUTTON_ADC_PIN_2);
|
||||
const int button2 = getButtonFromADC(adcValue2, ADC_RANGES_2, NUM_BUTTONS_2);
|
||||
if (button2 >= 0) {
|
||||
state |= (1 << (button2 + 4));
|
||||
}
|
||||
@ -60,8 +70,8 @@ uint8_t InputManager::getState() {
|
||||
}
|
||||
|
||||
void InputManager::update() {
|
||||
unsigned long currentTime = millis();
|
||||
uint8_t state = getState();
|
||||
const unsigned long currentTime = millis();
|
||||
const uint8_t state = getState();
|
||||
|
||||
// Always clear events first
|
||||
pressedEvents = 0;
|
||||
@ -78,39 +88,58 @@ void InputManager::update() {
|
||||
// Calculate pressed and released events
|
||||
pressedEvents = state & ~currentState;
|
||||
releasedEvents = currentState & ~state;
|
||||
currentState = state;
|
||||
|
||||
// Track power button press timing
|
||||
if (pressedEvents & (1 << BTN_POWER)) {
|
||||
powerButtonPressStart = currentTime;
|
||||
powerButtonWasPressed = true;
|
||||
// If pressing buttons and wasn't before, start recording time
|
||||
if (pressedEvents > 0 && currentState == 0) {
|
||||
buttonPressStart = currentTime;
|
||||
}
|
||||
if (releasedEvents & (1 << BTN_POWER)) {
|
||||
powerButtonWasPressed = false;
|
||||
|
||||
// If releasing a button and no other buttons being pressed, record finish time
|
||||
if (releasedEvents > 0 && state == 0) {
|
||||
buttonPressFinish = currentTime;
|
||||
}
|
||||
|
||||
currentState = state;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool InputManager::isPressed(uint8_t buttonIndex) {
|
||||
bool InputManager::isPressed(const uint8_t buttonIndex) const {
|
||||
return currentState & (1 << buttonIndex);
|
||||
}
|
||||
|
||||
bool InputManager::wasPressed(uint8_t buttonIndex) {
|
||||
bool InputManager::wasPressed(const uint8_t buttonIndex) const {
|
||||
return pressedEvents & (1 << buttonIndex);
|
||||
}
|
||||
|
||||
bool InputManager::wasReleased(uint8_t buttonIndex) {
|
||||
bool InputManager::wasAnyPressed() const {
|
||||
return pressedEvents > 0;
|
||||
}
|
||||
|
||||
bool InputManager::wasReleased(const uint8_t buttonIndex) const {
|
||||
return releasedEvents & (1 << buttonIndex);
|
||||
}
|
||||
|
||||
const char* InputManager::getButtonName(uint8_t buttonIndex) {
|
||||
bool InputManager::wasAnyReleased() const {
|
||||
return releasedEvents > 0;
|
||||
}
|
||||
|
||||
unsigned long InputManager::getHeldTime() const {
|
||||
// Still hold a button
|
||||
if (currentState > 0) {
|
||||
return millis() - buttonPressStart;
|
||||
}
|
||||
|
||||
return buttonPressFinish - buttonPressStart;
|
||||
}
|
||||
|
||||
const char* InputManager::getButtonName(const uint8_t buttonIndex) {
|
||||
if (buttonIndex <= BTN_POWER) {
|
||||
return BUTTON_NAMES[buttonIndex];
|
||||
}
|
||||
return "Unknown";
|
||||
}
|
||||
|
||||
bool InputManager::isPowerButtonPressed() {
|
||||
bool InputManager::isPowerButtonPressed() const {
|
||||
return isPressed(BTN_POWER);
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user