Baji_Rtc_Toy/main/dzbj/sleep_mgr.c
Rdzleo 0735d45e52 feat: 从按键版迁移APP传图、设备间图片分享/接收、组合键模式切换功能
## 功能迁移清单(从 Dzbj_ESP32_S3_Key → Baji_Rtc_Toy)

### 1. 设备间BLE图片传输(GATT Client + 协议)
- 新增 ble_transfer.c/h:发送方 GATT Client 扫描→连接→MTU协商→分包写入
- 接收方复用现有 GATT Server(IMAGE_WRITE 0x0B01),协议完全兼容
- 发送完成/失败自动跳转 Img 界面并关闭蓝牙

### 2. APP传图显示 Update 界面
- 新增 ui_ScreenUpdate.c/h:更新进度界面(Gengxin背景 + Update_GIF动画)
- dzbj_ble.c WRITE_EVT 中通过 ble_transfer_is_receiving() 区分 APP传图 vs 设备间传输
- APP传图 → ScreenUpdate,设备间传输 → ScreenReceiving

### 3. KEY2 按键功能入口(iot_button 单击/双击/长按)
- KEY2 单击:开蓝牙 → Peiwang 配对界面(APP传图)
- KEY2 双击:接收模式 → ScreenImageReception(等待配对)
- KEY2 长按:发送模式 → ScreenImageShar(等待配对)
- 按键参数与按键版对齐:long_press_time=1200ms, short_press_time=300ms

### 4. BOOT+KEY2 组合键模式切换(替代 BOOT 长按3秒)
- BOOT 2秒长按 + KEY2 同时按下 → 触发模式切换
- 消除单键长按的误触发问题
- AI模式和吧唧模式均注册组合键

### 5. 按键上下文状态机
- btn_context_t 枚举:HOME/IMG/SET/PEIWANG/IMAGE_SHAR/IMAGE_RECEPTION/SHARING/RECEIVING/UPDATE
- 所有界面切换点(手势/按键/BLE自动跳转)同步设置 context
- BOOT 单击按 context 分发:Home无操作、Img/Set返回Home、配对退出蓝牙、传输等待取消

### 6. 新增 UI 界面(6个Screen + 7张图片)
- ScreenPeiwang:蓝牙配对等待
- ScreenUpdate:APP传图更新中
- ScreenImageShar:发送方等待配对
- ScreenImageReception:接收方等待配对
- ScreenSharing:发送方传输中
- ScreenReceiving:接收方接收中

### 7. 其他适配
- BLE 广播改为按需启动(dzbj_ble_start/stop/is_active)
- sleep_mgr 移除 KEY2 唤醒(仅 BOOT 唤醒屏幕)
- device_mode 新增模式切换按键抑制(防止重启后立即触发)
- battery_ui 电池指示器组件
- sdkconfig 启用 BLE GATTC 支持

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-27 10:55:17 +08:00

223 lines
6.9 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.

