refactor(architecture): enforce component layering constraints

- move runtime policy/diag contracts to domain-owned facade and remove control_plane leapfrog usage

- enforce single declaration point for direct debug config in domain public API (constraint #6)

- harden timeout/idempotent semantics in REST/voice/printer/wifi/ble paths
This commit is contained in:
admin
2026-02-28 14:21:17 +08:00
parent 8a55ca0005
commit a549989332
23 changed files with 718 additions and 331 deletions

View File

@@ -9,6 +9,7 @@ idf_component_register(
"src/image_generation.c"
"src/screen_preview.c"
"src/system_runtime.c"
"src/domain_runtime_contracts.c"
"src/voice_interaction.c"
"src/voice_interaction_common.c"
"src/voice_interaction_ws.c"
@@ -19,9 +20,9 @@ idf_component_register(
"third_party/qrcodegen.c"
INCLUDE_DIRS
"include"
"third_party"
PRIV_INCLUDE_DIRS
"internal"
"third_party"
REQUIRES
platform
esp_http_client

View File

@@ -5,7 +5,6 @@
#include <stdint.h>
#include "esp_err.h"
#include "platform.h"
#ifdef __cplusplus
extern "C" {
@@ -19,6 +18,81 @@ esp_err_t system_runtime_bootstrap(void);
bool system_runtime_wifi_ready(void);
void system_runtime_get_ip(char *buf, size_t buf_len);
// ---------- domain_policy ----------
uint32_t domain_policy_lifecycle_start_retry_count(void);
uint32_t domain_policy_lifecycle_retry_backoff_ms(uint32_t attempt);
bool domain_policy_is_retryable_error(esp_err_t err);
uint32_t domain_policy_printer_stop_timeout_ms(void);
uint32_t domain_policy_rest_printer_connect_timeout_ms(void);
uint32_t domain_policy_rest_printer_connect_timeout_min_ms(void);
uint32_t domain_policy_rest_printer_connect_timeout_max_ms(void);
uint32_t domain_policy_rest_label_timeout_ms(void);
uint32_t domain_policy_rest_label_timeout_min_ms(void);
uint32_t domain_policy_rest_label_timeout_max_ms(void);
uint32_t domain_policy_rest_ota_timeout_ms(void);
uint32_t domain_policy_rest_ota_timeout_min_ms(void);
uint32_t domain_policy_rest_ota_timeout_max_ms(void);
uint32_t domain_policy_image_generation_timeout_default_ms(void);
uint32_t domain_policy_image_generation_timeout_min_ms(void);
uint32_t domain_policy_image_generation_timeout_max_ms(void);
uint32_t domain_policy_image_download_timeout_default_ms(void);
uint32_t domain_policy_image_download_timeout_min_ms(void);
uint32_t domain_policy_image_download_timeout_max_ms(void);
// ---------- domain_diagnostics ----------
typedef enum {
DOMAIN_DIAG_COUNTER_LIFECYCLE_START_ATTEMPT = 0,
DOMAIN_DIAG_COUNTER_LIFECYCLE_START_SUCCESS,
DOMAIN_DIAG_COUNTER_LIFECYCLE_START_FAILED,
DOMAIN_DIAG_COUNTER_LIFECYCLE_START_RETRY,
DOMAIN_DIAG_COUNTER_LIFECYCLE_STOP_ATTEMPT,
DOMAIN_DIAG_COUNTER_LIFECYCLE_STOP_SUCCESS,
DOMAIN_DIAG_COUNTER_LIFECYCLE_STOP_FAILED,
DOMAIN_DIAG_COUNTER_WIFI_CONNECT_SUCCESS,
DOMAIN_DIAG_COUNTER_WIFI_CONNECT_FAILED,
DOMAIN_DIAG_COUNTER_WIFI_CONNECT_TIMEOUT,
DOMAIN_DIAG_COUNTER_PRINTER_JOB_SUBMITTED,
DOMAIN_DIAG_COUNTER_PRINTER_JOB_SUCCESS,
DOMAIN_DIAG_COUNTER_PRINTER_JOB_FAILED,
DOMAIN_DIAG_COUNTER_PRINTER_JOB_CANCELED,
DOMAIN_DIAG_COUNTER_IMAGE_GENERATE_ATTEMPT,
DOMAIN_DIAG_COUNTER_IMAGE_GENERATE_SUCCESS,
DOMAIN_DIAG_COUNTER_IMAGE_GENERATE_FAILED,
DOMAIN_DIAG_COUNTER_IMAGE_GENERATE_TIMEOUT,
DOMAIN_DIAG_COUNTER_REST_RESPONSES_TOTAL,
DOMAIN_DIAG_COUNTER_REST_ERRORS_TOTAL,
DOMAIN_DIAG_COUNTER_MAX,
} domain_diag_counter_t;
typedef enum {
DOMAIN_DIAG_GAUGE_LIFECYCLE_STATE = 0,
DOMAIN_DIAG_GAUGE_STATUS_POLL_PAUSE_DEPTH,
DOMAIN_DIAG_GAUGE_PRINTER_QUEUE_DEPTH,
DOMAIN_DIAG_GAUGE_MAX,
} domain_diag_gauge_t;
typedef struct {
uint64_t counters[DOMAIN_DIAG_COUNTER_MAX];
int32_t gauges[DOMAIN_DIAG_GAUGE_MAX];
int64_t last_error_ms;
esp_err_t last_error_code;
char last_error_source[32];
char last_error_message[96];
} domain_diag_snapshot_t;
void domain_diag_counter_add(domain_diag_counter_t counter, uint32_t delta);
void domain_diag_set_gauge(domain_diag_gauge_t gauge, int32_t value);
void domain_diag_record_error(const char *source, esp_err_t code, const char *message);
void domain_diag_get_snapshot(domain_diag_snapshot_t *out_snapshot);
const char *domain_diag_counter_name(domain_diag_counter_t counter);
const char *domain_diag_gauge_name(domain_diag_gauge_t gauge);
// ---------- raster_tools ----------
esp_err_t raster_tools_render_text_384(const char *text,
uint8_t scale,
@@ -286,7 +360,9 @@ typedef struct {
} voice_interaction_status_t;
esp_err_t voice_interaction_init(void);
esp_err_t voice_interaction_start_with_timeout(uint32_t timeout_ms, char *err, size_t err_len);
esp_err_t voice_interaction_start(char *err, size_t err_len);
esp_err_t voice_interaction_stop_with_timeout(uint32_t timeout_ms, char *err, size_t err_len);
esp_err_t voice_interaction_stop(char *err, size_t err_len);
esp_err_t voice_interaction_tap_start(char *err, size_t err_len);

View File

@@ -6,6 +6,7 @@
#include "domain.h"
#include "esp_err.h"
#include "platform.h"
#include "freertos/FreeRTOS.h"
#include "freertos/event_groups.h"
#include "freertos/queue.h"
@@ -93,6 +94,7 @@ esp_err_t printer_protocol_send_cmd_wait_response(uint8_t cmd,
bool with_checksum,
uint32_t timeout_ms,
bool expect_ack,
bool reset_transport_on_timeout,
uint8_t *out_payload,
size_t out_payload_cap,
uint16_t *out_payload_len,
@@ -111,7 +113,8 @@ bool printer_protocol_send_cmd_with_ack(uint8_t cmd,
const uint8_t *payload,
uint16_t payload_len,
bool with_checksum,
uint32_t timeout_ms);
uint32_t timeout_ms,
bool reset_transport_on_timeout);
int printer_protocol_find_job_idx_locked(uint32_t id);
int printer_protocol_alloc_job_slot_locked(void);

View File

@@ -11,6 +11,7 @@
#include "freertos/semphr.h"
#include "freertos/task.h"
#include "domain.h"
#include "platform.h"
#define VOICE_STREAMING_MODE "duplex"
#define VOICE_TASK_GROUP "aigc"

View File

@@ -0,0 +1,201 @@
#include "domain.h"
#include <string.h>
#include "platform.h"
static runtime_diag_counter_t to_platform_counter(domain_diag_counter_t counter) {
switch (counter) {
case DOMAIN_DIAG_COUNTER_LIFECYCLE_START_ATTEMPT:
return RUNTIME_DIAG_COUNTER_LIFECYCLE_START_ATTEMPT;
case DOMAIN_DIAG_COUNTER_LIFECYCLE_START_SUCCESS:
return RUNTIME_DIAG_COUNTER_LIFECYCLE_START_SUCCESS;
case DOMAIN_DIAG_COUNTER_LIFECYCLE_START_FAILED:
return RUNTIME_DIAG_COUNTER_LIFECYCLE_START_FAILED;
case DOMAIN_DIAG_COUNTER_LIFECYCLE_START_RETRY:
return RUNTIME_DIAG_COUNTER_LIFECYCLE_START_RETRY;
case DOMAIN_DIAG_COUNTER_LIFECYCLE_STOP_ATTEMPT:
return RUNTIME_DIAG_COUNTER_LIFECYCLE_STOP_ATTEMPT;
case DOMAIN_DIAG_COUNTER_LIFECYCLE_STOP_SUCCESS:
return RUNTIME_DIAG_COUNTER_LIFECYCLE_STOP_SUCCESS;
case DOMAIN_DIAG_COUNTER_LIFECYCLE_STOP_FAILED:
return RUNTIME_DIAG_COUNTER_LIFECYCLE_STOP_FAILED;
case DOMAIN_DIAG_COUNTER_WIFI_CONNECT_SUCCESS:
return RUNTIME_DIAG_COUNTER_WIFI_CONNECT_SUCCESS;
case DOMAIN_DIAG_COUNTER_WIFI_CONNECT_FAILED:
return RUNTIME_DIAG_COUNTER_WIFI_CONNECT_FAILED;
case DOMAIN_DIAG_COUNTER_WIFI_CONNECT_TIMEOUT:
return RUNTIME_DIAG_COUNTER_WIFI_CONNECT_TIMEOUT;
case DOMAIN_DIAG_COUNTER_PRINTER_JOB_SUBMITTED:
return RUNTIME_DIAG_COUNTER_PRINTER_JOB_SUBMITTED;
case DOMAIN_DIAG_COUNTER_PRINTER_JOB_SUCCESS:
return RUNTIME_DIAG_COUNTER_PRINTER_JOB_SUCCESS;
case DOMAIN_DIAG_COUNTER_PRINTER_JOB_FAILED:
return RUNTIME_DIAG_COUNTER_PRINTER_JOB_FAILED;
case DOMAIN_DIAG_COUNTER_PRINTER_JOB_CANCELED:
return RUNTIME_DIAG_COUNTER_PRINTER_JOB_CANCELED;
case DOMAIN_DIAG_COUNTER_IMAGE_GENERATE_ATTEMPT:
return RUNTIME_DIAG_COUNTER_IMAGE_GENERATE_ATTEMPT;
case DOMAIN_DIAG_COUNTER_IMAGE_GENERATE_SUCCESS:
return RUNTIME_DIAG_COUNTER_IMAGE_GENERATE_SUCCESS;
case DOMAIN_DIAG_COUNTER_IMAGE_GENERATE_FAILED:
return RUNTIME_DIAG_COUNTER_IMAGE_GENERATE_FAILED;
case DOMAIN_DIAG_COUNTER_IMAGE_GENERATE_TIMEOUT:
return RUNTIME_DIAG_COUNTER_IMAGE_GENERATE_TIMEOUT;
case DOMAIN_DIAG_COUNTER_REST_RESPONSES_TOTAL:
return RUNTIME_DIAG_COUNTER_REST_RESPONSES_TOTAL;
case DOMAIN_DIAG_COUNTER_REST_ERRORS_TOTAL:
return RUNTIME_DIAG_COUNTER_REST_ERRORS_TOTAL;
default:
return RUNTIME_DIAG_COUNTER_MAX;
}
}
static runtime_diag_gauge_t to_platform_gauge(domain_diag_gauge_t gauge) {
switch (gauge) {
case DOMAIN_DIAG_GAUGE_LIFECYCLE_STATE:
return RUNTIME_DIAG_GAUGE_LIFECYCLE_STATE;
case DOMAIN_DIAG_GAUGE_STATUS_POLL_PAUSE_DEPTH:
return RUNTIME_DIAG_GAUGE_STATUS_POLL_PAUSE_DEPTH;
case DOMAIN_DIAG_GAUGE_PRINTER_QUEUE_DEPTH:
return RUNTIME_DIAG_GAUGE_PRINTER_QUEUE_DEPTH;
default:
return RUNTIME_DIAG_GAUGE_MAX;
}
}
uint32_t domain_policy_lifecycle_start_retry_count(void) {
return runtime_policy_lifecycle_start_retry_count();
}
uint32_t domain_policy_lifecycle_retry_backoff_ms(uint32_t attempt) {
return runtime_policy_lifecycle_retry_backoff_ms(attempt);
}
bool domain_policy_is_retryable_error(esp_err_t err) {
return runtime_policy_is_retryable_error(err);
}
uint32_t domain_policy_printer_stop_timeout_ms(void) {
return runtime_policy_printer_stop_timeout_ms();
}
uint32_t domain_policy_rest_printer_connect_timeout_ms(void) {
return runtime_policy_rest_printer_connect_timeout_ms();
}
uint32_t domain_policy_rest_printer_connect_timeout_min_ms(void) {
return 1000;
}
uint32_t domain_policy_rest_printer_connect_timeout_max_ms(void) {
return 60000;
}
uint32_t domain_policy_rest_label_timeout_ms(void) {
return runtime_policy_rest_label_timeout_ms();
}
uint32_t domain_policy_rest_label_timeout_min_ms(void) {
return 500;
}
uint32_t domain_policy_rest_label_timeout_max_ms(void) {
return 30000;
}
uint32_t domain_policy_rest_ota_timeout_ms(void) {
return runtime_policy_rest_ota_timeout_ms();
}
uint32_t domain_policy_rest_ota_timeout_min_ms(void) {
return 500;
}
uint32_t domain_policy_rest_ota_timeout_max_ms(void) {
return 60000;
}
uint32_t domain_policy_image_generation_timeout_default_ms(void) {
return runtime_policy_image_generation_timeout_default_ms();
}
uint32_t domain_policy_image_generation_timeout_min_ms(void) {
return runtime_policy_image_generation_timeout_min_ms();
}
uint32_t domain_policy_image_generation_timeout_max_ms(void) {
return runtime_policy_image_generation_timeout_max_ms();
}
uint32_t domain_policy_image_download_timeout_default_ms(void) {
return runtime_policy_image_download_timeout_default_ms();
}
uint32_t domain_policy_image_download_timeout_min_ms(void) {
return runtime_policy_image_download_timeout_min_ms();
}
uint32_t domain_policy_image_download_timeout_max_ms(void) {
return runtime_policy_image_download_timeout_max_ms();
}
void domain_diag_counter_add(domain_diag_counter_t counter, uint32_t delta) {
runtime_diag_counter_t mapped = to_platform_counter(counter);
if (mapped >= RUNTIME_DIAG_COUNTER_MAX) {
return;
}
runtime_diag_counter_add(mapped, delta);
}
void domain_diag_set_gauge(domain_diag_gauge_t gauge, int32_t value) {
runtime_diag_gauge_t mapped = to_platform_gauge(gauge);
if (mapped >= RUNTIME_DIAG_GAUGE_MAX) {
return;
}
runtime_diag_set_gauge(mapped, value);
}
void domain_diag_record_error(const char *source, esp_err_t code, const char *message) {
runtime_diag_record_error(source, code, message);
}
void domain_diag_get_snapshot(domain_diag_snapshot_t *out_snapshot) {
if (out_snapshot == NULL) {
return;
}
runtime_diag_snapshot_t platform_snapshot = {0};
runtime_diag_get_snapshot(&platform_snapshot);
for (int i = 0; i < DOMAIN_DIAG_COUNTER_MAX && i < RUNTIME_DIAG_COUNTER_MAX; ++i) {
out_snapshot->counters[i] = platform_snapshot.counters[i];
}
for (int i = 0; i < DOMAIN_DIAG_GAUGE_MAX && i < RUNTIME_DIAG_GAUGE_MAX; ++i) {
out_snapshot->gauges[i] = platform_snapshot.gauges[i];
}
out_snapshot->last_error_ms = platform_snapshot.last_error_ms;
out_snapshot->last_error_code = platform_snapshot.last_error_code;
strlcpy(out_snapshot->last_error_source,
platform_snapshot.last_error_source,
sizeof(out_snapshot->last_error_source));
strlcpy(out_snapshot->last_error_message,
platform_snapshot.last_error_message,
sizeof(out_snapshot->last_error_message));
}
const char *domain_diag_counter_name(domain_diag_counter_t counter) {
runtime_diag_counter_t mapped = to_platform_counter(counter);
if (mapped >= RUNTIME_DIAG_COUNTER_MAX) {
return "unknown";
}
return runtime_diag_counter_name(mapped);
}
const char *domain_diag_gauge_name(domain_diag_gauge_t gauge) {
runtime_diag_gauge_t mapped = to_platform_gauge(gauge);
if (mapped >= RUNTIME_DIAG_GAUGE_MAX) {
return "unknown";
}
return runtime_diag_gauge_name(mapped);
}

View File

@@ -1,4 +1,5 @@
#include "domain.h"
#include "platform.h"
#include <stdio.h>
#include <stdlib.h>

View File

@@ -441,16 +441,30 @@ static bool wait_ack(uint8_t cmd, uint32_t timeout_ms) {
return payload_len >= 1 && payload[0] == 0x01;
}
static void reset_transport_after_timeout(void) {
if (printer_protocol_is_stopping()) {
return;
}
if (printer_protocol_get_backend() == PRINTER_BACKEND_BLE) {
ble_printer_client_disconnect();
}
}
bool printer_protocol_send_cmd_with_ack(uint8_t cmd,
const uint8_t *payload,
uint16_t payload_len,
bool with_checksum,
uint32_t timeout_ms) {
uint32_t timeout_ms,
bool reset_transport_on_timeout) {
clear_ack_signal();
if (printer_protocol_send_frame(cmd, payload, payload_len, with_checksum) != ESP_OK) {
return false;
}
return wait_ack(cmd, timeout_ms);
bool ok = wait_ack(cmd, timeout_ms);
if (!ok && reset_transport_on_timeout) {
reset_transport_after_timeout();
}
return ok;
}
esp_err_t printer_protocol_send_cmd_wait_response(uint8_t cmd,
@@ -459,6 +473,7 @@ esp_err_t printer_protocol_send_cmd_wait_response(uint8_t cmd,
bool with_checksum,
uint32_t timeout_ms,
bool expect_ack,
bool reset_transport_on_timeout,
uint8_t *out_payload,
size_t out_payload_cap,
uint16_t *out_payload_len,
@@ -475,14 +490,21 @@ esp_err_t printer_protocol_send_cmd_wait_response(uint8_t cmd,
uint8_t rsp[252];
uint16_t rsp_len = 0;
if (!printer_protocol_wait_response(cmd, rsp, sizeof(rsp), &rsp_len, timeout_ms)) {
bool stopping = printer_protocol_is_stopping();
if (!stopping && reset_transport_on_timeout) {
reset_transport_after_timeout();
}
if (err != NULL && err_len > 0) {
if (printer_protocol_is_stopping()) {
if (stopping) {
snprintf(err, err_len, "protocol stopping");
} else {
snprintf(err, err_len, "response timeout");
snprintf(err,
err_len,
reset_transport_on_timeout ? "response timeout, transport reset"
: "response timeout");
}
}
return printer_protocol_is_stopping() ? ESP_ERR_INVALID_STATE : ESP_ERR_TIMEOUT;
return stopping ? ESP_ERR_INVALID_STATE : ESP_ERR_TIMEOUT;
}
if (expect_ack && (rsp_len < 1 || rsp[0] != 0x01)) {

View File

@@ -44,6 +44,7 @@ esp_err_t printer_protocol_gap_move(uint32_t timeout_ms, char *err, size_t err_l
true,
timeout_ms,
true,
true,
NULL,
0,
NULL,
@@ -85,6 +86,7 @@ esp_err_t printer_protocol_get_label_offset(uint8_t *out_offset, uint32_t timeou
true,
timeout_ms,
false,
false,
rsp,
sizeof(rsp),
&rsp_len,
@@ -133,6 +135,7 @@ esp_err_t printer_protocol_set_label_offset(uint8_t offset, uint32_t timeout_ms,
true,
timeout_ms,
true,
true,
NULL,
0,
NULL,
@@ -164,6 +167,7 @@ esp_err_t printer_protocol_ota_jump_boot(uint32_t timeout_ms, char *err, size_t
true,
timeout_ms,
true,
true,
NULL,
0,
NULL,
@@ -195,6 +199,7 @@ esp_err_t printer_protocol_ota_jump_app(uint32_t timeout_ms, char *err, size_t e
true,
timeout_ms,
true,
true,
NULL,
0,
NULL,
@@ -231,6 +236,7 @@ esp_err_t printer_protocol_ota_erase_page(uint16_t page_num, uint32_t timeout_ms
true,
timeout_ms,
true,
true,
NULL,
0,
NULL,
@@ -283,6 +289,7 @@ esp_err_t printer_protocol_ota_write_frame(uint16_t packet_num,
true,
timeout_ms,
true,
true,
NULL,
0,
NULL,
@@ -326,6 +333,7 @@ esp_err_t printer_protocol_ota_get_version(printer_ota_version_t *out_version,
true,
timeout_ms,
false,
false,
rsp,
sizeof(rsp),
&rsp_len,
@@ -361,22 +369,19 @@ esp_err_t printer_protocol_get_direct_debug_config(printer_direct_debug_config_t
return ESP_ERR_NOT_SUPPORTED;
}
platform_direct_debug_config_t cfg = {0};
esp_err_t rc = platform_direct_printer_get_debug_config(&cfg);
esp_err_t rc = platform_direct_printer_get_debug_config(&out_config->shift_clock_high_us,
&out_config->shift_clock_low_us,
&out_config->latch_pulse_us,
&out_config->strobe_active_high,
&out_config->boost_active_high,
&out_config->override_strobe_on_us,
&out_config->override_strobe_interval_us,
&out_config->override_motor_step_us,
&out_config->override_steps_per_line);
if (rc != ESP_OK) {
write_err(err, err_len, "get direct debug config failed");
return rc;
}
out_config->shift_clock_high_us = cfg.shift_clock_high_us;
out_config->shift_clock_low_us = cfg.shift_clock_low_us;
out_config->latch_pulse_us = cfg.latch_pulse_us;
out_config->strobe_active_high = cfg.strobe_active_high;
out_config->boost_active_high = cfg.boost_active_high;
out_config->override_strobe_on_us = cfg.override_strobe_on_us;
out_config->override_strobe_interval_us = cfg.override_strobe_interval_us;
out_config->override_motor_step_us = cfg.override_motor_step_us;
out_config->override_steps_per_line = cfg.override_steps_per_line;
return ESP_OK;
}
@@ -393,22 +398,19 @@ esp_err_t printer_protocol_set_direct_debug_config(const printer_direct_debug_co
return ESP_ERR_NOT_SUPPORTED;
}
platform_direct_debug_config_t cfg = {0};
platform_direct_debug_config_t *pcfg = NULL;
if (config != NULL) {
cfg.shift_clock_high_us = config->shift_clock_high_us;
cfg.shift_clock_low_us = config->shift_clock_low_us;
cfg.latch_pulse_us = config->latch_pulse_us;
cfg.strobe_active_high = config->strobe_active_high;
cfg.boost_active_high = config->boost_active_high;
cfg.override_strobe_on_us = config->override_strobe_on_us;
cfg.override_strobe_interval_us = config->override_strobe_interval_us;
cfg.override_motor_step_us = config->override_motor_step_us;
cfg.override_steps_per_line = config->override_steps_per_line;
pcfg = &cfg;
}
return platform_direct_printer_set_debug_config(pcfg, reset_defaults, err, err_len);
return platform_direct_printer_set_debug_config(config != NULL,
config != NULL ? config->shift_clock_high_us : 0,
config != NULL ? config->shift_clock_low_us : 0,
config != NULL ? config->latch_pulse_us : 0,
config != NULL ? config->strobe_active_high : false,
config != NULL ? config->boost_active_high : false,
config != NULL ? config->override_strobe_on_us : 0,
config != NULL ? config->override_strobe_interval_us : 0,
config != NULL ? config->override_motor_step_us : 0,
config != NULL ? config->override_steps_per_line : 0,
reset_defaults,
err,
err_len);
}
const char *printer_protocol_job_state_str(print_job_state_t state) {

View File

@@ -164,7 +164,7 @@ static bool run_print_job_ble(job_slot_t *job) {
}
uint8_t power_on = 0x01;
if (!printer_protocol_send_cmd_with_ack(CMD_POWER, &power_on, 1, true, 1500)) {
if (!printer_protocol_send_cmd_with_ack(CMD_POWER, &power_on, 1, true, 1500, true)) {
snprintf(job->error, sizeof(job->error), "power on failed");
ESP_LOGW(TAG, "job %u print aborted: %s", (unsigned)job->id, job->error);
return false;
@@ -178,7 +178,7 @@ static bool run_print_job_ble(job_slot_t *job) {
(uint8_t)(hot_time & 0xFF),
};
if (!printer_protocol_send_cmd_with_ack(CMD_SET_PARAM, param, sizeof(param), true, 1500)) {
if (!printer_protocol_send_cmd_with_ack(CMD_SET_PARAM, param, sizeof(param), true, 1500, true)) {
snprintf(job->error, sizeof(job->error), "set print param failed");
ESP_LOGW(TAG, "job %u print aborted: %s", (unsigned)job->id, job->error);
return false;
@@ -217,7 +217,8 @@ static bool run_print_job_ble(job_slot_t *job) {
&job->data[start],
(uint16_t)chunk_len,
false,
2500)) {
2500,
true)) {
snprintf(job->error, sizeof(job->error), "send chunk timeout at %u", (unsigned)i);
ESP_LOGW(TAG, "job %u print aborted: %s", (unsigned)job->id, job->error);
return false;
@@ -245,10 +246,15 @@ static bool run_print_job_ble(job_slot_t *job) {
ESP_LOGI(TAG, "job %u data transfer done", (unsigned)job->id);
uint8_t power_off = 0x00;
(void)printer_protocol_send_cmd_with_ack(CMD_POWER, &power_off, 1, true, 1200);
(void)printer_protocol_send_cmd_with_ack(CMD_POWER, &power_off, 1, true, 1200, false);
uint8_t feed_payload[3] = {0x2B, 0x00, 0x0C};
(void)printer_protocol_send_cmd_with_ack(CMD_SET_DISTANCE, feed_payload, sizeof(feed_payload), true, 1200);
(void)printer_protocol_send_cmd_with_ack(CMD_SET_DISTANCE,
feed_payload,
sizeof(feed_payload),
true,
1200,
false);
ESP_LOGI(TAG, "job %u print command sequence done", (unsigned)job->id);
return true;

View File

@@ -1,4 +1,5 @@
#include "domain.h"
#include "platform.h"
esp_err_t screen_preview_show_raster(const uint8_t *raster,
size_t raster_len,

View File

@@ -1,4 +1,5 @@
#include "domain.h"
#include "platform.h"
esp_err_t system_runtime_start(void) {
esp_err_t err = platform_bootstrap_init();

View File

@@ -9,7 +9,18 @@
static const char *TAG = "voice_interaction";
static void voice_wait_worker_tasks_exit(uint32_t timeout_ms) {
static uint32_t clamp_timeout_ms(uint32_t timeout_ms, uint32_t default_ms, uint32_t min_ms, uint32_t max_ms) {
uint32_t value = timeout_ms == 0 ? default_ms : timeout_ms;
if (value < min_ms) {
value = min_ms;
}
if (value > max_ms) {
value = max_ms;
}
return value;
}
static bool voice_wait_worker_tasks_exit(uint32_t timeout_ms) {
int64_t deadline_ms = voice_now_ms() + (int64_t)timeout_ms;
while (voice_now_ms() < deadline_ms) {
bool uplink_alive = false;
@@ -21,7 +32,7 @@ static void voice_wait_worker_tasks_exit(uint32_t timeout_ms) {
}
if (!uplink_alive && !heartbeat_alive) {
return;
return true;
}
vTaskDelay(pdMS_TO_TICKS(20));
}
@@ -33,6 +44,7 @@ static void voice_wait_worker_tasks_exit(uint32_t timeout_ms) {
s_voice.heartbeat_task != NULL);
voice_unlock();
}
return false;
}
const char *voice_interaction_dialog_state_str(voice_dialog_state_t state) {
@@ -68,7 +80,9 @@ esp_err_t voice_interaction_init(void) {
return ESP_OK;
}
esp_err_t voice_interaction_start(char *err, size_t err_len) {
esp_err_t voice_interaction_start_with_timeout(uint32_t timeout_ms, char *err, size_t err_len) {
uint32_t connect_timeout_ms =
clamp_timeout_ms(timeout_ms, VOICE_START_CONNECT_TIMEOUT_MS, 1000, 30000);
ESP_LOGI(TAG, "[stage] session_start_enter");
if (!s_voice.ready) {
voice_fill_err(err, err_len, "voice interaction not initialized");
@@ -260,8 +274,8 @@ esp_err_t voice_interaction_start(char *err, size_t err_len) {
ESP_LOGI(TAG, "[stage] heartbeat_task_create_ok");
voice_log_heap_snapshot("after_create_heartbeat");
ESP_LOGI(TAG, "[stage] wait_ws_connected_begin: timeout_ms=%d", VOICE_START_CONNECT_TIMEOUT_MS);
int64_t deadline = voice_now_ms() + VOICE_START_CONNECT_TIMEOUT_MS;
ESP_LOGI(TAG, "[stage] wait_ws_connected_begin: timeout_ms=%u", (unsigned)connect_timeout_ms);
int64_t deadline = voice_now_ms() + connect_timeout_ms;
while (voice_now_ms() < deadline) {
bool connected = false;
if (voice_lock(VOICE_STATUS_LOCK_TIMEOUT_MS)) {
@@ -301,17 +315,22 @@ exit_err:
return ESP_FAIL;
}
esp_err_t voice_interaction_stop(char *err, size_t err_len) {
(void)err;
(void)err_len;
esp_err_t voice_interaction_start(char *err, size_t err_len) {
return voice_interaction_start_with_timeout(VOICE_START_CONNECT_TIMEOUT_MS, err, err_len);
}
esp_err_t voice_interaction_stop_with_timeout(uint32_t timeout_ms, char *err, size_t err_len) {
uint32_t worker_exit_timeout_ms = clamp_timeout_ms(timeout_ms, 1500, 500, 10000);
ESP_LOGI(TAG, "[stage] session_stop_enter");
if (!s_voice.ready) {
voice_fill_err(err, err_len, "voice interaction not initialized");
ESP_LOGW(TAG, "[stage] session_stop_abort: not initialized");
return ESP_ERR_INVALID_STATE;
}
if (!voice_lock(VOICE_STATUS_LOCK_TIMEOUT_MS)) {
voice_fill_err(err, err_len, "voice lock timeout");
ESP_LOGW(TAG, "[stage] session_stop_abort: lock timeout");
return ESP_ERR_TIMEOUT;
}
@@ -343,7 +362,16 @@ esp_err_t voice_interaction_stop(char *err, size_t err_len) {
if (heartbeat_task != NULL) {
(void)xTaskAbortDelay(heartbeat_task);
}
voice_wait_worker_tasks_exit(1500);
bool workers_exited = voice_wait_worker_tasks_exit(worker_exit_timeout_ms);
if (!workers_exited) {
voice_fill_err(err, err_len, "voice worker exit timeout");
if (voice_lock(VOICE_STATUS_LOCK_TIMEOUT_MS)) {
voice_set_last_error_locked("worker exit timeout");
voice_unlock();
}
ESP_LOGW(TAG, "[stage] session_stop_abort: workers still alive");
return ESP_ERR_TIMEOUT;
}
if (ws != NULL) {
ESP_LOGI(TAG, "[stage] ws_stop_destroy_begin");
@@ -380,6 +408,10 @@ esp_err_t voice_interaction_stop(char *err, size_t err_len) {
return ESP_OK;
}
esp_err_t voice_interaction_stop(char *err, size_t err_len) {
return voice_interaction_stop_with_timeout(1500, err, err_len);
}
esp_err_t voice_interaction_tap_start(char *err, size_t err_len) {
ESP_LOGI(TAG, "[stage] tap_start_enter");
if (!voice_lock(VOICE_STATUS_LOCK_TIMEOUT_MS)) {