Initial Demo OS
This commit is contained in:
@@ -0,0 +1,13 @@
|
||||
idf_component_register(
|
||||
SRCS
|
||||
"sys_input.c"
|
||||
INCLUDE_DIRS
|
||||
"include"
|
||||
REQUIRES
|
||||
sys_core
|
||||
driver
|
||||
esp_driver_gpio
|
||||
freertos
|
||||
esp_timer
|
||||
log
|
||||
)
|
||||
@@ -0,0 +1,31 @@
|
||||
#ifndef OS_INPUT_H
|
||||
#define OS_INPUT_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "driver/gpio.h"
|
||||
#include "esp_err.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef enum {
|
||||
INPUT_ACTION_NONE = 0,
|
||||
INPUT_ACTION_CLICK, /* Short press (Next / Step / Advance) */
|
||||
INPUT_ACTION_DOUBLE_CLICK,/* Double click (Back / Cancel) */
|
||||
INPUT_ACTION_LONG_PRESS, /* Hold > 400ms (Select / Confirm / Open) */
|
||||
INPUT_ACTION_HOLD_HOME, /* Hold > 1500ms (Return to App Launcher) */
|
||||
} input_action_t;
|
||||
|
||||
typedef void (*sys_input_handler_t)(input_action_t action, void *user_arg);
|
||||
|
||||
esp_err_t sys_input_init(gpio_num_t button_gpio);
|
||||
esp_err_t sys_input_register_handler(sys_input_handler_t handler, void *user_arg);
|
||||
void sys_input_inject(input_action_t action);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // OS_INPUT_H
|
||||
@@ -0,0 +1,147 @@
|
||||
#include "os_input.h"
|
||||
#include "os_event.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_timer.h"
|
||||
|
||||
static const char *TAG = "SYS_INPUT";
|
||||
|
||||
#define DEBOUNCE_TIME_MS 25
|
||||
#define CLICK_TIME_MAX_MS 350
|
||||
#define DOUBLE_CLICK_GAP_MS 280
|
||||
#define LONG_PRESS_TIME_MS 450
|
||||
#define HOME_PRESS_TIME_MS 1500
|
||||
|
||||
typedef struct {
|
||||
sys_input_handler_t handler;
|
||||
void *user_arg;
|
||||
} input_listener_t;
|
||||
|
||||
#define MAX_INPUT_LISTENERS 8
|
||||
static input_listener_t s_listeners[MAX_INPUT_LISTENERS];
|
||||
static size_t s_listener_count = 0;
|
||||
static gpio_num_t s_button_pin = GPIO_NUM_9;
|
||||
|
||||
static void dispatch_action(input_action_t action)
|
||||
{
|
||||
sys_event_id_t evt_id = SYS_EVENT_CUSTOM;
|
||||
switch (action) {
|
||||
case INPUT_ACTION_CLICK:
|
||||
evt_id = SYS_EVENT_INPUT_SHORT_PRESS;
|
||||
break;
|
||||
case INPUT_ACTION_DOUBLE_CLICK:
|
||||
evt_id = SYS_EVENT_INPUT_DOUBLE_CLICK;
|
||||
break;
|
||||
case INPUT_ACTION_LONG_PRESS:
|
||||
evt_id = SYS_EVENT_INPUT_LONG_PRESS;
|
||||
break;
|
||||
case INPUT_ACTION_HOLD_HOME:
|
||||
evt_id = SYS_EVENT_INPUT_EXTRA_LONG_PRESS;
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
sys_event_post(evt_id, (int32_t)action, NULL);
|
||||
|
||||
for (size_t i = 0; i < s_listener_count; i++) {
|
||||
if (s_listeners[i].handler) {
|
||||
s_listeners[i].handler(action, s_listeners[i].user_arg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void sys_input_inject(input_action_t action)
|
||||
{
|
||||
dispatch_action(action);
|
||||
}
|
||||
|
||||
esp_err_t sys_input_register_handler(sys_input_handler_t handler, void *user_arg)
|
||||
{
|
||||
if (!handler) return ESP_ERR_INVALID_ARG;
|
||||
if (s_listener_count >= MAX_INPUT_LISTENERS) return ESP_ERR_NO_MEM;
|
||||
s_listeners[s_listener_count].handler = handler;
|
||||
s_listeners[s_listener_count].user_arg = user_arg;
|
||||
s_listener_count++;
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static void button_scanner_task(void *pvParameters)
|
||||
{
|
||||
bool last_state = true;
|
||||
uint32_t press_start_ms = 0;
|
||||
uint32_t release_time_ms = 0;
|
||||
uint8_t click_count = 0;
|
||||
bool long_press_fired = false;
|
||||
bool home_press_fired = false;
|
||||
|
||||
while (1) {
|
||||
vTaskDelay(pdMS_TO_TICKS(10));
|
||||
uint32_t now_ms = (uint32_t)(esp_timer_get_time() / 1000ULL);
|
||||
bool current_state = (gpio_get_level(s_button_pin) == 0);
|
||||
|
||||
if (current_state && !last_state) {
|
||||
press_start_ms = now_ms;
|
||||
long_press_fired = false;
|
||||
home_press_fired = false;
|
||||
} else if (current_state && last_state) {
|
||||
uint32_t held_duration = now_ms - press_start_ms;
|
||||
if (!home_press_fired && held_duration >= HOME_PRESS_TIME_MS) {
|
||||
home_press_fired = true;
|
||||
click_count = 0;
|
||||
dispatch_action(INPUT_ACTION_HOLD_HOME);
|
||||
} else if (!long_press_fired && !home_press_fired && held_duration >= LONG_PRESS_TIME_MS) {
|
||||
long_press_fired = true;
|
||||
click_count = 0;
|
||||
dispatch_action(INPUT_ACTION_LONG_PRESS);
|
||||
}
|
||||
} else if (!current_state && last_state) {
|
||||
uint32_t press_duration = now_ms - press_start_ms;
|
||||
if (press_duration >= DEBOUNCE_TIME_MS && !long_press_fired && !home_press_fired) {
|
||||
click_count++;
|
||||
release_time_ms = now_ms;
|
||||
}
|
||||
} else if (!current_state && !last_state) {
|
||||
if (click_count > 0) {
|
||||
uint32_t idle_time = now_ms - release_time_ms;
|
||||
if (click_count >= 2) {
|
||||
dispatch_action(INPUT_ACTION_DOUBLE_CLICK);
|
||||
click_count = 0;
|
||||
} else if (idle_time >= DOUBLE_CLICK_GAP_MS) {
|
||||
dispatch_action(INPUT_ACTION_CLICK);
|
||||
click_count = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
last_state = current_state;
|
||||
}
|
||||
}
|
||||
|
||||
esp_err_t sys_input_init(gpio_num_t button_gpio)
|
||||
{
|
||||
s_button_pin = button_gpio;
|
||||
|
||||
gpio_config_t io_conf = {
|
||||
.pin_bit_mask = (1ULL << s_button_pin),
|
||||
.mode = GPIO_MODE_INPUT,
|
||||
.pull_up_en = GPIO_PULLUP_ENABLE,
|
||||
.pull_down_en = GPIO_PULLDOWN_DISABLE,
|
||||
.intr_type = GPIO_INTR_DISABLE,
|
||||
};
|
||||
esp_err_t err = gpio_config(&io_conf);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to configure button GPIO %d: %s", (int)s_button_pin, esp_err_to_name(err));
|
||||
return err;
|
||||
}
|
||||
|
||||
BaseType_t ret = xTaskCreate(button_scanner_task, "btn_scan_task", 3072, NULL, 12, NULL);
|
||||
if (ret != pdPASS) {
|
||||
ESP_LOGE(TAG, "Failed to create button scanner task");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "Input gesture engine started on GPIO %d", (int)s_button_pin);
|
||||
return ESP_OK;
|
||||
}
|
||||
Reference in New Issue
Block a user