feat(power): add battery monitoring and status overlays
This commit is contained in:
@@ -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) {
|
||||
|
||||
Reference in New Issue
Block a user