Baji_Rtc_Toy_Key/main/dzbj/dzbj_button.c
Rdzleo 3a05c3c7d5 双模设备电子吧唧按键功能完整实现 + BLE设备间图片传输 + 模式切换防护
1、按键驱动重构:dzbj_button改为iot_button组件,支持BOOT/KEY2单击/双击/长按,回调通过xTaskCreate派发避免阻塞esp_timer;
2、新增按键导航管理器(key_nav):9种上下文状态机,统一分发按键事件到对应界面;
3、BLE改造:广播默认关闭由按键触发启停,新增设备间GATT Client图片传输(扫描→连接→MTU协商→分包发送),WRITE_EVT区分APP/设备传图跳转不同界面;
4、新增模式切换按键抑制:NVS标志+2秒时间窗,防止AI↔吧唧切换时幽灵按键触发配网或白屏;
5、AI模式BOOT单击回调添加抑制检查,吧唧模式key_nav_boot_click同步添加;
6、新增6个UI界面:配对(Peiwang)、更新(Update)、发送等待/接收等待/发送中/接收中;
7、新增电池指示器组件(battery_ui):多界面真实电量显示+3秒渐隐;
8、Home/Img界面重构:移除触摸手势事件,改为airhub背景+按键导航;
9、禁用触摸(DZBJ_ENABLE_TOUCH=0),保留代码可恢复;
10、sleep_mgr简化:按键唤醒由key_nav统一处理;

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-26 17:44:46 +08:00

159 lines
5.0 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// 按键驱动模块
// BOOT(GPIO0)由board类的iot_button处理单击/双击/长按3秒模式切换
// key_nav的1200ms长按通过iot_button_register_event_cb自定义阈值注册
// KEY2(GPIO4)由本模块的iot_button处理单击/双击/长按1200ms
#include "dzbj_button.h"
#include "key_nav.h"
#include "device_mode.h"
#include "iot_button.h"
#include "driver/gpio.h"
#include "esp_log.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
static const char *TAG = "DZBJ_BTN";
// KEY2 按键句柄
static button_handle_t key2_handle = NULL;
// === KEY2 回调esp_timer中执行派发到独立任务 ===
static void key2_click_task(void *arg) {
key_nav_key2_click();
vTaskDelete(NULL);
}
static void key2_double_click_task(void *arg) {
key_nav_key2_double_click();
vTaskDelete(NULL);
}
static void key2_long_press_task(void *arg) {
key_nav_key2_long_press();
vTaskDelete(NULL);
}
static void key2_click_cb(void *handle, void *data) {
xTaskCreate(key2_click_task, "nav_kc", 3072, NULL, 5, NULL);
}
static void key2_double_click_cb(void *handle, void *data) {
xTaskCreate(key2_double_click_task, "nav_kd", 3072, NULL, 5, NULL);
}
static void key2_long_press_cb(void *handle, void *data) {
xTaskCreate(key2_long_press_task, "nav_kl", 3072, NULL, 5, NULL);
}
esp_err_t dzbj_button_init(void)
{
// KEY2 按键配置iot_button_create 旧版API
button_config_t key2_cfg = {
.type = BUTTON_TYPE_GPIO,
.long_press_time = 1200, // 长按阈值1.2秒
.short_press_time = 300, // 双击检测窗口300ms
.gpio_button_config = {
.gpio_num = PIN_BTN_KEY2,
.active_level = 0, // 低电平有效
},
};
key2_handle = iot_button_create(&key2_cfg);
if (!key2_handle) {
ESP_LOGE(TAG, "KEY2按键创建失败");
return ESP_FAIL;
}
// 注册KEY2事件回调4参数版本
iot_button_register_cb(key2_handle, BUTTON_SINGLE_CLICK, key2_click_cb, NULL);
iot_button_register_cb(key2_handle, BUTTON_DOUBLE_CLICK, key2_double_click_cb, NULL);
iot_button_register_cb(key2_handle, BUTTON_LONG_PRESS_START, key2_long_press_cb, NULL);
ESP_LOGI(TAG, "按键初始化完成 (KEY2=GPIO%d, 长按1200ms, 双击300ms)", PIN_BTN_KEY2);
return ESP_OK;
}
// === BOOT 1200ms 长按注册由board类调用传入boot_button的iot_button句柄 ===
static void boot_long_press_1200_task(void *arg) {
key_nav_boot_long_press();
vTaskDelete(NULL);
}
static void boot_long_press_1200_cb(void *handle, void *data) {
xTaskCreate(boot_long_press_1200_task, "nav_bl", 3072, NULL, 5, NULL);
}
void dzbj_button_register_boot_long_press(void *boot_handle)
{
if (!boot_handle) return;
// 注册1200ms自定义长按事件不影响board类的3000ms模式切换
button_event_config_t evt_cfg = {
.event = BUTTON_LONG_PRESS_START,
.event_data = {
.long_press = {
.press_time = 1200,
},
},
};
esp_err_t ret = iot_button_register_event_cb((button_handle_t)boot_handle, evt_cfg, boot_long_press_1200_cb, NULL);
if (ret == ESP_OK) {
ESP_LOGI(TAG, "BOOT 1200ms长按事件注册成功");
} else {
ESP_LOGE(TAG, "BOOT 1200ms长按事件注册失败: %s", esp_err_to_name(ret));
}
}
// === BOOT+KEY2 组合键模式切换BOOT 2000ms长按时检测KEY2 ===
// === BOOT+KEY2 组合键模式切换BOOT 2000ms长按时检测KEY2 ===
static void mode_switch_task(void *arg) {
ESP_LOGI(TAG, "执行模式切换...");
if (device_mode_is_badge()) {
ESP_LOGI(TAG, "吧唧模式 → AI模式");
device_mode_set(DEVICE_MODE_AI);
} else {
ESP_LOGI(TAG, "AI模式 → 吧唧模式");
device_mode_set(DEVICE_MODE_BADGE);
}
// device_mode_set 内部会 esp_restart不会执行到这里
vTaskDelete(NULL);
}
static void mode_switch_combo_cb(void *handle, void *data) {
// esp_timer中执行检测KEY2是否同时按下
if (gpio_get_level(PIN_BTN_KEY2) == 0) {
ESP_LOGI(TAG, "BOOT+KEY2组合键2秒触发模式切换");
xTaskCreate(mode_switch_task, "mode_sw", 2048, NULL, 5, NULL);
}
}
void dzbj_button_register_mode_switch_combo(void *boot_handle)
{
if (!boot_handle) return;
// 注册2000ms自定义长按事件用于组合键检测
button_event_config_t evt_cfg = {
.event = BUTTON_LONG_PRESS_START,
.event_data = {
.long_press = {
.press_time = 2000,
},
},
};
esp_err_t ret = iot_button_register_event_cb((button_handle_t)boot_handle, evt_cfg, mode_switch_combo_cb, NULL);
if (ret == ESP_OK) {
ESP_LOGI(TAG, "BOOT+KEY2组合键模式切换注册成功(2000ms)");
} else {
ESP_LOGE(TAG, "组合键注册失败: %s", esp_err_to_name(ret));
}
}
// 吧唧模式 BOOT 单击处理转发到key_nav统一处理
void dzbj_boot_click_handler(void)
{
key_nav_boot_click();
}