修复了SW2 双击后抖动,

icon 文件改为每帧只加载一次,整帧绘制期间复用,不再每 8 行重复读取。
This commit is contained in:
CSBOOK\44744
2026-06-28 19:16:17 +08:00
parent 4c6bb66f7c
commit 21e5d43766
4 changed files with 115 additions and 20 deletions
@@ -44,6 +44,10 @@
#define CONFIG_TQ_KEY_DOUBLE_CLICK_MS 300
#endif
#ifndef CONFIG_TQ_KEY_POST_DOUBLE_CLICK_SUPPRESS_MS
#define CONFIG_TQ_KEY_POST_DOUBLE_CLICK_SUPPRESS_MS 450
#endif
#ifndef CONFIG_TQ_KEY_INPUT_POLL_MS
#define CONFIG_TQ_KEY_INPUT_POLL_MS 20
#endif
@@ -105,6 +109,7 @@ typedef struct {
int64_t inactive_since_ms;
int64_t press_start_ms;
int64_t click_deadline_ms;
int64_t suppress_until_ms;
} control_plane_key_state_t;
static const control_plane_key_config_t s_key_configs[] = {
@@ -312,6 +317,9 @@ static void control_plane_handle_debounced_transition(const control_plane_key_co
if (config->enable_double_click && state->click_pending && now_ms <= state->click_deadline_ms) {
state->click_pending = false;
state->debounce_pending = false;
state->press_start_ms = 0;
state->suppress_until_ms = now_ms + CONFIG_TQ_KEY_POST_DOUBLE_CLICK_SUPPRESS_MS;
control_plane_emit_key_event(config,
CONTROL_PLANE_KEY_EVENT_DOUBLE_CLICK,
level,
@@ -344,6 +352,11 @@ static void control_plane_process_key_timers(void)
continue;
}
if (state->suppress_until_ms > 0 && now_ms < state->suppress_until_ms) {
state->debounce_pending = false;
continue;
}
if (state->wait_inactive_before_press) {
const int level = gpio_get_level(config->gpio_num);
const bool pressed = control_plane_key_level_is_pressed(config, level);
@@ -469,6 +482,21 @@ static void control_plane_key_input_task(void *arg)
}
control_plane_key_state_t *state = &s_key_states[index];
if (state->suppress_until_ms > 0 && irq_event.timestamp_ms < state->suppress_until_ms) {
const bool pressed = control_plane_key_level_is_pressed(config, irq_event.level);
state->raw_level = irq_event.level;
state->debounce_pending = false;
if (!pressed) {
state->debounced_pressed = false;
}
ESP_LOGD(TAG,
"suppressed gpio change key=%s gpio=%d level=%d",
control_plane_key_id_name(config->key_id),
(int)irq_event.gpio_num,
irq_event.level);
continue;
}
state->raw_level = irq_event.level;
state->debounce_pending = true;
state->debounce_deadline_ms = irq_event.timestamp_ms + config->debounce_ms;
+78 -20
View File
@@ -55,6 +55,12 @@ typedef struct {
size_t step_count;
} lcd_direct_request_t;
typedef struct {
lcd_direct_icon_draw_t draw;
const lcd_direct_icon_t *icon;
lcd_direct_rle_run_t *loaded_runs;
} lcd_direct_prepared_icon_t;
typedef struct {
uint8_t cmd;
uint8_t data[16];
@@ -315,19 +321,18 @@ static lcd_direct_rle_run_t *lcd_direct_load_icon_runs(const lcd_direct_icon_t *
return runs;
}
static void lcd_direct_overlay_icons(uint16_t *pixel_buffer,
uint16_t row_start,
uint16_t row_count,
const lcd_direct_icon_draw_t *icons,
size_t icon_count)
static size_t lcd_direct_prepare_icons(const lcd_direct_icon_draw_t *icons,
size_t icon_count,
lcd_direct_prepared_icon_t *prepared,
size_t prepared_capacity)
{
if (pixel_buffer == NULL || icons == NULL || icon_count == 0U) {
return;
if (icons == NULL || icon_count == 0U || prepared == NULL || prepared_capacity == 0U) {
return 0;
}
const uint16_t row_end = row_start + row_count;
for (size_t icon_index = 0; icon_index < icon_count; ++icon_index) {
const lcd_direct_icon_draw_t *draw = &icons[icon_index];
size_t prepared_count = 0;
for (size_t i = 0; i < icon_count && prepared_count < prepared_capacity; ++i) {
const lcd_direct_icon_draw_t *draw = &icons[i];
const lcd_direct_icon_t *icon = lcd_direct_icon(draw->icon_id);
if (icon == NULL || icon->width == 0U || icon->height == 0U) {
continue;
@@ -337,11 +342,58 @@ static void lcd_direct_overlay_icons(uint16_t *pixel_buffer,
}
lcd_direct_rle_run_t *loaded_runs = NULL;
const lcd_direct_rle_run_t *runs = icon->runs;
if (runs == NULL) {
if (icon->runs == NULL) {
loaded_runs = lcd_direct_load_icon_runs(icon);
runs = loaded_runs;
if (loaded_runs == NULL) {
continue;
}
}
prepared[prepared_count] = (lcd_direct_prepared_icon_t) {
.draw = *draw,
.icon = icon,
.loaded_runs = loaded_runs,
};
prepared_count++;
}
return prepared_count;
}
static void lcd_direct_release_prepared_icons(lcd_direct_prepared_icon_t *prepared, size_t prepared_count)
{
if (prepared == NULL) {
return;
}
for (size_t i = 0; i < prepared_count; ++i) {
free(prepared[i].loaded_runs);
prepared[i].loaded_runs = NULL;
}
}
static void lcd_direct_overlay_icons(uint16_t *pixel_buffer,
uint16_t row_start,
uint16_t row_count,
const lcd_direct_prepared_icon_t *icons,
size_t icon_count)
{
if (pixel_buffer == NULL || icons == NULL || icon_count == 0U) {
return;
}
const uint16_t row_end = row_start + row_count;
for (size_t icon_index = 0; icon_index < icon_count; ++icon_index) {
const lcd_direct_icon_draw_t *draw = &icons[icon_index].draw;
const lcd_direct_icon_t *icon = icons[icon_index].icon;
if (icon == NULL || icon->width == 0U || icon->height == 0U) {
continue;
}
if (draw->x >= LCD_DIRECT_WIDTH || draw->y >= LCD_DIRECT_HEIGHT) {
continue;
}
const lcd_direct_rle_run_t *runs = icon->runs != NULL ? icon->runs : icons[icon_index].loaded_runs;
if (runs == NULL) {
continue;
}
@@ -358,7 +410,6 @@ static void lcd_direct_overlay_icons(uint16_t *pixel_buffer,
const uint16_t overlay_y0 = draw->y;
const uint16_t overlay_y1 = draw->y + draw_height;
if (overlay_y1 <= row_start || overlay_y0 >= row_end) {
free(loaded_runs);
continue;
}
@@ -387,13 +438,11 @@ static void lcd_direct_overlay_icons(uint16_t *pixel_buffer,
icon_pixel_pos = run_end;
}
}
free(loaded_runs);
}
}
static esp_err_t lcd_direct_draw_rle_memory_image(const lcd_direct_image_t *image,
const lcd_direct_icon_draw_t *icons,
const lcd_direct_prepared_icon_t *icons,
size_t icon_count)
{
ESP_RETURN_ON_FALSE(image != NULL && image->runs != NULL,
@@ -448,7 +497,7 @@ static esp_err_t lcd_direct_draw_rle_memory_image(const lcd_direct_image_t *imag
}
static esp_err_t lcd_direct_draw_rle_file_image(const lcd_direct_image_t *image,
const lcd_direct_icon_draw_t *icons,
const lcd_direct_prepared_icon_t *icons,
size_t icon_count)
{
ESP_RETURN_ON_FALSE(image != NULL && image->path != NULL,
@@ -547,10 +596,19 @@ static esp_err_t lcd_direct_draw_rle_image(const lcd_direct_image_t *image,
ESP_ERR_INVALID_ARG,
TAG,
"invalid image");
lcd_direct_prepared_icon_t prepared_icons[LCD_DIRECT_DEFAULT_ICON_COUNT];
size_t prepared_icon_count = lcd_direct_prepare_icons(icons,
icon_count,
prepared_icons,
sizeof(prepared_icons) / sizeof(prepared_icons[0]));
esp_err_t err = ESP_OK;
if (image->runs != NULL) {
return lcd_direct_draw_rle_memory_image(image, icons, icon_count);
err = lcd_direct_draw_rle_memory_image(image, prepared_icons, prepared_icon_count);
} else {
err = lcd_direct_draw_rle_file_image(image, prepared_icons, prepared_icon_count);
}
return lcd_direct_draw_rle_file_image(image, icons, icon_count);
lcd_direct_release_prepared_icons(prepared_icons, prepared_icon_count);
return err;
}
static esp_err_t lcd_direct_draw_asset_sequence_once(const lcd_direct_request_t *request)