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:
@@ -61,26 +61,31 @@ typedef struct {
|
||||
const volatile bool *cancel_flag;
|
||||
} platform_direct_print_request_t;
|
||||
|
||||
typedef struct {
|
||||
uint16_t shift_clock_high_us;
|
||||
uint16_t shift_clock_low_us;
|
||||
uint16_t latch_pulse_us;
|
||||
bool strobe_active_high;
|
||||
bool boost_active_high;
|
||||
uint16_t override_strobe_on_us;
|
||||
uint16_t override_strobe_interval_us;
|
||||
uint16_t override_motor_step_us;
|
||||
uint8_t override_steps_per_line;
|
||||
} platform_direct_debug_config_t;
|
||||
|
||||
esp_err_t platform_direct_printer_init(void);
|
||||
void platform_direct_printer_deinit(void);
|
||||
esp_err_t platform_direct_printer_connect(uint32_t timeout_ms);
|
||||
void platform_direct_printer_disconnect(void);
|
||||
bool platform_direct_printer_is_connected(void);
|
||||
esp_err_t platform_direct_printer_get_sensors(platform_printer_sensors_t *out_sensors);
|
||||
esp_err_t platform_direct_printer_get_debug_config(platform_direct_debug_config_t *out_config);
|
||||
esp_err_t platform_direct_printer_set_debug_config(const platform_direct_debug_config_t *config,
|
||||
esp_err_t platform_direct_printer_get_debug_config(uint16_t *out_shift_clock_high_us,
|
||||
uint16_t *out_shift_clock_low_us,
|
||||
uint16_t *out_latch_pulse_us,
|
||||
bool *out_strobe_active_high,
|
||||
bool *out_boost_active_high,
|
||||
uint16_t *out_override_strobe_on_us,
|
||||
uint16_t *out_override_strobe_interval_us,
|
||||
uint16_t *out_override_motor_step_us,
|
||||
uint8_t *out_override_steps_per_line);
|
||||
esp_err_t platform_direct_printer_set_debug_config(bool has_config,
|
||||
uint16_t shift_clock_high_us,
|
||||
uint16_t shift_clock_low_us,
|
||||
uint16_t latch_pulse_us,
|
||||
bool strobe_active_high,
|
||||
bool boost_active_high,
|
||||
uint16_t override_strobe_on_us,
|
||||
uint16_t override_strobe_interval_us,
|
||||
uint16_t override_motor_step_us,
|
||||
uint8_t override_steps_per_line,
|
||||
bool reset_defaults,
|
||||
char *err,
|
||||
size_t err_len);
|
||||
@@ -115,11 +120,15 @@ void voice_audio_close(void);
|
||||
|
||||
bool voice_audio_is_open(void);
|
||||
|
||||
// timeout_ms applies to voice-audio mutex acquisition.
|
||||
// Underlying codec driver I/O duration depends on driver/clocking state.
|
||||
esp_err_t voice_audio_read_pcm(int16_t *pcm,
|
||||
size_t samples,
|
||||
uint32_t timeout_ms,
|
||||
char *err,
|
||||
size_t err_len);
|
||||
// timeout_ms applies to voice-audio mutex acquisition.
|
||||
// Underlying codec driver I/O duration depends on driver/clocking state.
|
||||
esp_err_t voice_audio_write_pcm(const int16_t *pcm,
|
||||
size_t samples,
|
||||
uint32_t timeout_ms,
|
||||
|
||||
@@ -52,6 +52,8 @@ static bool s_scanning;
|
||||
static bool s_notify_ready;
|
||||
static bool s_host_synced;
|
||||
static bool s_initialized;
|
||||
static bool s_connecting;
|
||||
static uint32_t s_connect_timeout_ms = 15000;
|
||||
|
||||
static uint16_t uuid16(const ble_uuid_t *uuid) {
|
||||
if (uuid == NULL || uuid->type != BLE_UUID_TYPE_16) {
|
||||
@@ -397,12 +399,13 @@ static int gap_event_cb(struct ble_gap_event *event, void *arg) {
|
||||
|
||||
rc = ble_gap_connect(s_addr_type,
|
||||
&s_target_addr,
|
||||
30000,
|
||||
s_connect_timeout_ms > 30000 ? 30000 : s_connect_timeout_ms,
|
||||
&conn_params,
|
||||
gap_event_cb,
|
||||
NULL);
|
||||
if (rc != 0) {
|
||||
ESP_LOGE(TAG, "ble_gap_connect failed rc=%d", rc);
|
||||
s_connecting = false;
|
||||
signal_failure();
|
||||
} else {
|
||||
ESP_LOGI(TAG, "Connecting...");
|
||||
@@ -417,6 +420,11 @@ static int gap_event_cb(struct ble_gap_event *event, void *arg) {
|
||||
|
||||
case BLE_GAP_EVENT_CONNECT:
|
||||
if (event->connect.status == 0) {
|
||||
if (!s_connecting) {
|
||||
(void)ble_gap_terminate(event->connect.conn_handle, BLE_ERR_REM_USER_CONN_TERM);
|
||||
return 0;
|
||||
}
|
||||
s_connecting = false;
|
||||
s_conn_handle = event->connect.conn_handle;
|
||||
xEventGroupSetBits(s_evt_group, EVT_CONNECTED);
|
||||
ESP_LOGI(TAG, "Connected handle=%u", s_conn_handle);
|
||||
@@ -424,6 +432,7 @@ static int gap_event_cb(struct ble_gap_event *event, void *arg) {
|
||||
ble_gattc_exchange_mtu(s_conn_handle, NULL, NULL);
|
||||
start_service_discovery();
|
||||
} else {
|
||||
s_connecting = false;
|
||||
ESP_LOGE(TAG, "Connect failed status=%d", event->connect.status);
|
||||
signal_failure();
|
||||
}
|
||||
@@ -431,6 +440,7 @@ static int gap_event_cb(struct ble_gap_event *event, void *arg) {
|
||||
|
||||
case BLE_GAP_EVENT_DISCONNECT:
|
||||
ESP_LOGW(TAG, "Disconnected reason=%d", event->disconnect.reason);
|
||||
s_connecting = false;
|
||||
s_conn_handle = BLE_HS_CONN_HANDLE_NONE;
|
||||
s_notify_ready = false;
|
||||
reset_discovery_state();
|
||||
@@ -564,6 +574,13 @@ esp_err_t ble_printer_client_connect(const char *target_name, uint32_t timeout_m
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
|
||||
uint32_t effective_timeout_ms = timeout_ms;
|
||||
if (effective_timeout_ms < 1000) {
|
||||
effective_timeout_ms = 1000;
|
||||
} else if (effective_timeout_ms > 60000) {
|
||||
effective_timeout_ms = 60000;
|
||||
}
|
||||
|
||||
s_match_any_compatible = false;
|
||||
if (target_name != NULL && target_name[0] != '\0') {
|
||||
if (strcmp(target_name, "*") == 0) {
|
||||
@@ -581,9 +598,15 @@ esp_err_t ble_printer_client_connect(const char *target_name, uint32_t timeout_m
|
||||
xSemaphoreGive(s_lock);
|
||||
return ESP_OK;
|
||||
}
|
||||
if (s_connecting) {
|
||||
xSemaphoreGive(s_lock);
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
|
||||
xEventGroupClearBits(s_evt_group, EVT_CONNECTED | EVT_READY | EVT_FAILED);
|
||||
reset_discovery_state();
|
||||
s_connect_timeout_ms = effective_timeout_ms;
|
||||
s_connecting = true;
|
||||
|
||||
int wait_sync_ms = 3000;
|
||||
while (!s_host_synced && wait_sync_ms > 0) {
|
||||
@@ -602,36 +625,21 @@ esp_err_t ble_printer_client_connect(const char *target_name, uint32_t timeout_m
|
||||
EVT_READY | EVT_FAILED,
|
||||
pdFALSE,
|
||||
pdFALSE,
|
||||
pdMS_TO_TICKS(timeout_ms));
|
||||
pdMS_TO_TICKS(effective_timeout_ms));
|
||||
|
||||
if (bits & EVT_READY) {
|
||||
return ESP_OK;
|
||||
}
|
||||
if (xSemaphoreTake(s_lock, pdMS_TO_TICKS(500)) == pdTRUE) {
|
||||
stop_scan_if_running();
|
||||
xSemaphoreGive(s_lock);
|
||||
}
|
||||
|
||||
// Similar to Android app behavior: quick retry when initial attempt fails or times out.
|
||||
if (xSemaphoreTake(s_lock, pdMS_TO_TICKS(1000)) == pdTRUE) {
|
||||
xEventGroupClearBits(s_evt_group, EVT_CONNECTED | EVT_READY | EVT_FAILED);
|
||||
stop_scan_if_running();
|
||||
if (s_conn_handle != BLE_HS_CONN_HANDLE_NONE) {
|
||||
(void)ble_gap_terminate(s_conn_handle, BLE_ERR_REM_USER_CONN_TERM);
|
||||
}
|
||||
s_connecting = false;
|
||||
reset_discovery_state();
|
||||
start_scan();
|
||||
xSemaphoreGive(s_lock);
|
||||
}
|
||||
|
||||
bits = xEventGroupWaitBits(s_evt_group,
|
||||
EVT_READY | EVT_FAILED,
|
||||
pdFALSE,
|
||||
pdFALSE,
|
||||
pdMS_TO_TICKS(timeout_ms));
|
||||
if (bits & EVT_READY) {
|
||||
return ESP_OK;
|
||||
}
|
||||
if (xSemaphoreTake(s_lock, pdMS_TO_TICKS(500)) == pdTRUE) {
|
||||
stop_scan_if_running();
|
||||
xSemaphoreGive(s_lock);
|
||||
}
|
||||
if (bits & EVT_FAILED) {
|
||||
return ESP_FAIL;
|
||||
}
|
||||
@@ -653,6 +661,7 @@ void ble_printer_client_disconnect(void) {
|
||||
ble_gap_terminate(s_conn_handle, BLE_ERR_REM_USER_CONN_TERM);
|
||||
}
|
||||
|
||||
s_connecting = false;
|
||||
s_conn_handle = BLE_HS_CONN_HANDLE_NONE;
|
||||
reset_discovery_state();
|
||||
xSemaphoreGive(s_lock);
|
||||
|
||||
@@ -49,11 +49,23 @@ typedef struct {
|
||||
adc_channel_t channel;
|
||||
} adc_pin_t;
|
||||
|
||||
typedef struct {
|
||||
uint16_t shift_clock_high_us;
|
||||
uint16_t shift_clock_low_us;
|
||||
uint16_t latch_pulse_us;
|
||||
bool strobe_active_high;
|
||||
bool boost_active_high;
|
||||
uint16_t override_strobe_on_us;
|
||||
uint16_t override_strobe_interval_us;
|
||||
uint16_t override_motor_step_us;
|
||||
uint8_t override_steps_per_line;
|
||||
} direct_debug_config_t;
|
||||
|
||||
typedef struct {
|
||||
bool initialized;
|
||||
bool connected;
|
||||
uint8_t motor_phase;
|
||||
platform_direct_debug_config_t debug;
|
||||
direct_debug_config_t debug;
|
||||
SemaphoreHandle_t lock;
|
||||
adc_oneshot_unit_handle_t adc1_handle;
|
||||
adc_oneshot_unit_handle_t adc2_handle;
|
||||
@@ -567,8 +579,8 @@ void platform_direct_printer_deinit(void) {
|
||||
}
|
||||
|
||||
esp_err_t platform_direct_printer_connect(uint32_t timeout_ms) {
|
||||
(void)timeout_ms;
|
||||
#if !CONFIG_TQ_DIRECT_PRINTER_ENABLE
|
||||
(void)timeout_ms;
|
||||
return ESP_ERR_NOT_SUPPORTED;
|
||||
#else
|
||||
esp_err_t err = platform_direct_printer_init();
|
||||
@@ -576,7 +588,12 @@ esp_err_t platform_direct_printer_connect(uint32_t timeout_ms) {
|
||||
return err;
|
||||
}
|
||||
|
||||
if (xSemaphoreTake(s_state.lock, pdMS_TO_TICKS(500)) != pdTRUE) {
|
||||
uint32_t lock_timeout_ms = timeout_ms == 0 ? 500 : timeout_ms;
|
||||
if (lock_timeout_ms > 5000) {
|
||||
lock_timeout_ms = 5000;
|
||||
}
|
||||
|
||||
if (xSemaphoreTake(s_state.lock, pdMS_TO_TICKS(lock_timeout_ms)) != pdTRUE) {
|
||||
return ESP_ERR_TIMEOUT;
|
||||
}
|
||||
|
||||
@@ -631,12 +648,31 @@ esp_err_t platform_direct_printer_get_sensors(platform_printer_sensors_t *out_se
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t platform_direct_printer_get_debug_config(platform_direct_debug_config_t *out_config) {
|
||||
esp_err_t platform_direct_printer_get_debug_config(uint16_t *out_shift_clock_high_us,
|
||||
uint16_t *out_shift_clock_low_us,
|
||||
uint16_t *out_latch_pulse_us,
|
||||
bool *out_strobe_active_high,
|
||||
bool *out_boost_active_high,
|
||||
uint16_t *out_override_strobe_on_us,
|
||||
uint16_t *out_override_strobe_interval_us,
|
||||
uint16_t *out_override_motor_step_us,
|
||||
uint8_t *out_override_steps_per_line) {
|
||||
#if !CONFIG_TQ_DIRECT_PRINTER_ENABLE
|
||||
(void)out_config;
|
||||
(void)out_shift_clock_high_us;
|
||||
(void)out_shift_clock_low_us;
|
||||
(void)out_latch_pulse_us;
|
||||
(void)out_strobe_active_high;
|
||||
(void)out_boost_active_high;
|
||||
(void)out_override_strobe_on_us;
|
||||
(void)out_override_strobe_interval_us;
|
||||
(void)out_override_motor_step_us;
|
||||
(void)out_override_steps_per_line;
|
||||
return ESP_ERR_NOT_SUPPORTED;
|
||||
#else
|
||||
if (out_config == NULL) {
|
||||
if (out_shift_clock_high_us == NULL || out_shift_clock_low_us == NULL || out_latch_pulse_us == NULL ||
|
||||
out_strobe_active_high == NULL || out_boost_active_high == NULL || out_override_strobe_on_us == NULL ||
|
||||
out_override_strobe_interval_us == NULL || out_override_motor_step_us == NULL ||
|
||||
out_override_steps_per_line == NULL) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
esp_err_t init_rc = platform_direct_printer_init();
|
||||
@@ -646,23 +682,49 @@ esp_err_t platform_direct_printer_get_debug_config(platform_direct_debug_config_
|
||||
if (xSemaphoreTake(s_state.lock, pdMS_TO_TICKS(500)) != pdTRUE) {
|
||||
return ESP_ERR_TIMEOUT;
|
||||
}
|
||||
*out_config = s_state.debug;
|
||||
*out_shift_clock_high_us = s_state.debug.shift_clock_high_us;
|
||||
*out_shift_clock_low_us = s_state.debug.shift_clock_low_us;
|
||||
*out_latch_pulse_us = s_state.debug.latch_pulse_us;
|
||||
*out_strobe_active_high = s_state.debug.strobe_active_high;
|
||||
*out_boost_active_high = s_state.debug.boost_active_high;
|
||||
*out_override_strobe_on_us = s_state.debug.override_strobe_on_us;
|
||||
*out_override_strobe_interval_us = s_state.debug.override_strobe_interval_us;
|
||||
*out_override_motor_step_us = s_state.debug.override_motor_step_us;
|
||||
*out_override_steps_per_line = s_state.debug.override_steps_per_line;
|
||||
xSemaphoreGive(s_state.lock);
|
||||
return ESP_OK;
|
||||
#endif
|
||||
}
|
||||
|
||||
esp_err_t platform_direct_printer_set_debug_config(const platform_direct_debug_config_t *config,
|
||||
esp_err_t platform_direct_printer_set_debug_config(bool has_config,
|
||||
uint16_t shift_clock_high_us,
|
||||
uint16_t shift_clock_low_us,
|
||||
uint16_t latch_pulse_us,
|
||||
bool strobe_active_high,
|
||||
bool boost_active_high,
|
||||
uint16_t override_strobe_on_us,
|
||||
uint16_t override_strobe_interval_us,
|
||||
uint16_t override_motor_step_us,
|
||||
uint8_t override_steps_per_line,
|
||||
bool reset_defaults,
|
||||
char *err,
|
||||
size_t err_len) {
|
||||
#if !CONFIG_TQ_DIRECT_PRINTER_ENABLE
|
||||
(void)config;
|
||||
(void)has_config;
|
||||
(void)shift_clock_high_us;
|
||||
(void)shift_clock_low_us;
|
||||
(void)latch_pulse_us;
|
||||
(void)strobe_active_high;
|
||||
(void)boost_active_high;
|
||||
(void)override_strobe_on_us;
|
||||
(void)override_strobe_interval_us;
|
||||
(void)override_motor_step_us;
|
||||
(void)override_steps_per_line;
|
||||
(void)reset_defaults;
|
||||
write_err(err, err_len, "direct backend disabled");
|
||||
return ESP_ERR_NOT_SUPPORTED;
|
||||
#else
|
||||
if (config == NULL && !reset_defaults) {
|
||||
if (!has_config && !reset_defaults) {
|
||||
write_err(err, err_len, "invalid args");
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
@@ -681,45 +743,48 @@ esp_err_t platform_direct_printer_set_debug_config(const platform_direct_debug_c
|
||||
set_debug_defaults_locked();
|
||||
}
|
||||
|
||||
if (config != NULL) {
|
||||
if (config->shift_clock_high_us < DEBUG_SHIFT_CLOCK_US_MIN ||
|
||||
config->shift_clock_high_us > DEBUG_SHIFT_CLOCK_US_MAX ||
|
||||
config->shift_clock_low_us < DEBUG_SHIFT_CLOCK_US_MIN ||
|
||||
config->shift_clock_low_us > DEBUG_SHIFT_CLOCK_US_MAX) {
|
||||
if (has_config) {
|
||||
if (shift_clock_high_us < DEBUG_SHIFT_CLOCK_US_MIN || shift_clock_high_us > DEBUG_SHIFT_CLOCK_US_MAX ||
|
||||
shift_clock_low_us < DEBUG_SHIFT_CLOCK_US_MIN || shift_clock_low_us > DEBUG_SHIFT_CLOCK_US_MAX) {
|
||||
xSemaphoreGive(s_state.lock);
|
||||
write_err(err, err_len, "shift clock us out of range (1..50)");
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
if (config->latch_pulse_us < DEBUG_LATCH_PULSE_US_MIN ||
|
||||
config->latch_pulse_us > DEBUG_LATCH_PULSE_US_MAX) {
|
||||
if (latch_pulse_us < DEBUG_LATCH_PULSE_US_MIN || latch_pulse_us > DEBUG_LATCH_PULSE_US_MAX) {
|
||||
xSemaphoreGive(s_state.lock);
|
||||
write_err(err, err_len, "latch pulse us out of range (1..50)");
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
if (config->override_strobe_on_us != 0 &&
|
||||
(config->override_strobe_on_us < 100 || config->override_strobe_on_us > 10000)) {
|
||||
if (override_strobe_on_us != 0 && (override_strobe_on_us < 100 || override_strobe_on_us > 10000)) {
|
||||
xSemaphoreGive(s_state.lock);
|
||||
write_err(err, err_len, "strobe_on_us must be 0 or 100..10000");
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
if (config->override_strobe_interval_us > 10000) {
|
||||
if (override_strobe_interval_us > 10000) {
|
||||
xSemaphoreGive(s_state.lock);
|
||||
write_err(err, err_len, "strobe_interval_us must be 0..10000");
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
if (config->override_motor_step_us != 0 &&
|
||||
(config->override_motor_step_us < 100 || config->override_motor_step_us > 20000)) {
|
||||
if (override_motor_step_us != 0 && (override_motor_step_us < 100 || override_motor_step_us > 20000)) {
|
||||
xSemaphoreGive(s_state.lock);
|
||||
write_err(err, err_len, "motor_step_us must be 0 or 100..20000");
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
if (config->override_steps_per_line > 8) {
|
||||
if (override_steps_per_line > 8) {
|
||||
xSemaphoreGive(s_state.lock);
|
||||
write_err(err, err_len, "steps_per_line must be 0..8");
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
s_state.debug = *config;
|
||||
s_state.debug.shift_clock_high_us = shift_clock_high_us;
|
||||
s_state.debug.shift_clock_low_us = shift_clock_low_us;
|
||||
s_state.debug.latch_pulse_us = latch_pulse_us;
|
||||
s_state.debug.strobe_active_high = strobe_active_high;
|
||||
s_state.debug.boost_active_high = boost_active_high;
|
||||
s_state.debug.override_strobe_on_us = override_strobe_on_us;
|
||||
s_state.debug.override_strobe_interval_us = override_strobe_interval_us;
|
||||
s_state.debug.override_motor_step_us = override_motor_step_us;
|
||||
s_state.debug.override_steps_per_line = override_steps_per_line;
|
||||
}
|
||||
|
||||
safe_drive_off_locked(s_state.connected);
|
||||
|
||||
@@ -292,7 +292,9 @@ void lcd_module_deinit(void)
|
||||
{
|
||||
#if CONFIG_TQ_SCREEN_ENABLE
|
||||
if (s_lcd.lock != NULL) {
|
||||
(void)xSemaphoreTake(s_lcd.lock, portMAX_DELAY);
|
||||
if (xSemaphoreTake(s_lcd.lock, pdMS_TO_TICKS(1000)) != pdTRUE) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (s_lcd.lv_disp != NULL) {
|
||||
|
||||
@@ -56,12 +56,18 @@ static void wifi_event_handler(void *arg,
|
||||
(void)event_data;
|
||||
|
||||
if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START) {
|
||||
if (!s_started) {
|
||||
return;
|
||||
}
|
||||
(void)esp_wifi_connect();
|
||||
return;
|
||||
}
|
||||
|
||||
if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED) {
|
||||
s_ready = false;
|
||||
if (!s_started) {
|
||||
return;
|
||||
}
|
||||
if (s_retry_num < CONFIG_TQ_WIFI_MAXIMUM_RETRY) {
|
||||
(void)esp_wifi_connect();
|
||||
s_retry_num++;
|
||||
@@ -73,6 +79,9 @@ static void wifi_event_handler(void *arg,
|
||||
}
|
||||
|
||||
if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) {
|
||||
if (!s_started) {
|
||||
return;
|
||||
}
|
||||
ip_event_got_ip_t *event = (ip_event_got_ip_t *)event_data;
|
||||
ESP_LOGI(TAG, "got ip:" IPSTR, IP2STR(&event->ip_info.ip));
|
||||
s_retry_num = 0;
|
||||
@@ -218,6 +227,7 @@ esp_err_t wifi_manager_start(void) {
|
||||
runtime_diag_counter_add(RUNTIME_DIAG_COUNTER_WIFI_CONNECT_FAILED, 1);
|
||||
}
|
||||
runtime_diag_record_error("wifi_connect", err, "STA connect failed");
|
||||
(void)wifi_manager_stop();
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user