按 GSD 框架 .planning/milestones/digital_human_rtc/ 规划完成 Phase 1。 源代码全部保留,通过 Kconfig 开关 + CMakeLists 条件编译 + #ifdef 调用点保护 实现"吧唧模式不进固件但代码可恢复"。 ## 核心变更 ### Kconfig 开关(默认关闭) - 新增 CONFIG_BAJI_BADGE_MODE(main/Kconfig.projbuild) - sdkconfig.defaults 默认 =n - =y 时恢复双模式(电子吧唧 + AI 对话) - =n 时仅 AI 数字人 RTC 模式 ### CMakeLists 剥离(剥离式不重写) - 9 个 dzbj/ 吧唧专属 + 9 个 ui/screens/ 吧唧 UI 进入 if(CONFIG_BAJI_BADGE_MODE) 条件块 - 公共保留: dzbj/lcd.c, ai_chat_ui.c, sprite_demo.c, dual_gif_demo.c, bg_gif_demo.c, pages_pwm.c, dzbj_init.c, fatfs.c - 修正 PLAN 漏判:dzbj_init/fatfs 公共化(AI 模式调用 dzbj_hw_display_init/DecodeImg) ### 调用点 #ifdef 保护 - application.cc: L20 include, L63-66 background_task, L536 device_mode 分支 - movecall_moji_esp32s3.cc: dzbj headers, init_spiffs_image_list extern, dzbj_boot_click_handler extern, device_mode_is_badge 分支, InitializeBadgeMode, InitializeBadgeModeButtons, mode_switch_combo 注册, device_mode_in_switch_suppress - 保留公共 extern: ai_chat_screen_init, ai_chat_resume_animation, pwm_init ### 整体文件级 #ifdef 包裹 - dzbj/dzbj_button.c/h - dzbj/sleep_mgr.c - sleep_mgr/include/sleep_mgr.h ### 6 个文件显式 #include "sdkconfig.h" - ESP-IDF 不会 force-include,必须手动 include 才能拿到 CONFIG_* 宏 ## G7 验收双向编译 - =n 模式 build: ✅ EXIT=0(数字人 RTC 单一形态) - =y 模式 build: ✅ EXIT=0(双模式恢复可用) ## 固件大小变化 | 段 | =n | =y | 节省 | |----|-----|------|------| | .text | 2.03 MB | 2.06 MB | 27 KB | | .rodata | 2.48 MB | 3.87 MB | 1.39 MB | | Total | 4.63 MB | 6.05 MB | 1.45 MB | ## GSD 文档(同时提交) - .planning/milestones/digital_human_rtc/MILESTONE.md - .planning/milestones/digital_human_rtc/ROADMAP.md - .planning/milestones/digital_human_rtc/INTEL.md - .planning/milestones/digital_human_rtc/phases/phase_01_kconfig_isolation/PLAN.md - .planning/milestones/digital_human_rtc/phases/phase_01_kconfig_isolation/SIZE_REPORT.md - .planning/milestones/digital_human_rtc/phases/phase_01_kconfig_isolation/BADGE_MODE_ISOLATION_MAP.md - 编译大小原始数据: size_*.txt ## 已知事项 - =n 固件 4.63 MB 仍 > 4 MB 目标,Phase 2 调整分区 + Phase 3 物理移除图片资源解决 - main/dzbj/ 下所有源文件完整保留,无任何物理删除
229 lines
7.0 KiB
C
229 lines
7.0 KiB
C
#include "sdkconfig.h"
|
||
|
||
#ifdef CONFIG_BAJI_BADGE_MODE
|
||
|
||
#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;
|
||
}
|
||
|
||
#endif // CONFIG_BAJI_BADGE_MODE
|