feat(power): add battery monitoring and status overlays

This commit is contained in:
chenjintao
2026-08-18 11:53:14 +08:00
parent 609fe978f1
commit 8f8254b397
31 changed files with 1655 additions and 22 deletions
+84 -3
View File
@@ -46,8 +46,15 @@
#define LCD_DIRECT_PRESENTATION_WAIT_POLL_MS 20U
#define LCD_DIRECT_TRANSFER_TIMEOUT_MS 100U
#define LCD_DIRECT_PREHEAT_WAIT_TIMEOUT_MS 5000U
#define LCD_DIRECT_FRAME_CACHE_MAX 4U
#define LCD_DIRECT_FRAME_CACHE_MAX 6U
#define LCD_DIRECT_PATH_MAX 96U
#define LCD_DIRECT_CHARGING_ICON_WIDTH 50U
#define LCD_DIRECT_CHARGING_ICON_X (LCD_DIRECT_WIDTH - LCD_DIRECT_CHARGING_ICON_WIDTH - 8U)
#define LCD_DIRECT_CHARGING_ICON_Y 8U
#define LCD_DIRECT_LOW_BATTERY_ICON_WIDTH 232U
#define LCD_DIRECT_LOW_BATTERY_ICON_HEIGHT 36U
#define LCD_DIRECT_LOW_BATTERY_ICON_X ((LCD_DIRECT_WIDTH - LCD_DIRECT_LOW_BATTERY_ICON_WIDTH) / 2U)
#define LCD_DIRECT_LOW_BATTERY_ICON_Y (LCD_DIRECT_HEIGHT - LCD_DIRECT_LOW_BATTERY_ICON_HEIGHT - 8U)
#define LCD_DIRECT_LAST_FRAME_EXTRA_HOLD_MS 200U
#define LCD_DIRECT_BASIC_FACE_FRAME_HOLD_MS 100U
#define LCD_DIRECT_BASIC_FACE_LAST_FRAME_HOLD_MS 100U
@@ -135,6 +142,7 @@ static bool s_render_loop_running;
static bool s_stop_requested;
static bool s_pending_valid;
static lcd_direct_request_t s_pending;
static platform_lcd_status_overlay_t s_status_overlay;
static bool s_preheat_pending_valid;
static bool s_preheat_in_progress;
static bool s_preheat_waiter_active;
@@ -683,6 +691,38 @@ static void lcd_direct_release_prepared_icons(lcd_direct_prepared_icon_t *prepar
}
}
static size_t lcd_direct_append_status_icons(const lcd_direct_image_t *image,
lcd_direct_icon_draw_t *icons,
size_t icon_count,
size_t icon_capacity)
{
if (image == NULL || image->path == NULL || icons == NULL ||
icon_count >= icon_capacity || strstr(image->path, "/qrcode.png") != NULL) {
return icon_count;
}
platform_lcd_status_overlay_t overlay = {0};
portENTER_CRITICAL(&s_state_lock);
overlay = s_status_overlay;
portEXIT_CRITICAL(&s_state_lock);
if (overlay.low_battery_visible && icon_count < icon_capacity) {
icons[icon_count++] = (lcd_direct_icon_draw_t) {
.icon_id = LCD_DIRECT_ICON_LOW_BATTERY,
.x = LCD_DIRECT_LOW_BATTERY_ICON_X,
.y = LCD_DIRECT_LOW_BATTERY_ICON_Y,
};
}
if (overlay.charging_visible && icon_count < icon_capacity) {
icons[icon_count++] = (lcd_direct_icon_draw_t) {
.icon_id = LCD_DIRECT_ICON_CHARGING,
.x = LCD_DIRECT_CHARGING_ICON_X,
.y = LCD_DIRECT_CHARGING_ICON_Y,
};
}
return icon_count;
}
static void lcd_direct_overlay_icons(uint16_t *pixel_buffer,
uint16_t row_start,
uint16_t row_count,
@@ -766,9 +806,23 @@ static esp_err_t lcd_direct_draw_png_image(const lcd_direct_image_t *image,
decoded->pinned = true;
}
lcd_direct_icon_draw_t combined_icons[LCD_DIRECT_DEFAULT_ICON_COUNT] = {0};
size_t combined_icon_count = icon_count;
if (combined_icon_count > LCD_DIRECT_DEFAULT_ICON_COUNT) {
combined_icon_count = LCD_DIRECT_DEFAULT_ICON_COUNT;
}
if (icons != NULL && combined_icon_count > 0U) {
memcpy(combined_icons, icons, combined_icon_count * sizeof(combined_icons[0]));
}
combined_icon_count = lcd_direct_append_status_icons(
image,
combined_icons,
combined_icon_count,
LCD_DIRECT_DEFAULT_ICON_COUNT);
lcd_direct_prepared_icon_t prepared_icons[LCD_DIRECT_DEFAULT_ICON_COUNT] = {0};
size_t prepared_icon_count = lcd_direct_prepare_icons(icons,
icon_count,
size_t prepared_icon_count = lcd_direct_prepare_icons(combined_icons,
combined_icon_count,
prepared_icons,
sizeof(prepared_icons) / sizeof(prepared_icons[0]));
esp_err_t err = ESP_OK;
@@ -1424,6 +1478,33 @@ esp_err_t lcd_direct_stop_render_loop(int timeout_ms)
return ESP_ERR_TIMEOUT;
}
esp_err_t lcd_direct_set_status_overlay(const platform_lcd_status_overlay_t *overlay)
{
if (overlay == NULL) {
return ESP_ERR_INVALID_ARG;
}
bool changed = false;
TaskHandle_t render_task = NULL;
portENTER_CRITICAL(&s_state_lock);
changed = s_status_overlay.low_battery_visible != overlay->low_battery_visible ||
s_status_overlay.charging_visible != overlay->charging_visible;
s_status_overlay = *overlay;
render_task = s_render_task;
portEXIT_CRITICAL(&s_state_lock);
if (changed && render_task != NULL) {
xTaskNotifyGive(render_task);
}
if (changed) {
ESP_LOGI(TAG,
"LCD battery overlays low=%d charging=%d",
overlay->low_battery_visible,
overlay->charging_visible);
}
return ESP_OK;
}
esp_err_t lcd_direct_request_presentation(const platform_lcd_presentation_request_t *request)
{
if (!s_initialized || request == NULL) {