/** * @file ui_task.c * @brief UI task - button handling and OLED display */ #include #include #include "freertos/FreeRTOS.h" #include "freertos/task.h" #include "freertos/queue.h" #include "esp_log.h" #include "driver/gpio.h" #include "app_main.h" static const char *TAG = "ui"; /* Button debounce parameters */ #define DEBOUNCE_MS 50 #define LONG_PRESS_MS 1000 /* Button state tracking */ typedef struct { uint8_t gpio; uint8_t last_state; uint32_t last_change_ms; uint32_t press_start_ms; uint8_t long_press_sent; } btn_state_t; static btn_state_t buttons[] = { {BTN_UP_GPIO, 1, 0, 0, 0}, {BTN_DOWN_GPIO, 1, 0, 0, 0}, {BTN_SEL_GPIO, 1, 0, 0, 0}, {BTN_BACK_GPIO, 1, 0, 0, 0}, }; static void handle_button(btn_state_t *btn, uint8_t idx) { uint8_t state = gpio_get_level(btn->gpio); uint32_t now = xTaskGetTickCount() * portTICK_PERIOD_MS; if (state != btn->last_state) { btn->last_change_ms = now; btn->last_state = state; if (state == 0) { /* Pressed */ btn->press_start_ms = now; btn->long_press_sent = 0; ui_event_t evt = {.key = idx, .action = 0}; /* press */ if (ui_event_queue) { xQueueSend(ui_event_queue, &evt, 0); } } else { /* Released */ if (!btn->long_press_sent) { ui_event_t evt = {.key = idx, .action = 1}; /* release */ if (ui_event_queue) { xQueueSend(ui_event_queue, &evt, 0); } } } } else if (state == 0 && !btn->long_press_sent) { /* Check for long press */ if ((now - btn->press_start_ms) >= LONG_PRESS_MS) { btn->long_press_sent = 1; ui_event_t evt = {.key = idx, .action = 2}; /* long press */ if (ui_event_queue) { xQueueSend(ui_event_queue, &evt, 0); } } } } void ui_task(void *pvParameters) { ESP_LOGI(TAG, "UI task started"); /* OLED initialization would go here */ /* display_init(); */ /* Button state initialization */ for (int i = 0; i < 4; i++) { buttons[i].last_state = gpio_get_level(buttons[i].gpio); } while (1) { /* Scan buttons */ for (int i = 0; i < 4; i++) { handle_button(&buttons[i], i); } /* Process UI events */ ui_event_t evt; while (xQueueReceive(ui_event_queue, &evt, 0)) { const char *key_names[] = {"UP", "DOWN", "SEL", "BACK"}; const char *actions[] = {"press", "release", "long_press"}; ESP_LOGI(TAG, "Button: %s - %s", key_names[evt.key], actions[evt.action]); } /* Read ADC data for display */ adc_data_t adc_data; if (adc_data_queue && xQueuePeek(adc_data_queue, &adc_data, 0)) { /* Update OLED display with ADC data */ /* display_update(&adc_data); */ } vTaskDelay(pdMS_TO_TICKS(20)); /* 50Hz scan rate */ } }