Make ScreenHandler class, fix button handling

This commit is contained in:
Djuri 2024-12-26 23:08:46 +01:00
parent 698c3a3a43
commit 17fef80253
11 changed files with 484 additions and 410 deletions

View file

@ -1,8 +1,7 @@
#include "button_handler.hpp"
TaskHandle_t buttonTaskHandle = NULL;
const TickType_t debounceDelay = pdMS_TO_TICKS(50);
TickType_t lastDebounceTime = 0;
ButtonState buttonStates[4];
#ifdef IS_BTCLOCK_V8
#define BTN_1 256
@ -17,65 +16,134 @@ TickType_t lastDebounceTime = 0;
#endif
void buttonTask(void *parameter) {
while (1) {
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
while (1) {
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
TickType_t currentTime = xTaskGetTickCount();
std::lock_guard<std::mutex> lock(mcpMutex);
if (!digitalRead(MCP_INT_PIN)) {
uint16_t intFlags = mcp1.getInterruptFlagRegister();
uint16_t intCap = mcp1.getInterruptCaptureRegister();
// Check button states
if (intFlags & BTN_1) handleButtonPress(0);
if (intFlags & BTN_2) handleButtonPress(1);
if (intFlags & BTN_3) handleButtonPress(2);
if (intFlags & BTN_4) handleButtonPress(3);
// Check for button releases
for (int i = 0; i < 4; i++) {
if (buttonStates[i].isPressed) {
bool currentlyPressed = false;
switch (i) {
case 0: currentlyPressed = (intCap & BTN_1); break;
case 1: currentlyPressed = (intCap & BTN_2); break;
case 2: currentlyPressed = (intCap & BTN_3); break;
case 3: currentlyPressed = (intCap & BTN_4); break;
}
if (!currentlyPressed) {
handleButtonRelease(i);
}
}
}
// Check for long press on pressed buttons
for (int i = 0; i < 4; i++) {
if (buttonStates[i].isPressed && !buttonStates[i].longPressHandled) {
if ((currentTime - buttonStates[i].pressStartTime) >= longPressDelay) {
handleLongPress(i);
buttonStates[i].longPressHandled = true;
}
}
}
}
// Clear interrupt state
while (!digitalRead(MCP_INT_PIN)) {
mcp1.getInterruptCaptureRegister();
delay(1);
}
}
}
void handleButtonPress(int buttonIndex) {
TickType_t currentTime = xTaskGetTickCount();
ButtonState &state = buttonStates[buttonIndex];
if ((currentTime - lastDebounceTime) >= debounceDelay) {
lastDebounceTime = currentTime;
std::lock_guard<std::mutex> lock(mcpMutex);
if (!digitalRead(MCP_INT_PIN)) {
uint16_t intFlags = mcp1.getInterruptFlagRegister();
uint16_t intCap = mcp1.getInterruptCaptureRegister();
// Check each button individually
if (intFlags & BTN_1) handleButton1();
if (intFlags & BTN_2) handleButton2();
if (intFlags & BTN_3) handleButton3();
if (intFlags & BTN_4) handleButton4();
}
if ((currentTime - state.lastPressTime) >= debounceDelay) {
state.isPressed = true;
state.pressStartTime = currentTime;
state.longPressHandled = false;
// Check for double click
if ((currentTime - state.lastPressTime) <= doubleClickDelay) {
state.clickCount++;
if (state.clickCount == 2) {
handleDoubleClick(buttonIndex);
state.clickCount = 0;
}
} else {
state.clickCount = 1;
}
state.lastPressTime = currentTime;
}
}
void handleButtonRelease(int buttonIndex) {
TickType_t currentTime = xTaskGetTickCount();
ButtonState &state = buttonStates[buttonIndex];
// Clear interrupt state
while (!digitalRead(MCP_INT_PIN)) {
std::lock_guard<std::mutex> lock(mcpMutex);
mcp1.getInterruptCaptureRegister();
delay(1); // Small delay to prevent tight loop
state.isPressed = false;
// If this wasn't a long press or double click, handle as single click
if (!state.longPressHandled && state.clickCount == 1 &&
(currentTime - state.pressStartTime) < longPressDelay) {
handleSingleClick(buttonIndex);
state.clickCount = 0;
}
}
}
// Helper functions to handle each button
void handleButton1() {
toggleTimerActive();
// Button action handlers
void handleSingleClick(int buttonIndex) {
switch (buttonIndex) {
case 0:
toggleTimerActive();
break;
case 1:
Serial.println("Button 2 single click");
ScreenHandler::nextScreen();
break;
case 2:
Serial.println("Button 3 single click");
ScreenHandler::previousScreen();
break;
case 3:
ScreenHandler::showSystemStatusScreen();
break;
}
}
void handleButton2() {
nextScreen();
void handleDoubleClick(int buttonIndex) {
Serial.printf("Button %d double clicked\n", buttonIndex + 1);
}
void handleButton3() {
previousScreen();
}
void handleButton4() {
showSystemStatusScreen();
void handleLongPress(int buttonIndex) {
Serial.printf("Button %d long press detected\n", buttonIndex + 1);
}
void IRAM_ATTR handleButtonInterrupt() {
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
xTaskNotifyFromISR(buttonTaskHandle, 0, eNoAction, &xHigherPriorityTaskWoken);
if (xHigherPriorityTaskWoken == pdTRUE) {
portYIELD_FROM_ISR();
}
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
xTaskNotifyFromISR(buttonTaskHandle, 0, eNoAction, &xHigherPriorityTaskWoken);
if (xHigherPriorityTaskWoken == pdTRUE) {
portYIELD_FROM_ISR();
}
}
void setupButtonTask() {
xTaskCreate(buttonTask, "ButtonTask", 3072, NULL, tskIDLE_PRIORITY,
&buttonTaskHandle); // Create the FreeRTOS task
// Use interrupt instead of task
attachInterrupt(MCP_INT_PIN, handleButtonInterrupt, CHANGE);
xTaskCreate(buttonTask, "ButtonTask", 3072, NULL, tskIDLE_PRIORITY,
&buttonTaskHandle);
attachInterrupt(MCP_INT_PIN, handleButtonInterrupt, FALLING);
}