fix(voice): preview generated png and recover shared spi display/print
This commit is contained in:
@@ -182,6 +182,11 @@ esp_err_t screen_preview_show_raster(const uint8_t *raster,
|
|||||||
uint32_t timeout_ms,
|
uint32_t timeout_ms,
|
||||||
char *err,
|
char *err,
|
||||||
size_t err_len);
|
size_t err_len);
|
||||||
|
esp_err_t screen_preview_show_png(const uint8_t *png,
|
||||||
|
size_t png_len,
|
||||||
|
uint32_t timeout_ms,
|
||||||
|
char *err,
|
||||||
|
size_t err_len);
|
||||||
|
|
||||||
// ---------- printer_protocol ----------
|
// ---------- printer_protocol ----------
|
||||||
typedef enum {
|
typedef enum {
|
||||||
|
|||||||
@@ -11,3 +11,12 @@ esp_err_t screen_preview_show_raster(const uint8_t *raster,
|
|||||||
{
|
{
|
||||||
return platform_display_show_raster_1bpp(raster, raster_len, width, height, timeout_ms, err, err_len);
|
return platform_display_show_raster_1bpp(raster, raster_len, width, height, timeout_ms, err, err_len);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
esp_err_t screen_preview_show_png(const uint8_t *png,
|
||||||
|
size_t png_len,
|
||||||
|
uint32_t timeout_ms,
|
||||||
|
char *err,
|
||||||
|
size_t err_len)
|
||||||
|
{
|
||||||
|
return platform_display_show_png(png, png_len, timeout_ms, err, err_len);
|
||||||
|
}
|
||||||
|
|||||||
@@ -17,8 +17,9 @@ static const char *TAG = "voice_interaction";
|
|||||||
#define VOICE_IMAGE_MARKER_REPEAT_SUPPRESS_MS 45000
|
#define VOICE_IMAGE_MARKER_REPEAT_SUPPRESS_MS 45000
|
||||||
#define VOICE_IMAGE_PRINT_THRESHOLD 160
|
#define VOICE_IMAGE_PRINT_THRESHOLD 160
|
||||||
#define VOICE_IMAGE_PRINT_MAX_HEIGHT 2200
|
#define VOICE_IMAGE_PRINT_MAX_HEIGHT 2200
|
||||||
|
#define VOICE_IMAGE_PREVIEW_TIMEOUT_MS 200
|
||||||
#define VOICE_IMAGE_MARKER_TEMPLATE \
|
#define VOICE_IMAGE_MARKER_TEMPLATE \
|
||||||
"%s,黑白线稿风格,白色背景,主体居中,边缘清晰,细节简洁,高对比,避免大面积阴影和灰度渐变,适配热敏打印机打印。"
|
"%s,线稿风格,白色背景,边缘清晰,细节简洁,高对比,避免大面积阴影和灰度渐变,适配热敏打印机打印。"
|
||||||
#define VOICE_IMAGE_MARKER_TEMPLATE_FALLBACK_SUBJECT "简洁卡通图案"
|
#define VOICE_IMAGE_MARKER_TEMPLATE_FALLBACK_SUBJECT "简洁卡通图案"
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
@@ -228,6 +229,38 @@ static void voice_build_marker_image_prompt(const char *subject,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void voice_try_preview_marker_png(const voice_image_generation_task_arg_t *task_arg,
|
||||||
|
const uint8_t *png,
|
||||||
|
size_t png_len) {
|
||||||
|
if (task_arg == NULL || png == NULL || png_len == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
char preview_err[96] = {0};
|
||||||
|
esp_err_t preview_rc = screen_preview_show_png(png,
|
||||||
|
png_len,
|
||||||
|
VOICE_IMAGE_PREVIEW_TIMEOUT_MS,
|
||||||
|
preview_err,
|
||||||
|
sizeof(preview_err));
|
||||||
|
if (preview_rc == ESP_OK) {
|
||||||
|
ESP_LOGI(TAG,
|
||||||
|
"[stage] marker_image_preview_ok: dialog_id=%s png_bytes=%u",
|
||||||
|
task_arg->dialog_id[0] != '\0' ? task_arg->dialog_id : "-",
|
||||||
|
(unsigned)png_len);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (preview_rc == ESP_ERR_NOT_SUPPORTED) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ESP_LOGW(TAG,
|
||||||
|
"[stage] marker_image_preview_failed: dialog_id=%s rc=0x%x msg=%s",
|
||||||
|
task_arg->dialog_id[0] != '\0' ? task_arg->dialog_id : "-",
|
||||||
|
(unsigned)preview_rc,
|
||||||
|
preview_err[0] != '\0' ? preview_err : "preview failed");
|
||||||
|
}
|
||||||
|
|
||||||
static esp_err_t voice_submit_marker_generated_image(const voice_image_generation_task_arg_t *task_arg,
|
static esp_err_t voice_submit_marker_generated_image(const voice_image_generation_task_arg_t *task_arg,
|
||||||
const image_generation_result_t *result,
|
const image_generation_result_t *result,
|
||||||
char *err,
|
char *err,
|
||||||
@@ -237,6 +270,8 @@ static esp_err_t voice_submit_marker_generated_image(const voice_image_generatio
|
|||||||
return ESP_ERR_INVALID_ARG;
|
return ESP_ERR_INVALID_ARG;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
voice_try_preview_marker_png(task_arg, result->png, result->png_len);
|
||||||
|
|
||||||
uint16_t raster_width = 0;
|
uint16_t raster_width = 0;
|
||||||
uint16_t raster_height = 0;
|
uint16_t raster_height = 0;
|
||||||
uint8_t *raster = NULL;
|
uint8_t *raster = NULL;
|
||||||
@@ -280,11 +315,15 @@ static esp_err_t voice_submit_marker_generated_image(const voice_image_generatio
|
|||||||
|
|
||||||
uint32_t job_id = 0;
|
uint32_t job_id = 0;
|
||||||
char submit_err[128] = {0};
|
char submit_err[128] = {0};
|
||||||
esp_err_t submit_rc = printer_protocol_submit_raster_job(raster,
|
printer_print_options_t print_opt = {
|
||||||
|
.direct_ignore_precheck = true,
|
||||||
|
};
|
||||||
|
esp_err_t submit_rc = printer_protocol_submit_raster_job_ex(raster,
|
||||||
raster_len,
|
raster_len,
|
||||||
raster_width,
|
raster_width,
|
||||||
raster_height,
|
raster_height,
|
||||||
NULL,
|
NULL,
|
||||||
|
&print_opt,
|
||||||
&job_id,
|
&job_id,
|
||||||
submit_err,
|
submit_err,
|
||||||
sizeof(submit_err));
|
sizeof(submit_err));
|
||||||
@@ -371,7 +410,6 @@ static void voice_image_generation_task(void *arg) {
|
|||||||
gen_err[0] != '\0' ? gen_err : "image generation failed");
|
gen_err[0] != '\0' ? gen_err : "image generation failed");
|
||||||
}
|
}
|
||||||
|
|
||||||
printer_protocol_status_poll_pause_release(&status_poll_pause_token);
|
|
||||||
image_generation_result_free(&result);
|
image_generation_result_free(&result);
|
||||||
voice_marker_image_generation_release();
|
voice_marker_image_generation_release();
|
||||||
image_generation_schedule_prewarm();
|
image_generation_schedule_prewarm();
|
||||||
|
|||||||
@@ -104,6 +104,11 @@ esp_err_t platform_display_show_raster_1bpp(const uint8_t *raster,
|
|||||||
uint32_t timeout_ms,
|
uint32_t timeout_ms,
|
||||||
char *err,
|
char *err,
|
||||||
size_t err_len);
|
size_t err_len);
|
||||||
|
esp_err_t platform_display_show_png(const uint8_t *png,
|
||||||
|
size_t png_len,
|
||||||
|
uint32_t timeout_ms,
|
||||||
|
char *err,
|
||||||
|
size_t err_len);
|
||||||
void platform_display_deinit(void);
|
void platform_display_deinit(void);
|
||||||
|
|
||||||
// ---------- voice_audio ----------
|
// ---------- voice_audio ----------
|
||||||
|
|||||||
@@ -5,6 +5,14 @@
|
|||||||
|
|
||||||
#include "esp_err.h"
|
#include "esp_err.h"
|
||||||
|
|
||||||
|
esp_err_t platform_lcd_decode_png_rgb565(const uint8_t *png,
|
||||||
|
size_t png_len,
|
||||||
|
uint16_t **out_pixels,
|
||||||
|
uint16_t *out_width,
|
||||||
|
uint16_t *out_height,
|
||||||
|
char *err,
|
||||||
|
size_t err_len);
|
||||||
|
|
||||||
esp_err_t platform_lcd_decode_demo_png(uint16_t **out_pixels,
|
esp_err_t platform_lcd_decode_demo_png(uint16_t **out_pixels,
|
||||||
uint16_t *out_width,
|
uint16_t *out_width,
|
||||||
uint16_t *out_height,
|
uint16_t *out_height,
|
||||||
|
|||||||
@@ -18,6 +18,11 @@ esp_err_t lcd_module_show_raster_1bpp(const uint8_t *raster,
|
|||||||
uint32_t timeout_ms,
|
uint32_t timeout_ms,
|
||||||
char *err,
|
char *err,
|
||||||
size_t err_len);
|
size_t err_len);
|
||||||
|
esp_err_t lcd_module_show_png(const uint8_t *png,
|
||||||
|
size_t png_len,
|
||||||
|
uint32_t timeout_ms,
|
||||||
|
char *err,
|
||||||
|
size_t err_len);
|
||||||
void lcd_module_deinit(void);
|
void lcd_module_deinit(void);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
|||||||
@@ -162,6 +162,14 @@ static esp_err_t config_input_pin(int gpio_num, bool pull_up, const char *name)
|
|||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static esp_err_t ensure_shared_shift_pins_gpio_locked(void) {
|
||||||
|
esp_err_t err = config_output_pin(CONFIG_TQ_SPI_SHARED_MOSI_PIN, 0, "print_mosi");
|
||||||
|
if (err != ESP_OK) {
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
return config_output_pin(CONFIG_TQ_SPI_SHARED_CLK_PIN, 0, "print_clk");
|
||||||
|
}
|
||||||
|
|
||||||
static void set_stb_level_locked(int level) {
|
static void set_stb_level_locked(int level) {
|
||||||
int out_level = level ? strobe_active_level_locked() : strobe_idle_level_locked();
|
int out_level = level ? strobe_active_level_locked() : strobe_idle_level_locked();
|
||||||
set_gpio_level_if_valid(CONFIG_TQ_PRINT_STB_12_PIN, out_level);
|
set_gpio_level_if_valid(CONFIG_TQ_PRINT_STB_12_PIN, out_level);
|
||||||
@@ -507,11 +515,7 @@ esp_err_t platform_direct_printer_init(void) {
|
|||||||
if (err != ESP_OK) {
|
if (err != ESP_OK) {
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
err = config_output_pin(CONFIG_TQ_SPI_SHARED_MOSI_PIN, 0, "print_mosi");
|
err = ensure_shared_shift_pins_gpio_locked();
|
||||||
if (err != ESP_OK) {
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
err = config_output_pin(CONFIG_TQ_SPI_SHARED_CLK_PIN, 0, "print_clk");
|
|
||||||
if (err != ESP_OK) {
|
if (err != ESP_OK) {
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
@@ -598,6 +602,11 @@ esp_err_t platform_direct_printer_connect(uint32_t timeout_ms) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!s_state.connected) {
|
if (!s_state.connected) {
|
||||||
|
err = ensure_shared_shift_pins_gpio_locked();
|
||||||
|
if (err != ESP_OK) {
|
||||||
|
xSemaphoreGive(s_state.lock);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
set_gpio_level_if_valid(CONFIG_TQ_KEY_PRINT_PIN, boost_on_level_locked());
|
set_gpio_level_if_valid(CONFIG_TQ_KEY_PRINT_PIN, boost_on_level_locked());
|
||||||
vTaskDelay(pdMS_TO_TICKS(10));
|
vTaskDelay(pdMS_TO_TICKS(10));
|
||||||
safe_drive_off_locked(true);
|
safe_drive_off_locked(true);
|
||||||
@@ -837,6 +846,14 @@ esp_err_t platform_direct_printer_print(const platform_direct_print_request_t *r
|
|||||||
return ESP_ERR_INVALID_STATE;
|
return ESP_ERR_INVALID_STATE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
esp_err_t rc = ensure_shared_shift_pins_gpio_locked();
|
||||||
|
if (rc != ESP_OK) {
|
||||||
|
safe_drive_off_locked(true);
|
||||||
|
xSemaphoreGive(s_state.lock);
|
||||||
|
write_err(err, err_len, "direct printer gpio setup failed");
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
uint16_t strobe_on_us = (request->strobe_on_time_us > 0)
|
uint16_t strobe_on_us = (request->strobe_on_time_us > 0)
|
||||||
? request->strobe_on_time_us
|
? request->strobe_on_time_us
|
||||||
: runtime_policy_direct_printer_strobe_on_us();
|
: runtime_policy_direct_printer_strobe_on_us();
|
||||||
@@ -863,7 +880,7 @@ esp_err_t platform_direct_printer_print(const platform_direct_print_request_t *r
|
|||||||
steps_per_line = s_state.debug.override_steps_per_line;
|
steps_per_line = s_state.debug.override_steps_per_line;
|
||||||
}
|
}
|
||||||
|
|
||||||
esp_err_t rc = ESP_OK;
|
rc = ESP_OK;
|
||||||
if (!request->ignore_precheck) {
|
if (!request->ignore_precheck) {
|
||||||
rc = precheck_before_print_locked(err, err_len);
|
rc = precheck_before_print_locked(err, err_len);
|
||||||
if (rc != ESP_OK) {
|
if (rc != ESP_OK) {
|
||||||
|
|||||||
@@ -23,7 +23,9 @@ static void lcd_fill_err(char *err, size_t err_len, const char *msg)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
esp_err_t platform_lcd_decode_demo_png(uint16_t **out_pixels,
|
esp_err_t platform_lcd_decode_png_rgb565(const uint8_t *png,
|
||||||
|
size_t png_len,
|
||||||
|
uint16_t **out_pixels,
|
||||||
uint16_t *out_width,
|
uint16_t *out_width,
|
||||||
uint16_t *out_height,
|
uint16_t *out_height,
|
||||||
char *err,
|
char *err,
|
||||||
@@ -35,22 +37,20 @@ esp_err_t platform_lcd_decode_demo_png(uint16_t **out_pixels,
|
|||||||
ESP_ERR_INVALID_ARG,
|
ESP_ERR_INVALID_ARG,
|
||||||
TAG,
|
TAG,
|
||||||
"invalid output args");
|
"invalid output args");
|
||||||
|
ESP_RETURN_ON_FALSE(png != NULL && png_len > 0, ESP_ERR_INVALID_ARG, TAG, "invalid png data");
|
||||||
*out_pixels = NULL;
|
*out_pixels = NULL;
|
||||||
*out_width = 0;
|
*out_width = 0;
|
||||||
*out_height = 0;
|
*out_height = 0;
|
||||||
|
|
||||||
const size_t png_len = (size_t)(lcd_demo_png_end - lcd_demo_png_start);
|
|
||||||
ESP_RETURN_ON_FALSE(png_len > 0, ESP_ERR_INVALID_SIZE, TAG, "empty png data");
|
|
||||||
|
|
||||||
png_image image;
|
png_image image;
|
||||||
memset(&image, 0, sizeof(image));
|
memset(&image, 0, sizeof(image));
|
||||||
image.version = PNG_IMAGE_VERSION;
|
image.version = PNG_IMAGE_VERSION;
|
||||||
|
|
||||||
ESP_RETURN_ON_FALSE(png_image_begin_read_from_memory(&image, lcd_demo_png_start, png_len),
|
if (!png_image_begin_read_from_memory(&image, png, png_len)) {
|
||||||
ESP_FAIL,
|
const char *png_err = image.message[0] != '\0' ? image.message : "png header decode failed";
|
||||||
TAG,
|
lcd_fill_err(err, err_len, png_err);
|
||||||
"png header decode failed: %s",
|
return ESP_FAIL;
|
||||||
image.message);
|
}
|
||||||
ESP_GOTO_ON_FALSE(image.width > 0 && image.height > 0, ESP_ERR_INVALID_SIZE, fail, TAG, "invalid png size");
|
ESP_GOTO_ON_FALSE(image.width > 0 && image.height > 0, ESP_ERR_INVALID_SIZE, fail, TAG, "invalid png size");
|
||||||
ESP_GOTO_ON_FALSE(image.width <= UINT16_MAX && image.height <= UINT16_MAX,
|
ESP_GOTO_ON_FALSE(image.width <= UINT16_MAX && image.height <= UINT16_MAX,
|
||||||
ESP_ERR_INVALID_SIZE,
|
ESP_ERR_INVALID_SIZE,
|
||||||
@@ -59,21 +59,21 @@ esp_err_t platform_lcd_decode_demo_png(uint16_t **out_pixels,
|
|||||||
"png dimensions too large");
|
"png dimensions too large");
|
||||||
ESP_GOTO_ON_FALSE(image.width <= SIZE_MAX / image.height, ESP_ERR_INVALID_SIZE, fail, TAG, "png too large");
|
ESP_GOTO_ON_FALSE(image.width <= SIZE_MAX / image.height, ESP_ERR_INVALID_SIZE, fail, TAG, "png too large");
|
||||||
|
|
||||||
image.format = PNG_FORMAT_RGB;
|
image.format = PNG_FORMAT_RGBA;
|
||||||
png_alloc_size_t rgb_size = PNG_IMAGE_SIZE(image);
|
png_alloc_size_t rgba_size = PNG_IMAGE_SIZE(image);
|
||||||
ESP_GOTO_ON_FALSE(rgb_size > 0, ESP_ERR_INVALID_SIZE, fail, TAG, "png output size invalid");
|
ESP_GOTO_ON_FALSE(rgba_size > 0, ESP_ERR_INVALID_SIZE, fail, TAG, "png output size invalid");
|
||||||
|
|
||||||
uint8_t *rgb = (uint8_t *)heap_caps_malloc((size_t)rgb_size, MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT);
|
uint8_t *rgba = (uint8_t *)heap_caps_malloc((size_t)rgba_size, MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT);
|
||||||
if (rgb == NULL) {
|
if (rgba == NULL) {
|
||||||
rgb = (uint8_t *)heap_caps_malloc((size_t)rgb_size, MALLOC_CAP_8BIT);
|
rgba = (uint8_t *)heap_caps_malloc((size_t)rgba_size, MALLOC_CAP_8BIT);
|
||||||
}
|
}
|
||||||
ESP_GOTO_ON_FALSE(rgb != NULL, ESP_ERR_NO_MEM, fail, TAG, "alloc rgb buffer failed");
|
ESP_GOTO_ON_FALSE(rgba != NULL, ESP_ERR_NO_MEM, fail, TAG, "alloc rgba buffer failed");
|
||||||
|
|
||||||
png_alloc_size_t stride = PNG_IMAGE_ROW_STRIDE(image);
|
png_alloc_size_t stride = PNG_IMAGE_ROW_STRIDE(image);
|
||||||
if (!png_image_finish_read(&image, NULL, rgb, stride, NULL)) {
|
if (!png_image_finish_read(&image, NULL, rgba, stride, NULL)) {
|
||||||
const char *png_err = image.message[0] != '\0' ? image.message : "png decode failed";
|
const char *png_err = image.message[0] != '\0' ? image.message : "png decode failed";
|
||||||
lcd_fill_err(err, err_len, png_err);
|
lcd_fill_err(err, err_len, png_err);
|
||||||
heap_caps_free(rgb);
|
heap_caps_free(rgba);
|
||||||
png_image_free(&image);
|
png_image_free(&image);
|
||||||
return ESP_FAIL;
|
return ESP_FAIL;
|
||||||
}
|
}
|
||||||
@@ -87,16 +87,25 @@ esp_err_t platform_lcd_decode_demo_png(uint16_t **out_pixels,
|
|||||||
}
|
}
|
||||||
if (pixels == NULL) {
|
if (pixels == NULL) {
|
||||||
lcd_fill_err(err, err_len, "alloc rgb565 buffer failed");
|
lcd_fill_err(err, err_len, "alloc rgb565 buffer failed");
|
||||||
heap_caps_free(rgb);
|
heap_caps_free(rgba);
|
||||||
return ESP_ERR_NO_MEM;
|
return ESP_ERR_NO_MEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (size_t i = 0; i < pixel_count; ++i) {
|
for (size_t i = 0; i < pixel_count; ++i) {
|
||||||
const size_t base = i * 3u;
|
const size_t base = i * 4u;
|
||||||
lv_color_t color = lv_color_make(rgb[base], rgb[base + 1u], rgb[base + 2u]);
|
uint8_t r = rgba[base];
|
||||||
|
uint8_t g = rgba[base + 1u];
|
||||||
|
uint8_t b = rgba[base + 2u];
|
||||||
|
uint8_t a = rgba[base + 3u];
|
||||||
|
if (a < 255u) {
|
||||||
|
r = (uint8_t)((((uint32_t)r * (uint32_t)a) + (255u * (255u - (uint32_t)a)) + 127u) / 255u);
|
||||||
|
g = (uint8_t)((((uint32_t)g * (uint32_t)a) + (255u * (255u - (uint32_t)a)) + 127u) / 255u);
|
||||||
|
b = (uint8_t)((((uint32_t)b * (uint32_t)a) + (255u * (255u - (uint32_t)a)) + 127u) / 255u);
|
||||||
|
}
|
||||||
|
lv_color_t color = lv_color_make(r, g, b);
|
||||||
pixels[i] = (uint16_t)color.full;
|
pixels[i] = (uint16_t)color.full;
|
||||||
}
|
}
|
||||||
heap_caps_free(rgb);
|
heap_caps_free(rgba);
|
||||||
|
|
||||||
*out_pixels = pixels;
|
*out_pixels = pixels;
|
||||||
*out_width = (uint16_t)image.width;
|
*out_width = (uint16_t)image.width;
|
||||||
@@ -111,3 +120,20 @@ fail:
|
|||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
esp_err_t platform_lcd_decode_demo_png(uint16_t **out_pixels,
|
||||||
|
uint16_t *out_width,
|
||||||
|
uint16_t *out_height,
|
||||||
|
char *err,
|
||||||
|
size_t err_len)
|
||||||
|
{
|
||||||
|
const size_t png_len = (size_t)(lcd_demo_png_end - lcd_demo_png_start);
|
||||||
|
ESP_RETURN_ON_FALSE(png_len > 0, ESP_ERR_INVALID_SIZE, TAG, "empty png data");
|
||||||
|
return platform_lcd_decode_png_rgb565(lcd_demo_png_start,
|
||||||
|
png_len,
|
||||||
|
out_pixels,
|
||||||
|
out_width,
|
||||||
|
out_height,
|
||||||
|
err,
|
||||||
|
err_len);
|
||||||
|
}
|
||||||
|
|||||||
@@ -187,6 +187,18 @@ static void lcd_free_lvgl_buffers(void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static esp_err_t lcd_recover_panel_for_shared_spi(void)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Printer bit-bang path reconfigures shared MOSI/CLK as GPIO.
|
||||||
|
* Re-initialize panel before each preview draw to restore SPI pin routing.
|
||||||
|
*/
|
||||||
|
if (s_lcd.initialized) {
|
||||||
|
lcd_module_deinit();
|
||||||
|
}
|
||||||
|
return lcd_module_init();
|
||||||
|
}
|
||||||
|
|
||||||
static void lcd_lvgl_flush_cb(lv_disp_drv_t *disp_drv, const lv_area_t *area, lv_color_t *color_map)
|
static void lcd_lvgl_flush_cb(lv_disp_drv_t *disp_drv, const lv_area_t *area, lv_color_t *color_map)
|
||||||
{
|
{
|
||||||
st7789p3_handle_t panel = (st7789p3_handle_t)disp_drv->user_data;
|
st7789p3_handle_t panel = (st7789p3_handle_t)disp_drv->user_data;
|
||||||
@@ -346,6 +358,101 @@ static esp_err_t lcd_render_raster_to_rgb565(const uint8_t *raster,
|
|||||||
return ESP_OK;
|
return ESP_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static esp_err_t lcd_scale_rgb565_to_preview(const uint16_t *src_pixels,
|
||||||
|
uint16_t src_w,
|
||||||
|
uint16_t src_h,
|
||||||
|
uint16_t **out_pixels,
|
||||||
|
uint16_t *out_w,
|
||||||
|
uint16_t *out_h,
|
||||||
|
char *err,
|
||||||
|
size_t err_len)
|
||||||
|
{
|
||||||
|
if (src_pixels == NULL || src_w == 0 || src_h == 0 || out_pixels == NULL || out_w == NULL || out_h == NULL) {
|
||||||
|
lcd_fill_err(err, err_len, "invalid rgb565 image");
|
||||||
|
return ESP_ERR_INVALID_ARG;
|
||||||
|
}
|
||||||
|
|
||||||
|
*out_pixels = NULL;
|
||||||
|
*out_w = 0;
|
||||||
|
*out_h = 0;
|
||||||
|
lcd_calc_preview_size(src_w, src_h, out_w, out_h);
|
||||||
|
size_t pixel_count = (size_t)(*out_w) * (size_t)(*out_h);
|
||||||
|
if (pixel_count == 0 || pixel_count > SIZE_MAX / sizeof(uint16_t)) {
|
||||||
|
lcd_fill_err(err, err_len, "preview size invalid");
|
||||||
|
return ESP_ERR_INVALID_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t *preview = (uint16_t *)heap_caps_malloc(pixel_count * sizeof(uint16_t),
|
||||||
|
MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT);
|
||||||
|
if (preview == NULL) {
|
||||||
|
preview = (uint16_t *)heap_caps_malloc(pixel_count * sizeof(uint16_t), MALLOC_CAP_8BIT);
|
||||||
|
}
|
||||||
|
if (preview == NULL) {
|
||||||
|
lcd_fill_err(err, err_len, "no memory");
|
||||||
|
return ESP_ERR_NO_MEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*out_w == src_w && *out_h == src_h) {
|
||||||
|
memcpy(preview, src_pixels, pixel_count * sizeof(uint16_t));
|
||||||
|
*out_pixels = preview;
|
||||||
|
return ESP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (uint16_t y = 0; y < *out_h; ++y) {
|
||||||
|
uint16_t src_y = (uint16_t)(((uint32_t)y * src_h) / (*out_h));
|
||||||
|
size_t src_row = (size_t)src_y * src_w;
|
||||||
|
size_t dst_row = (size_t)y * (*out_w);
|
||||||
|
for (uint16_t x = 0; x < *out_w; ++x) {
|
||||||
|
uint16_t src_x = (uint16_t)(((uint32_t)x * src_w) / (*out_w));
|
||||||
|
preview[dst_row + x] = src_pixels[src_row + src_x];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
*out_pixels = preview;
|
||||||
|
return ESP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static esp_err_t lcd_apply_preview_locked(lv_color_t bg_color, char *err, size_t err_len)
|
||||||
|
{
|
||||||
|
if (s_lcd.panel == NULL || s_lcd.preview_pixels == NULL) {
|
||||||
|
lcd_fill_err(err, err_len, "display panel not ready");
|
||||||
|
return ESP_ERR_INVALID_STATE;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t preview_w = s_lcd.preview_dsc.header.w;
|
||||||
|
uint16_t preview_h = s_lcd.preview_dsc.header.h;
|
||||||
|
if (preview_w == 0 || preview_h == 0 || preview_w > LCD_PANEL_H_RES || preview_h > LCD_PANEL_V_RES) {
|
||||||
|
lcd_fill_err(err, err_len, "invalid preview size");
|
||||||
|
return ESP_ERR_INVALID_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
esp_err_t draw_rc = st7789p3_fill_color(s_lcd.panel, (uint16_t)bg_color.full);
|
||||||
|
if (draw_rc != ESP_OK) {
|
||||||
|
lcd_fill_err(err, err_len, "display clear failed");
|
||||||
|
return draw_rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t x = (uint16_t)((LCD_PANEL_H_RES - preview_w) / 2u);
|
||||||
|
uint16_t y = (uint16_t)((LCD_PANEL_V_RES - preview_h) / 2u);
|
||||||
|
draw_rc = st7789p3_draw_bitmap(s_lcd.panel,
|
||||||
|
x,
|
||||||
|
y,
|
||||||
|
(uint16_t)(x + preview_w),
|
||||||
|
(uint16_t)(y + preview_h),
|
||||||
|
s_lcd.preview_pixels);
|
||||||
|
if (draw_rc != ESP_OK) {
|
||||||
|
lcd_fill_err(err, err_len, "display draw failed");
|
||||||
|
return draw_rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
ESP_LOGI(TAG, "preview drawn directly: size=%ux%u offset=(%u,%u)",
|
||||||
|
(unsigned)preview_w,
|
||||||
|
(unsigned)preview_h,
|
||||||
|
(unsigned)x,
|
||||||
|
(unsigned)y);
|
||||||
|
return ESP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
void lcd_module_deinit(void)
|
void lcd_module_deinit(void)
|
||||||
{
|
{
|
||||||
#if CONFIG_TQ_SCREEN_ENABLE
|
#if CONFIG_TQ_SCREEN_ENABLE
|
||||||
@@ -474,7 +581,7 @@ esp_err_t lcd_module_show_raster_1bpp(const uint8_t *raster,
|
|||||||
#if !CONFIG_TQ_SCREEN_ENABLE
|
#if !CONFIG_TQ_SCREEN_ENABLE
|
||||||
return ESP_ERR_NOT_SUPPORTED;
|
return ESP_ERR_NOT_SUPPORTED;
|
||||||
#else
|
#else
|
||||||
ESP_RETURN_ON_ERROR(lcd_module_init(), TAG, "display init failed");
|
ESP_RETURN_ON_ERROR(lcd_recover_panel_for_shared_spi(), TAG, "display init failed");
|
||||||
|
|
||||||
if (timeout_ms == 0) {
|
if (timeout_ms == 0) {
|
||||||
timeout_ms = LCD_PREVIEW_TIMEOUT_MS_DEFAULT;
|
timeout_ms = LCD_PREVIEW_TIMEOUT_MS_DEFAULT;
|
||||||
@@ -515,16 +622,79 @@ esp_err_t lcd_module_show_raster_1bpp(const uint8_t *raster,
|
|||||||
s_lcd.preview_dsc.data_size = (uint32_t)((size_t)preview_w * preview_h * sizeof(uint16_t));
|
s_lcd.preview_dsc.data_size = (uint32_t)((size_t)preview_w * preview_h * sizeof(uint16_t));
|
||||||
s_lcd.preview_dsc.data = (const uint8_t *)s_lcd.preview_pixels;
|
s_lcd.preview_dsc.data = (const uint8_t *)s_lcd.preview_pixels;
|
||||||
|
|
||||||
lv_obj_t *screen = lv_scr_act();
|
esp_err_t draw_err = lcd_apply_preview_locked(lv_color_white(), err, err_len);
|
||||||
lv_obj_set_style_bg_color(screen, lv_color_white(), LV_PART_MAIN);
|
|
||||||
lv_obj_set_style_bg_opa(screen, LV_OPA_COVER, LV_PART_MAIN);
|
|
||||||
lv_img_set_src(s_lcd.preview_img, &s_lcd.preview_dsc);
|
|
||||||
lv_obj_clear_flag(s_lcd.preview_img, LV_OBJ_FLAG_HIDDEN);
|
|
||||||
lv_obj_center(s_lcd.preview_img);
|
|
||||||
lv_refr_now(s_lcd.lv_disp);
|
|
||||||
|
|
||||||
lcd_lock_give();
|
lcd_lock_give();
|
||||||
return ESP_OK;
|
return draw_err;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
esp_err_t lcd_module_show_png(const uint8_t *png,
|
||||||
|
size_t png_len,
|
||||||
|
uint32_t timeout_ms,
|
||||||
|
char *err,
|
||||||
|
size_t err_len)
|
||||||
|
{
|
||||||
|
#if !CONFIG_TQ_SCREEN_ENABLE
|
||||||
|
return ESP_ERR_NOT_SUPPORTED;
|
||||||
|
#else
|
||||||
|
ESP_RETURN_ON_ERROR(lcd_recover_panel_for_shared_spi(), TAG, "display init failed");
|
||||||
|
|
||||||
|
if (timeout_ms == 0) {
|
||||||
|
timeout_ms = LCD_PREVIEW_TIMEOUT_MS_DEFAULT;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t *src_pixels = NULL;
|
||||||
|
uint16_t src_w = 0;
|
||||||
|
uint16_t src_h = 0;
|
||||||
|
esp_err_t decode_err = platform_lcd_decode_png_rgb565(png,
|
||||||
|
png_len,
|
||||||
|
&src_pixels,
|
||||||
|
&src_w,
|
||||||
|
&src_h,
|
||||||
|
err,
|
||||||
|
err_len);
|
||||||
|
if (decode_err != ESP_OK) {
|
||||||
|
return decode_err;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t *preview_pixels = NULL;
|
||||||
|
uint16_t preview_w = 0;
|
||||||
|
uint16_t preview_h = 0;
|
||||||
|
esp_err_t scale_err = lcd_scale_rgb565_to_preview(src_pixels,
|
||||||
|
src_w,
|
||||||
|
src_h,
|
||||||
|
&preview_pixels,
|
||||||
|
&preview_w,
|
||||||
|
&preview_h,
|
||||||
|
err,
|
||||||
|
err_len);
|
||||||
|
heap_caps_free(src_pixels);
|
||||||
|
if (scale_err != ESP_OK) {
|
||||||
|
return scale_err;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!lcd_lock_take(timeout_ms)) {
|
||||||
|
heap_caps_free(preview_pixels);
|
||||||
|
lcd_fill_err(err, err_len, "display lock timeout");
|
||||||
|
return ESP_ERR_TIMEOUT;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (s_lcd.preview_pixels != NULL) {
|
||||||
|
heap_caps_free(s_lcd.preview_pixels);
|
||||||
|
}
|
||||||
|
s_lcd.preview_pixels = preview_pixels;
|
||||||
|
|
||||||
|
memset(&s_lcd.preview_dsc, 0, sizeof(s_lcd.preview_dsc));
|
||||||
|
s_lcd.preview_dsc.header.always_zero = 0;
|
||||||
|
s_lcd.preview_dsc.header.w = preview_w;
|
||||||
|
s_lcd.preview_dsc.header.h = preview_h;
|
||||||
|
s_lcd.preview_dsc.header.cf = LV_IMG_CF_TRUE_COLOR;
|
||||||
|
s_lcd.preview_dsc.data_size = (uint32_t)((size_t)preview_w * preview_h * sizeof(uint16_t));
|
||||||
|
s_lcd.preview_dsc.data = (const uint8_t *)s_lcd.preview_pixels;
|
||||||
|
|
||||||
|
esp_err_t draw_err = lcd_apply_preview_locked(lv_color_white(), err, err_len);
|
||||||
|
lcd_lock_give();
|
||||||
|
return draw_err;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -533,7 +703,7 @@ esp_err_t lcd_module_start_demo(void)
|
|||||||
#if !CONFIG_TQ_SCREEN_ENABLE
|
#if !CONFIG_TQ_SCREEN_ENABLE
|
||||||
return ESP_ERR_NOT_SUPPORTED;
|
return ESP_ERR_NOT_SUPPORTED;
|
||||||
#else
|
#else
|
||||||
ESP_RETURN_ON_ERROR(lcd_module_init(), TAG, "display init failed");
|
ESP_RETURN_ON_ERROR(lcd_recover_panel_for_shared_spi(), TAG, "display init failed");
|
||||||
if (!lcd_lock_take(LCD_LOCK_TIMEOUT_MS)) {
|
if (!lcd_lock_take(LCD_LOCK_TIMEOUT_MS)) {
|
||||||
return ESP_ERR_TIMEOUT;
|
return ESP_ERR_TIMEOUT;
|
||||||
}
|
}
|
||||||
@@ -566,15 +736,12 @@ esp_err_t lcd_module_start_demo(void)
|
|||||||
s_lcd.preview_dsc.data_size = (uint32_t)((size_t)demo_w * demo_h * sizeof(uint16_t));
|
s_lcd.preview_dsc.data_size = (uint32_t)((size_t)demo_w * demo_h * sizeof(uint16_t));
|
||||||
s_lcd.preview_dsc.data = (const uint8_t *)s_lcd.preview_pixels;
|
s_lcd.preview_dsc.data = (const uint8_t *)s_lcd.preview_pixels;
|
||||||
|
|
||||||
lv_obj_t *screen = lv_scr_act();
|
esp_err_t draw_err = lcd_apply_preview_locked(lv_color_black(), decode_err, sizeof(decode_err));
|
||||||
lv_obj_set_style_bg_color(screen, lv_color_black(), LV_PART_MAIN);
|
|
||||||
lv_obj_set_style_bg_opa(screen, LV_OPA_COVER, LV_PART_MAIN);
|
|
||||||
|
|
||||||
lv_img_set_src(s_lcd.preview_img, &s_lcd.preview_dsc);
|
|
||||||
lv_obj_clear_flag(s_lcd.preview_img, LV_OBJ_FLAG_HIDDEN);
|
|
||||||
lv_obj_center(s_lcd.preview_img);
|
|
||||||
lv_refr_now(s_lcd.lv_disp);
|
|
||||||
lcd_lock_give();
|
lcd_lock_give();
|
||||||
|
if (draw_err != ESP_OK) {
|
||||||
|
ESP_LOGW(TAG, "demo draw failed: rc=0x%x msg=%s", (unsigned)draw_err, decode_err);
|
||||||
|
return draw_err;
|
||||||
|
}
|
||||||
return ESP_OK;
|
return ESP_OK;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,3 +27,12 @@ esp_err_t platform_display_show_raster_1bpp(const uint8_t *raster,
|
|||||||
{
|
{
|
||||||
return lcd_module_show_raster_1bpp(raster, raster_len, width, height, timeout_ms, err, err_len);
|
return lcd_module_show_raster_1bpp(raster, raster_len, width, height, timeout_ms, err, err_len);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
esp_err_t platform_display_show_png(const uint8_t *png,
|
||||||
|
size_t png_len,
|
||||||
|
uint32_t timeout_ms,
|
||||||
|
char *err,
|
||||||
|
size_t err_len)
|
||||||
|
{
|
||||||
|
return lcd_module_show_png(png, png_len, timeout_ms, err, err_len);
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user