#include "../sleep_mgr/include/sleep_mgr.h"
#include "dzbj_button.h"
#include "pages.h"
#include "pages_pwm.h"
#include "esp_log.h"
#include "esp_timer.h"
#include "esp_lvgl_port.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "lvgl.h"
#include "../ui/screens/ui_ScreenSet.h"
#include "lcd.h"
#include <stdio.h>
static const char *TAG = "SLEEP";
static bool sleep_enabled = false;
static bool screen_off = false;
static int64_t last_activity_us = 0;
static uint8_t saved_brightness = 50;
static const uint8_t DEFAULT_BRIGHTNESS = 50; // 默认亮度
static const uint8_t SLEEP_MODE_BRIGHTNESS = 10; // 休眠模式亮度
// 通知有用户活动
void sleep_mgr_notify_activity(void)
{
last_activity_us = esp_timer_get_time();
// 如果屏幕已关闭,立即唤醒
if (screen_off) {
screen_off = false;
// 恢复 LVGL 和触摸输入
if (lvgl_port_lock(100)) {
// 1. 启用所有输入设备(恢复触摸事件处理)
lv_indev_t *indev = lv_indev_get_next(NULL);
while (indev) {
lv_indev_enable(indev, true);
ESP_LOGI(TAG, "输入设备已启用");
indev = lv_indev_get_next(indev);
}
// 2. 恢复刷新定时器(恢复屏幕重绘)
lv_timer_t *refr_timer = _lv_disp_get_refr_timer(NULL);
if (refr_timer) {
lv_timer_resume(refr_timer);
ESP_LOGI(TAG, "LVGL 刷新定时器已恢复");
}
// 3. 强制刷新当前屏幕因为GRAM被清空为黑色需要重绘
lv_obj_invalidate(lv_scr_act());
ESP_LOGI(TAG, "已标记屏幕需要重绘");
lvgl_port_unlock();
}
// 延迟50ms等待LVGL完成至少一次重绘避免看到黑屏
vTaskDelay(pdMS_TO_TICKS(50));
// 恢复背光
pwm_set_brightness(saved_brightness);
ESP_LOGI(TAG, "屏幕唤醒,恢复亮度%d%%", saved_brightness);
}
}
// 关闭屏幕(熄屏进入低功耗)
static void screen_turn_off(void)
{
if (screen_off) return;
// 保存当前亮度
saved_brightness = pwm_get_brightness();
if (saved_brightness == 0) {
saved_brightness = 50; // 防止保存到0值
}
// 暂停 LVGL 并禁用触摸输入
if (lvgl_port_lock(100)) {
// 1. 暂停刷新定时器(停止屏幕重绘)
lv_timer_t *refr_timer = _lv_disp_get_refr_timer(NULL);
if (refr_timer) {
lv_timer_pause(refr_timer);
ESP_LOGI(TAG, "LVGL 刷新定时器已暂停");
}
// 2. 禁用所有输入设备(停止触摸事件处理)
lv_indev_t *indev = lv_indev_get_next(NULL);
while (indev) {
lv_indev_enable(indev, false);
ESP_LOGI(TAG, "输入设备已禁用");
indev = lv_indev_get_next(indev);
}
lvgl_port_unlock();
}
// 清空LCD GRAM为黑色避免关闭背光后看到残影
lcd_clear_screen_black();
// 关闭背光
screen_off = true;
pwm_set_brightness(0);
ESP_LOGI(TAG, "屏幕已关闭(亮度=%d%%系统进入真正低功耗模式Light Sleep + LVGL暂停 + LCD GRAM清空", saved_brightness);
}
// 休眠管理任务
static void sleep_mgr_task(void *pvParameters)
{
while (1) {
uint32_t delay_ms = 500; // 默认轮询间隔 500ms
if (sleep_enabled) {
// 检查LVGL触摸活动屏幕开启时
if (!screen_off) {
if (lvgl_port_lock(50)) {
uint32_t inactive_ms = lv_disp_get_inactive_time(NULL);
lvgl_port_unlock();
// 屏幕开启状态:检测到新触摸(< 500ms立即更新活动时间
if (inactive_ms < 500) {
sleep_mgr_notify_activity();
}
}
// 检查超时熄屏
int64_t now = esp_timer_get_time();
int64_t elapsed_ms = (now - last_activity_us) / 1000;
if (elapsed_ms >= SLEEP_TIMEOUT_MS) {
screen_turn_off();
}
}
// 屏幕关闭状态:禁用触摸唤醒,只允许按键唤醒
// 如需启用触摸唤醒,取消注释以下代码:
/*
else {
if (lvgl_port_lock(50)) {
uint32_t inactive_ms = lv_disp_get_inactive_time(NULL);
lvgl_port_unlock();
// 检测到触摸(< 2000ms立即唤醒
if (inactive_ms < 2000) {
sleep_mgr_notify_activity();
ESP_LOGI(TAG, "触摸唤醒屏幕inactive=%lums", inactive_ms);
}
}
}
*/
}
vTaskDelay(pdMS_TO_TICKS(delay_ms));
}
}
void sleep_mgr_init(void)
{
last_activity_us = esp_timer_get_time();
// BOOT按键唤醒由dzbj_boot_click_handler统一处理
// KEY2改为iot_button管理回调中直接调用sleep_mgr_notify_activity()
xTaskCreate(sleep_mgr_task, "sleep_mgr", 3072, NULL, 3, NULL);
ESP_LOGI(TAG, "休眠管理器初始化完成(超时=%ds", SLEEP_TIMEOUT_MS / 1000);
}
// 更新ScreenSet界面的亮度UI控件
static void update_brightness_ui(uint8_t brightness)
{
if (!lvgl_port_lock(100)) {
return;
}
// 更新滑块位置
if (ui_SliderBrightness) {
lv_slider_set_value(ui_SliderBrightness, brightness, LV_ANIM_OFF);
}
// 更新亮度文本标签
if (ui_LabelBrightness) {
char buf[8];
snprintf(buf, sizeof(buf), "%d%%", brightness);
lv_label_set_text(ui_LabelBrightness, buf);
}
lvgl_port_unlock();
}
void sleep_mgr_set_enabled(bool enabled)
{
sleep_enabled = enabled;
if (enabled) {
last_activity_us = esp_timer_get_time();
// 进入休眠模式时将亮度调节到10%
pwm_set_brightness(SLEEP_MODE_BRIGHTNESS);
update_brightness_ui(SLEEP_MODE_BRIGHTNESS);
ESP_LOGI(TAG, "休眠模式已启用,亮度已调节至%d%%%ds无操作将熄屏",
SLEEP_MODE_BRIGHTNESS, SLEEP_TIMEOUT_MS / 1000);
} else {
// 禁用休眠模式时恢复到默认亮度50%
if (screen_off) {
screen_off = false;
pwm_set_brightness(DEFAULT_BRIGHTNESS);
update_brightness_ui(DEFAULT_BRIGHTNESS);
ESP_LOGI(TAG, "休眠模式已禁用,屏幕已恢复,亮度恢复到%d%%", DEFAULT_BRIGHTNESS);
} else {
pwm_set_brightness(DEFAULT_BRIGHTNESS);
update_brightness_ui(DEFAULT_BRIGHTNESS);
ESP_LOGI(TAG, "休眠模式已禁用,亮度恢复到%d%%", DEFAULT_BRIGHTNESS);
}
}
}
bool sleep_mgr_is_enabled(void)
{
return sleep_enabled;
}
bool sleep_mgr_is_screen_off(void)
{
return screen_off;
}