初始提交卡包 USB 工程
纳入固件源码、屏幕组件、nand_xfer 工具和文档。忽略本机构建产物、sdkconfig,以及含本机路径的依赖锁。 Co-authored-by: Cursor <[email protected]>
This commit is contained in:
@@ -0,0 +1,171 @@
|
||||
/*****************************************************include files **************************************************************************/
|
||||
#include "screen_brightness.h"
|
||||
#include "LVGL/lvgl_init.h"
|
||||
#include "ui.h"
|
||||
/******************************************************* variable declaration ************************************************************************/
|
||||
|
||||
/*
|
||||
* 亮度模型:UI/BLE 的 0~100% 线性映射到面板 PWM [BRIGHTNESS_PWM_MIN, BRIGHTNESS_PWM_MAX]。
|
||||
* 选 55 作为下限:约 21.5% 全量程,且 (255-55)=200,duty = 55 + percent*2,0~100 与整数 PWM 一一对应、无除法舍入误差。
|
||||
* 若硬件需其它暗场门限,只改 BRIGHTNESS_PWM_MIN(需保持 SPAN 与映射公式一致或同步改除法)。
|
||||
*/
|
||||
#define BRIGHTNESS_PWM_MIN 55
|
||||
#define BRIGHTNESS_PWM_MAX 255
|
||||
#define BRIGHTNESS_PWM_SPAN (BRIGHTNESS_PWM_MAX - BRIGHTNESS_PWM_MIN)
|
||||
|
||||
// 当前面板 PWM(BRIGHTNESS_PWM_MIN~BRIGHTNESS_PWM_MAX);未读 NVS 前取中间偏亮,避免明显过暗
|
||||
uint8_t g_current_brightness = (uint8_t)(BRIGHTNESS_PWM_MIN + BRIGHTNESS_PWM_SPAN * 3 / 4);
|
||||
static bool g_brightness_dirty = false;
|
||||
static uint8_t g_brightness_commit_pending = 0;
|
||||
|
||||
static TimerHandle_t g_brightness_commit_timer = NULL;
|
||||
|
||||
/******************************************************* functions declaration ************************************************************************/
|
||||
|
||||
|
||||
void save_brightness_to_nvs(uint8_t value); /* forward declaration for timer callback */
|
||||
void commit_brightness_if_dirty(void);
|
||||
|
||||
extern esp_err_t panel_qspi_amoled_set_brightness(esp_lcd_panel_handle_t panel, uint8_t brightness);
|
||||
|
||||
|
||||
/******************************************************* functions definition ************************************************************************/
|
||||
|
||||
// 保存亮度到 NVS
|
||||
void save_brightness_to_nvs(uint8_t value)
|
||||
{
|
||||
nvs_handle_t my_handle;
|
||||
esp_err_t err = nvs_open("system_cfg", NVS_READWRITE, &my_handle);
|
||||
if (err == ESP_OK)
|
||||
{
|
||||
nvs_set_u8(my_handle, "brightness", value);
|
||||
nvs_commit(my_handle);
|
||||
nvs_close(my_handle);
|
||||
// ESP_LOGI("NVS", "亮度已保存: %d", value);
|
||||
}
|
||||
}
|
||||
|
||||
static void brightness_commit_timer_cb(TimerHandle_t xTimer)
|
||||
{
|
||||
(void)xTimer;
|
||||
save_brightness_to_nvs(g_brightness_commit_pending);
|
||||
}
|
||||
|
||||
// 从 NVS 读取亮度
|
||||
void load_brightness_from_nvs(void)
|
||||
{
|
||||
nvs_handle_t my_handle;
|
||||
esp_err_t err = nvs_open("system_cfg", NVS_READONLY, &my_handle);
|
||||
if (err == ESP_OK)
|
||||
{
|
||||
uint8_t saved_val = 0;
|
||||
if (nvs_get_u8(my_handle, "brightness", &saved_val) == ESP_OK)
|
||||
{
|
||||
g_current_brightness = saved_val;
|
||||
if (g_current_brightness < BRIGHTNESS_PWM_MIN)
|
||||
g_current_brightness = BRIGHTNESS_PWM_MIN;
|
||||
if (g_current_brightness > BRIGHTNESS_PWM_MAX)
|
||||
g_current_brightness = BRIGHTNESS_PWM_MAX;
|
||||
ESP_LOGI("NVS", "加载保存的亮度: %d", g_current_brightness);
|
||||
}
|
||||
nvs_close(my_handle);
|
||||
}
|
||||
}
|
||||
|
||||
// ================= 对外接口 =================
|
||||
|
||||
// 设置亮度 (供 UI 和 BLE 调用)
|
||||
// 参数 percent: 0-100,0 对应 PWM_MIN、100 对应 PWM_MAX
|
||||
void set_system_brightness(int percent)
|
||||
{
|
||||
if (percent < 0)
|
||||
percent = 0;
|
||||
if (percent > 100)
|
||||
percent = 100;
|
||||
|
||||
uint8_t duty = (uint8_t)(BRIGHTNESS_PWM_MIN + ((unsigned)percent * BRIGHTNESS_PWM_SPAN) / 100U);
|
||||
|
||||
// 3. 应用到硬件
|
||||
if (panel_handle)
|
||||
{
|
||||
panel_qspi_amoled_set_brightness(panel_handle, duty);
|
||||
}
|
||||
|
||||
// 4. 更新全局变量并保存
|
||||
if (g_current_brightness != duty)
|
||||
{
|
||||
g_current_brightness = duty;
|
||||
g_brightness_dirty = true;
|
||||
request_brightness_slider_sync();
|
||||
}
|
||||
/* BLE/UI 共用:有变更时经定时器落盘 NVS(避免在回调里同步写) */
|
||||
commit_brightness_if_dirty();
|
||||
}
|
||||
|
||||
/* 退出亮度界面时调用:只写一次 NVS,避免频繁保存导致不稳定 */
|
||||
void commit_brightness_if_dirty(void)
|
||||
{
|
||||
if (!g_brightness_dirty)
|
||||
return;
|
||||
g_brightness_commit_pending = g_current_brightness;
|
||||
g_brightness_dirty = false;
|
||||
/* NVS 写放到 timer 任务上下文,避免在 LVGL 点击事件回调里同步写导致崩溃 */
|
||||
if (g_brightness_commit_timer == NULL)
|
||||
{
|
||||
g_brightness_commit_timer = xTimerCreate("brightness_commit_tmr",
|
||||
pdMS_TO_TICKS(50),
|
||||
pdFALSE,
|
||||
NULL,
|
||||
brightness_commit_timer_cb);
|
||||
}
|
||||
if (g_brightness_commit_timer)
|
||||
{
|
||||
xTimerStop(g_brightness_commit_timer, 0);
|
||||
if (xTimerStart(g_brightness_commit_timer, 0) != pdPASS)
|
||||
{
|
||||
/* 定时器队列满等异常时仍落盘,避免已清 dirty 却永不写入 NVS */
|
||||
save_brightness_to_nvs(g_brightness_commit_pending);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* xTimerCreate 失败(如堆不足)时直接写 NVS,否则与蓝牙路径行为不一致 */
|
||||
save_brightness_to_nvs(g_brightness_commit_pending);
|
||||
}
|
||||
}
|
||||
|
||||
// 获取当前亮度百分比 (供 UI 初始化滑块与 BLE 查询,0~100)
|
||||
int get_system_brightness_percent(void)
|
||||
{
|
||||
unsigned d = g_current_brightness;
|
||||
if (d <= BRIGHTNESS_PWM_MIN)
|
||||
return 0;
|
||||
if (d >= BRIGHTNESS_PWM_MAX)
|
||||
return 100;
|
||||
return (int)((d - BRIGHTNESS_PWM_MIN) * 100U / BRIGHTNESS_PWM_SPAN);
|
||||
}
|
||||
|
||||
// 【核心函数 2】设置是否阻止休眠 (例如 OTA 时调用 set_block_sleep(true))
|
||||
void set_block_auto_sleep(bool block)
|
||||
{
|
||||
block_auto_sleep = block;
|
||||
if (block)
|
||||
{
|
||||
system_keep_alive(); // 阻止时顺便刷新一下时间
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* 亮度滑动条同步:将设置页滑动条与当前系统亮度对齐 */
|
||||
void request_brightness_slider_sync(void)
|
||||
{
|
||||
extern lv_ui guider_ui;
|
||||
extern int get_system_brightness_percent(void);
|
||||
|
||||
int percent = get_system_brightness_percent();
|
||||
|
||||
if (guider_ui.screen_set_slider_light != NULL &&
|
||||
lv_obj_is_valid(guider_ui.screen_set_slider_light)) {
|
||||
lv_slider_set_value(guider_ui.screen_set_slider_light, percent, LV_ANIM_OFF);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
#ifndef __SCREEN_BRIGHTNESS_H__
|
||||
#define __SCREEN_BRIGHTNESS_H__
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
#include "config.h"
|
||||
|
||||
|
||||
extern uint8_t g_current_brightness;
|
||||
|
||||
/** percent: 0~100,与滑动条/BLE 一致;0→PWM 下限、100→PWM 上限(见 screen_brightness.c) */
|
||||
void set_system_brightness(int percent);
|
||||
/** 有亮度脏标记时写 NVS(内部 50ms 防抖定时器);供退出设置页等场景也可直接调用 */
|
||||
void commit_brightness_if_dirty(void);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,237 @@
|
||||
#include "screen_init.h"
|
||||
#include "config.h"
|
||||
#include "LVGL/lvgl_init.h"
|
||||
#include "driver/i2c_master.h"
|
||||
|
||||
|
||||
|
||||
const char *TAG_LVGL = "lvgl_init";//打印标签
|
||||
#if EXAMPLE_USE_TOUCH
|
||||
esp_lcd_touch_handle_t tp = NULL;
|
||||
bool is_anim_paused = false;
|
||||
i2c_master_bus_handle_t touch_bus_handle_touch; // 定义触摸屏I2C总线句柄(全局,供BMI270共享)
|
||||
#endif
|
||||
static void read_lcd_id(esp_lcd_panel_io_handle_t read_io)
|
||||
{
|
||||
uint8_t id_buf[3] = {0};
|
||||
esp_err_t ret = esp_lcd_panel_io_rx_param(read_io, 0x03000400, id_buf, 3);
|
||||
if (ret == ESP_OK) {
|
||||
ESP_LOGI(TAG_LVGL, "LCD ID: %02X %02X %02X", id_buf[0], id_buf[1], id_buf[2]);
|
||||
} else {
|
||||
ESP_LOGE(TAG_LVGL, "Read ID failed: %s", esp_err_to_name(ret));
|
||||
}
|
||||
|
||||
uint8_t id1 = 0;
|
||||
uint8_t id2 = 0;
|
||||
uint8_t id3 = 0;
|
||||
esp_err_t ret1 = esp_lcd_panel_io_rx_param(read_io, 0x0300DA00, &id1, 1);
|
||||
esp_err_t ret2 = esp_lcd_panel_io_rx_param(read_io, 0x0300DB00, &id2, 1);
|
||||
esp_err_t ret3 = esp_lcd_panel_io_rx_param(read_io, 0x0300DC00, &id3, 1);
|
||||
if (ret1 == ESP_OK && ret2 == ESP_OK && ret3 == ESP_OK) {
|
||||
ESP_LOGI(TAG_LVGL, "LCD RDID: %02X %02X %02X", id1, id2, id3);
|
||||
} else {
|
||||
ESP_LOGE(TAG_LVGL, "Read RDID failed: %s %s %s",
|
||||
esp_err_to_name(ret1), esp_err_to_name(ret2), esp_err_to_name(ret3));
|
||||
}
|
||||
}
|
||||
/*
|
||||
const qspi_amoled_lcd_init_cmd_t lcd_init_cmds[13] = {
|
||||
{0xFE, (uint8_t[]){0x00}, 1, 0},
|
||||
{0xC4, (uint8_t[]){0x80}, 1, 0},
|
||||
{0x35, (uint8_t[]){0x00}, 1, 0},
|
||||
{0x3A, (uint8_t[]){0x77}, 1, 0},
|
||||
{0x53, (uint8_t[]){0x20}, 1, 0},
|
||||
{0x51, (uint8_t[]){0x00}, 1, 0},
|
||||
{0x63, (uint8_t[]){0xFF}, 1, 0},
|
||||
{0x2A, (uint8_t[]){0x00, 0x16, 0x01, 0xAF}, 4, 0},
|
||||
{0x2B, (uint8_t[]){0x00, 0x00, 0x01, 0xF5}, 4, 0},
|
||||
{0x11, (uint8_t[]){0x00}, 0, 120},
|
||||
{0x29, (uint8_t[]){0x00}, 0, 60},
|
||||
{0x58, (uint8_t[]){0x07}, 1, 10},
|
||||
{0x36, (uint8_t[]){0xA8}, 1, 0},
|
||||
};
|
||||
*/
|
||||
const qspi_amoled_lcd_init_cmd_t lcd_init_cmds[] = {
|
||||
// 0x11: 退出睡眠模式(Sleep Out),之后延时 60ms
|
||||
{0x11, (uint8_t[]){0x00}, 0, 60},
|
||||
|
||||
// 0x2A: 列地址范围 0~239(0x00 0x00 ~ 0x00 0xEF)
|
||||
{0x2A, (uint8_t[]){0x00, 0x00, 0x00, 0xEF}, 4, 0},
|
||||
|
||||
// 0x2B: 行地址范围 0~295(0x00 0x00 ~ 0x01 0x27)
|
||||
{0x2B, (uint8_t[]){0x00, 0x00, 0x01, 0x27}, 4, 0},
|
||||
|
||||
// 0x44: 撕裂效应行(TE Line)设为 295
|
||||
{0x44, (uint8_t[]){0x01, 0x27}, 2, 0},
|
||||
|
||||
// 0x3A: 像素格式(Pixel Format)0x55(通常为 16bit/18bit)
|
||||
{0x3A, (uint8_t[]){0x55}, 1, 0},
|
||||
|
||||
// 0x35: TE 信号控制,0x00 = 关闭
|
||||
{0x35, (uint8_t[]){0x00}, 1, 0},
|
||||
|
||||
// 0x53: 亮度控制寄存器,设为 0x20
|
||||
{0x53, (uint8_t[]){0x20}, 1, 0},
|
||||
|
||||
// 0x51: 亮度值设为最高 0xFF,之后延时 60ms 再开启显示
|
||||
{0x51, (uint8_t[]){0xFF}, 1, 60},
|
||||
|
||||
// 0x29: 开启显示(Display On),无需额外延时
|
||||
{0x29, (uint8_t[]){0x00}, 0, 0},
|
||||
};
|
||||
|
||||
|
||||
|
||||
// QSPI AMOLED供应商配置
|
||||
qspi_amoled_vendor_config_t vendor_config =
|
||||
{
|
||||
.init_cmds = lcd_init_cmds,
|
||||
.init_cmds_size = sizeof(lcd_init_cmds) / sizeof(lcd_init_cmds[0]),
|
||||
.flags =
|
||||
{
|
||||
.use_qspi_interface = 1,
|
||||
},
|
||||
};
|
||||
|
||||
// LCD面板配置
|
||||
const esp_lcd_panel_dev_config_t panel_config =
|
||||
{
|
||||
.reset_gpio_num = EXAMPLE_PIN_NUM_LCD_RST,
|
||||
.rgb_ele_order = LCD_RGB_ELEMENT_ORDER,
|
||||
.bits_per_pixel = LCD_BIT_PER_PIXEL,
|
||||
.vendor_config = &vendor_config,
|
||||
};
|
||||
|
||||
|
||||
extern esp_lcd_panel_io_handle_t io_handle;
|
||||
|
||||
void read_co5300_response(void) {
|
||||
|
||||
}
|
||||
esp_err_t app_lcd_init(void)//QSPI初始化
|
||||
{
|
||||
esp_err_t ret = ESP_OK;
|
||||
|
||||
ESP_LOGI(TAG_LVGL, "Initialize QSPI bus");
|
||||
|
||||
// 使用原始的SPI总线最大传输大小,确保稳定传输
|
||||
const spi_bus_config_t buscfg = QSPI_AMOLED_PANEL_BUS_QSPI_CONFIG(EXAMPLE_PIN_NUM_LCD_PCLK,
|
||||
EXAMPLE_PIN_NUM_LCD_DATA0,
|
||||
EXAMPLE_PIN_NUM_LCD_DATA1,
|
||||
EXAMPLE_PIN_NUM_LCD_DATA2,
|
||||
EXAMPLE_PIN_NUM_LCD_DATA3,
|
||||
(EXAMPLE_LCD_H_RES * EXAMPLE_LVGL_BUF_HEIGHT * LCD_BIT_PER_PIXEL / 8) + 64);
|
||||
|
||||
ESP_ERROR_CHECK(spi_bus_initialize(LCD_HOST, &buscfg, SPI_DMA_CH_AUTO));
|
||||
ESP_LOGI(TAG_LVGL, "Install panel IO");
|
||||
esp_lcd_panel_io_spi_config_t io_config = {
|
||||
.cs_gpio_num = EXAMPLE_PIN_NUM_LCD_CS,
|
||||
.dc_gpio_num = -1,
|
||||
.spi_mode = AMOLED_QSPI_MODE,
|
||||
.pclk_hz = AMOLED_QSPI_MAX_PCLK,
|
||||
.trans_queue_depth = 3,
|
||||
.on_color_trans_done = example_notify_lvgl_flush_ready,
|
||||
.user_ctx = NULL,
|
||||
.lcd_cmd_bits = 32,
|
||||
.lcd_param_bits = 8,
|
||||
.flags = {
|
||||
.quad_mode = true,
|
||||
},
|
||||
};
|
||||
|
||||
ESP_ERROR_CHECK(esp_lcd_new_panel_io_spi((esp_lcd_spi_bus_handle_t)LCD_HOST, &io_config, &io_handle));
|
||||
ESP_LOGI(TAG_LVGL, "Install QSPI_AMOLED panel driver");
|
||||
ESP_ERROR_CHECK(esp_lcd_new_panel_qspi_amoled(io_handle, &panel_config, &panel_handle));
|
||||
ESP_ERROR_CHECK(esp_lcd_panel_reset(panel_handle));
|
||||
ESP_ERROR_CHECK(esp_lcd_panel_init(panel_handle));
|
||||
ESP_ERROR_CHECK(esp_lcd_panel_set_gap(panel_handle, EXAMPLE_LCD_X_GAP, EXAMPLE_LCD_Y_GAP));
|
||||
ESP_ERROR_CHECK(esp_lcd_panel_disp_on_off(panel_handle, true));
|
||||
/* 初始化时设置亮度为0,避免白光闪烁,等待 UI 加载后渐变亮屏 */
|
||||
esp_err_t br = panel_qspi_amoled_set_brightness(panel_handle,100);
|
||||
//uint8_t read_buf[3] = {0}; // RDDID 返回 3 个字节
|
||||
/*
|
||||
// 发送读指令 0x04,读取 3 个字节的回应数据
|
||||
esp_err_t ret2 = esp_lcd_panel_io_rx_param(io_handle, 0x04, read_buf, 3);
|
||||
|
||||
if (ret2 == ESP_OK) {
|
||||
ESP_LOGI("TAG", "读取回应成功!ID1: 0x%02X, ID2: 0x%02X, ID3: 0x%02X",
|
||||
read_buf[0], read_buf[1], read_buf[2]);
|
||||
// 根据数据手册,正常回应通常为:33h, 10h, 00h 或 33h, 11h, 00h
|
||||
} else {
|
||||
ESP_LOGE("TAG", "读取回应失败:%s", esp_err_to_name(ret2));
|
||||
}*/
|
||||
//read_lcd_id(io_handle);
|
||||
//ESP_LOGI(TAG_LVGL,"br=%d",br);
|
||||
//uint8_t blue_color[] = {0x00, 0x00, 0xFF};
|
||||
//esp_err_t brt =panel_qspi_amoled_draw_bitmap(panel_handle, 0, 0, EXAMPLE_LCD_H_RES - 1, EXAMPLE_LCD_V_RES - 1, blue_color);
|
||||
/*
|
||||
if (br != ESP_OK)
|
||||
{
|
||||
ESP_LOGE(TAG_LVGL, "panel_qspi_amoled_set_brightness failed: %s", esp_err_to_name(br));
|
||||
}
|
||||
else
|
||||
{
|
||||
ESP_LOGI(TAG_LVGL, "Screen brightness set to 0 (等待 UI 加载后渐变亮屏)");
|
||||
}
|
||||
|
||||
*/
|
||||
/* Register done callback */
|
||||
//ESP_ERROR_CHECK(esp_lcd_panel_io_register_event_callbacks(io_handle, &cbs, disp));
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
|
||||
esp_err_t app_touch_init(void)
|
||||
{
|
||||
ESP_LOGI(TAG_LVGL, "初始化 I2C 总线 (新驱动模式)");
|
||||
|
||||
// 1. 配置 I2C 总线
|
||||
i2c_master_bus_config_t i2c_bus_config = {
|
||||
.clk_source = I2C_CLK_SRC_DEFAULT,
|
||||
.i2c_port = TOUCH_HOST,
|
||||
.scl_io_num = EXAMPLE_PIN_NUM_TOUCH_SCL,
|
||||
.sda_io_num = EXAMPLE_PIN_NUM_TOUCH_SDA,
|
||||
.glitch_ignore_cnt = 7,
|
||||
.flags.enable_internal_pullup = true,
|
||||
};
|
||||
ESP_ERROR_CHECK(i2c_new_master_bus(&i2c_bus_config, &touch_bus_handle_touch));
|
||||
|
||||
// 2. 配置触摸面板 IO(这里会自动适配新驱动)
|
||||
esp_lcd_panel_io_handle_t tp_io_handle = NULL;
|
||||
const esp_lcd_panel_io_i2c_config_t tp_io_config = {
|
||||
.dev_addr = 0x15, // CST816/CST820 的默认地址,根据实际修改
|
||||
.on_color_trans_done = NULL,
|
||||
.user_ctx = NULL,
|
||||
.control_phase_bytes = 1,
|
||||
.dc_bit_offset = 0,
|
||||
.lcd_cmd_bits = 8,
|
||||
.lcd_param_bits = 8,
|
||||
.scl_speed_hz = 400 * 1000,
|
||||
.flags = {
|
||||
.disable_control_phase = 1,
|
||||
}};
|
||||
|
||||
// 使用新总线句柄创建 IO
|
||||
ESP_ERROR_CHECK(esp_lcd_new_panel_io_i2c_v2(touch_bus_handle_touch, &tp_io_config, &tp_io_handle));
|
||||
|
||||
// 3. 配置触摸芯片参数
|
||||
const esp_lcd_touch_config_t tp_cfg = {
|
||||
.x_max = EXAMPLE_LCD_H_RES,
|
||||
.y_max = EXAMPLE_LCD_V_RES,
|
||||
.rst_gpio_num = EXAMPLE_PIN_NUM_TOUCH_RST,
|
||||
.int_gpio_num = EXAMPLE_PIN_NUM_TOUCH_INT,
|
||||
.levels = {
|
||||
.reset = 0,
|
||||
.interrupt = 0,
|
||||
},
|
||||
.flags = {
|
||||
.swap_xy = 1,
|
||||
.mirror_x = 0,
|
||||
.mirror_y = 1,
|
||||
},
|
||||
};
|
||||
|
||||
ESP_LOGI(TAG_LVGL, "创建触摸控制器句柄");
|
||||
return esp_lcd_touch_new_i2c(tp_io_handle, &tp_cfg, &tp);
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
#ifndef __SCREEN_INIT_H__
|
||||
#define __SCREEN_INIT_H__
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
#include "config.h"
|
||||
|
||||
extern const esp_lcd_panel_dev_config_t panel_config;
|
||||
extern const char *TAG_LVGL ;
|
||||
|
||||
esp_err_t app_lcd_init(void);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@@ -0,0 +1,177 @@
|
||||
/*****************************************************include files **************************************************************************/
|
||||
#include "screen_sleep.h"
|
||||
#include "ui/generated/events_init.h"
|
||||
#include "ui/ui.h"
|
||||
|
||||
#define AUTO_SLEEP_DEFAULT_MS 0//默认休眠时间
|
||||
|
||||
/******************************************************* variable declaration ************************************************************************/
|
||||
static uint32_t g_auto_sleep_timeout_ms = AUTO_SLEEP_DEFAULT_MS;
|
||||
|
||||
// 初始化为当前开机时间
|
||||
int64_t last_activity_timestamp = 0; //最后一次用户活动的时间戳
|
||||
|
||||
static bool g_sleep_timeout_dirty = false; //休眠时间是否被改过但是没有写入NVS
|
||||
|
||||
static uint32_t g_sleep_commit_pending_ms = 0; //待提交到NVS的休眠时间缓存值
|
||||
|
||||
/* ===== 休眠设置 NVS 提交:离开休眠界面时写一次 ===== */
|
||||
|
||||
static TimerHandle_t g_sleep_commit_timer = NULL; //创建了freeRTOS的软件定时器句柄
|
||||
|
||||
extern volatile bool is_system_sleeping; //系统睡眠标记
|
||||
extern bool block_auto_sleep ; //是否阻止自动休眠
|
||||
extern int current_page_idx ; //当前页面索引
|
||||
/******************************************************* functions declaration ************************************************************************/
|
||||
|
||||
static void save_timeout_to_nvs(uint32_t ms);
|
||||
static void sleep_commit_timer_cb(TimerHandle_t xTimer);
|
||||
|
||||
/******************************************************* functions definition ************************************************************************/
|
||||
// 【新增】从 NVS 加载休眠时间
|
||||
void load_timeout_from_nvs(void)//从nvs加载休眠时间
|
||||
{
|
||||
nvs_handle_t my_handle;
|
||||
esp_err_t err = nvs_open("system_cfg", NVS_READONLY, &my_handle);
|
||||
if (err != ESP_OK)
|
||||
{
|
||||
ESP_LOGW("NVS", "打开 system_cfg 失败: %s,休眠时间使用默认 %lu ms",
|
||||
esp_err_to_name(err), (unsigned long)AUTO_SLEEP_DEFAULT_MS);
|
||||
g_auto_sleep_timeout_ms = AUTO_SLEEP_DEFAULT_MS;
|
||||
system_keep_alive();
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t saved_val = 0;
|
||||
if (nvs_get_u32(my_handle, "sleep_ms", &saved_val) == ESP_OK)
|
||||
{
|
||||
g_auto_sleep_timeout_ms = saved_val;
|
||||
ESP_LOGI("NVS", "从 NVS 加载休眠时间: %lu ms", (unsigned long)g_auto_sleep_timeout_ms);
|
||||
}
|
||||
else
|
||||
{
|
||||
g_auto_sleep_timeout_ms = AUTO_SLEEP_DEFAULT_MS;
|
||||
ESP_LOGW("NVS", "未找到 sleep_ms,使用默认 %lu ms", (unsigned long)AUTO_SLEEP_DEFAULT_MS);
|
||||
}
|
||||
nvs_close(my_handle);
|
||||
/* 以完成 NVS 加载时刻为空闲计时起点,避免 last_activity 长期为 0 误判超时 */
|
||||
system_keep_alive();
|
||||
}
|
||||
|
||||
// 【新增】保存设置到 NVS
|
||||
static void save_timeout_to_nvs(uint32_t ms)//保存休眠时间到nvs
|
||||
{
|
||||
nvs_handle_t my_handle;
|
||||
esp_err_t err = nvs_open("system_cfg", NVS_READWRITE, &my_handle);
|
||||
if (err == ESP_OK)
|
||||
{
|
||||
nvs_set_u32(my_handle, "sleep_ms", ms);
|
||||
nvs_commit(my_handle); // 提交保存
|
||||
nvs_close(my_handle);
|
||||
ESP_LOGI("NVS", "休眠时间已保存: %lu ms", (unsigned long)ms);
|
||||
}
|
||||
else
|
||||
{
|
||||
ESP_LOGE("NVS", "无法打开 NVS 保存设置");
|
||||
}
|
||||
}
|
||||
|
||||
void persist_auto_sleep_timeout_ms_now(uint32_t ms)
|
||||
{
|
||||
if (g_sleep_commit_timer != NULL)
|
||||
{
|
||||
xTimerStop(g_sleep_commit_timer, pdMS_TO_TICKS(100));
|
||||
}
|
||||
g_auto_sleep_timeout_ms = ms;
|
||||
g_sleep_timeout_dirty = false;
|
||||
g_sleep_commit_pending_ms = ms;
|
||||
system_keep_alive();
|
||||
save_timeout_to_nvs(ms);
|
||||
}
|
||||
|
||||
// 2. 【新增】设置超时时间的函数 (提供给按钮调用)
|
||||
// 输入 0 代表永不休眠 设置自动休眠时间
|
||||
void set_auto_sleep_timeout(uint32_t ms)
|
||||
{
|
||||
if (g_auto_sleep_timeout_ms == ms) {
|
||||
return;
|
||||
}
|
||||
g_auto_sleep_timeout_ms = ms;
|
||||
system_keep_alive();
|
||||
ESP_LOGI("PM", "休眠设置更新: %lu ms (mark dirty)", (unsigned long)ms);
|
||||
|
||||
g_sleep_timeout_dirty = true;
|
||||
}
|
||||
|
||||
|
||||
// 【核心函数 1】系统保活:任何操作都应该调用这个函数
|
||||
void system_keep_alive(void)//更新当前的活动时间戳
|
||||
{
|
||||
last_activity_timestamp = esp_timer_get_time() / 1000; // 更新为当前时间(ms)
|
||||
}
|
||||
|
||||
//获取自动休眠时间
|
||||
uint32_t get_auto_sleep_timeout(void)
|
||||
{
|
||||
return g_auto_sleep_timeout_ms;
|
||||
}
|
||||
|
||||
//如果脏标记被设置过之后 发送自动休眠时间
|
||||
void commit_auto_sleep_timeout_if_dirty(void)
|
||||
{
|
||||
if (!g_sleep_timeout_dirty)
|
||||
return;
|
||||
|
||||
g_sleep_commit_pending_ms = g_auto_sleep_timeout_ms;
|
||||
g_sleep_timeout_dirty = false;
|
||||
|
||||
/* 真正的 NVS 写放到 timer 回调里,避免在 LVGL 事件栈上下文里写 NVS */
|
||||
if (g_sleep_commit_timer == NULL)
|
||||
{
|
||||
g_sleep_commit_timer = xTimerCreate("sleep_commit_tmr",
|
||||
pdMS_TO_TICKS(50),
|
||||
pdFALSE,
|
||||
NULL,
|
||||
sleep_commit_timer_cb);
|
||||
}
|
||||
if (g_sleep_commit_timer)
|
||||
{
|
||||
if (xTimerStart(g_sleep_commit_timer, 0) != pdPASS)
|
||||
{
|
||||
save_timeout_to_nvs(g_sleep_commit_pending_ms);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
save_timeout_to_nvs(g_sleep_commit_pending_ms);
|
||||
}
|
||||
}
|
||||
|
||||
static void sleep_commit_timer_cb(TimerHandle_t xTimer)
|
||||
{
|
||||
(void)xTimer;
|
||||
save_timeout_to_nvs(g_sleep_commit_pending_ms);
|
||||
}
|
||||
|
||||
|
||||
void auto_sleep_checker_cb(lv_timer_t *timer)
|
||||
{
|
||||
// 如果已经在睡觉,或者被阻止,或者设置为 0 (永不),直接返回
|
||||
if (is_system_sleeping || block_auto_sleep || g_auto_sleep_timeout_ms == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
int64_t now = esp_timer_get_time() / 1000;
|
||||
|
||||
// 使用变量 g_auto_sleep_timeout_ms 替代原来的 30000
|
||||
if ((now - last_activity_timestamp) > g_auto_sleep_timeout_ms)
|
||||
{
|
||||
ESP_LOGW("PM", "系统空闲超时,自动进入休眠...");
|
||||
if (current_page_idx != 0)
|
||||
{
|
||||
ui_change_page(0, LV_SCR_LOAD_ANIM_FADE_ON);
|
||||
}
|
||||
toggle_sleep_mode(true);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
#ifndef __SCREEN_SLEEP_H__
|
||||
#define __SCREEN_SLEEP_H__
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
#include "config.h"
|
||||
|
||||
extern const esp_lcd_panel_dev_config_t panel_config;
|
||||
extern const char *TAG_LVGL ;
|
||||
|
||||
esp_err_t app_lcd_init(void);
|
||||
|
||||
void system_keep_alive(void);
|
||||
void load_timeout_from_nvs(void);
|
||||
void set_auto_sleep_timeout(uint32_t ms);
|
||||
uint32_t get_auto_sleep_timeout(void);
|
||||
void commit_auto_sleep_timeout_if_dirty(void);
|
||||
/** 立即把 ms 写入 RAM 与 NVS(停掉延迟提交定时器);用于恢复出厂等须在 esp_restart 前落盘的场景 */
|
||||
void persist_auto_sleep_timeout_ms_now(uint32_t ms);
|
||||
void auto_sleep_checker_cb(lv_timer_t *timer);
|
||||
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user