feat(product-test): add UART automation flow
This commit is contained in:
@@ -10,6 +10,7 @@ idf_component_register(
|
||||
"src/platform_mic_key.c"
|
||||
"src/platform_power_key.c"
|
||||
"src/voice_audio.c"
|
||||
"src/product_test_uart.c"
|
||||
"src/runtime_policy.c"
|
||||
INCLUDE_DIRS
|
||||
"include"
|
||||
|
||||
@@ -37,6 +37,11 @@ typedef struct {
|
||||
bool has_paper;
|
||||
int8_t paper_gpio_level;
|
||||
uint8_t paper_present_level;
|
||||
bool battery_adc_ready;
|
||||
bool ntc_adc_ready;
|
||||
int battery_adc_raw;
|
||||
int ntc_adc_raw;
|
||||
uint16_t battery_mv;
|
||||
uint8_t battery_percent;
|
||||
float temperature_c;
|
||||
int64_t updated_ms;
|
||||
@@ -177,6 +182,21 @@ uint32_t runtime_policy_image_download_timeout_default_ms(void);
|
||||
uint32_t runtime_policy_image_download_timeout_min_ms(void);
|
||||
uint32_t runtime_policy_image_download_timeout_max_ms(void);
|
||||
|
||||
// ---------- product_test_uart ----------
|
||||
typedef struct {
|
||||
int port;
|
||||
int baud_rate;
|
||||
int tx_pin;
|
||||
int rx_pin;
|
||||
size_t rx_buffer_size;
|
||||
size_t tx_buffer_size;
|
||||
} platform_test_uart_config_t;
|
||||
|
||||
esp_err_t platform_test_uart_init(const platform_test_uart_config_t *cfg);
|
||||
void platform_test_uart_deinit(void);
|
||||
esp_err_t platform_test_uart_read_byte(uint8_t *out_byte, uint32_t timeout_ms);
|
||||
esp_err_t platform_test_uart_write_line(const char *line, uint32_t timeout_ms);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
207
components/platform/src/product_test_uart.c
Normal file
207
components/platform/src/product_test_uart.c
Normal file
@@ -0,0 +1,207 @@
|
||||
#include "platform.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "driver/uart.h"
|
||||
#include "esp_log.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/semphr.h"
|
||||
|
||||
static const char *TAG = "product_test_uart";
|
||||
|
||||
static SemaphoreHandle_t s_lock;
|
||||
static SemaphoreHandle_t s_output_lock;
|
||||
static uart_port_t s_uart_port = UART_NUM_MAX;
|
||||
static bool s_ready;
|
||||
static bool s_installed_by_us;
|
||||
|
||||
static bool valid_uart_port(int port) {
|
||||
return port >= 0 && port < UART_NUM_MAX;
|
||||
}
|
||||
|
||||
static esp_err_t ensure_output_lock(void) {
|
||||
if (s_output_lock == NULL) {
|
||||
s_output_lock = xSemaphoreCreateMutex();
|
||||
if (s_output_lock == NULL) {
|
||||
return ESP_ERR_NO_MEM;
|
||||
}
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static bool output_lock_take(uint32_t timeout_ms) {
|
||||
if (s_output_lock == NULL) {
|
||||
return true;
|
||||
}
|
||||
return xSemaphoreTake(s_output_lock, pdMS_TO_TICKS(timeout_ms)) == pdTRUE;
|
||||
}
|
||||
|
||||
static void output_lock_give(void) {
|
||||
if (s_output_lock != NULL) {
|
||||
xSemaphoreGive(s_output_lock);
|
||||
}
|
||||
}
|
||||
|
||||
esp_err_t platform_test_uart_init(const platform_test_uart_config_t *cfg) {
|
||||
if (cfg == NULL || !valid_uart_port(cfg->port) || cfg->baud_rate <= 0) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
if (s_lock == NULL) {
|
||||
s_lock = xSemaphoreCreateMutex();
|
||||
if (s_lock == NULL) {
|
||||
return ESP_ERR_NO_MEM;
|
||||
}
|
||||
}
|
||||
esp_err_t lock_rc = ensure_output_lock();
|
||||
if (lock_rc != ESP_OK) {
|
||||
return lock_rc;
|
||||
}
|
||||
|
||||
if (xSemaphoreTake(s_lock, pdMS_TO_TICKS(1000)) != pdTRUE) {
|
||||
return ESP_ERR_TIMEOUT;
|
||||
}
|
||||
|
||||
uart_port_t port = (uart_port_t)cfg->port;
|
||||
if (s_ready) {
|
||||
if (s_uart_port == port) {
|
||||
xSemaphoreGive(s_lock);
|
||||
return ESP_OK;
|
||||
}
|
||||
xSemaphoreGive(s_lock);
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
|
||||
bool already_installed = uart_is_driver_installed(port);
|
||||
if (!already_installed) {
|
||||
int rx_buffer_size = (int)(cfg->rx_buffer_size > 0 ? cfg->rx_buffer_size : 2048);
|
||||
int tx_buffer_size = (int)(cfg->tx_buffer_size > 0 ? cfg->tx_buffer_size : 1024);
|
||||
esp_err_t install_rc = uart_driver_install(port,
|
||||
rx_buffer_size,
|
||||
tx_buffer_size,
|
||||
0,
|
||||
NULL,
|
||||
0);
|
||||
if (install_rc != ESP_OK) {
|
||||
xSemaphoreGive(s_lock);
|
||||
return install_rc;
|
||||
}
|
||||
s_installed_by_us = true;
|
||||
} else {
|
||||
s_installed_by_us = false;
|
||||
}
|
||||
|
||||
uart_config_t uart_cfg = {
|
||||
.baud_rate = cfg->baud_rate,
|
||||
.data_bits = UART_DATA_8_BITS,
|
||||
.parity = UART_PARITY_DISABLE,
|
||||
.stop_bits = UART_STOP_BITS_1,
|
||||
.flow_ctrl = UART_HW_FLOWCTRL_DISABLE,
|
||||
.rx_flow_ctrl_thresh = 0,
|
||||
.source_clk = UART_SCLK_DEFAULT,
|
||||
};
|
||||
|
||||
esp_err_t rc = uart_param_config(port, &uart_cfg);
|
||||
if (rc == ESP_OK) {
|
||||
rc = uart_set_pin(port, cfg->tx_pin, cfg->rx_pin, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE);
|
||||
}
|
||||
if (rc == ESP_OK) {
|
||||
rc = uart_flush_input(port);
|
||||
}
|
||||
if (rc != ESP_OK) {
|
||||
if (s_installed_by_us && uart_is_driver_installed(port)) {
|
||||
(void)uart_driver_delete(port);
|
||||
}
|
||||
s_installed_by_us = false;
|
||||
xSemaphoreGive(s_lock);
|
||||
return rc;
|
||||
}
|
||||
|
||||
s_uart_port = port;
|
||||
s_ready = true;
|
||||
ESP_LOGI(TAG,
|
||||
"product test uart ready: port=%d baud=%d tx=%d rx=%d",
|
||||
cfg->port,
|
||||
cfg->baud_rate,
|
||||
cfg->tx_pin,
|
||||
cfg->rx_pin);
|
||||
|
||||
xSemaphoreGive(s_lock);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
void platform_test_uart_deinit(void) {
|
||||
if (s_lock == NULL) {
|
||||
return;
|
||||
}
|
||||
if (xSemaphoreTake(s_lock, pdMS_TO_TICKS(1000)) != pdTRUE) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (s_ready && s_installed_by_us && s_uart_port != UART_NUM_MAX && uart_is_driver_installed(s_uart_port)) {
|
||||
(void)uart_wait_tx_done(s_uart_port, pdMS_TO_TICKS(200));
|
||||
(void)uart_driver_delete(s_uart_port);
|
||||
}
|
||||
s_uart_port = UART_NUM_MAX;
|
||||
s_ready = false;
|
||||
s_installed_by_us = false;
|
||||
|
||||
xSemaphoreGive(s_lock);
|
||||
}
|
||||
|
||||
esp_err_t platform_test_uart_read_byte(uint8_t *out_byte, uint32_t timeout_ms) {
|
||||
if (out_byte == NULL) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
if (!s_ready || s_uart_port == UART_NUM_MAX) {
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
|
||||
int n = uart_read_bytes(s_uart_port, out_byte, 1, pdMS_TO_TICKS(timeout_ms));
|
||||
if (n == 1) {
|
||||
return ESP_OK;
|
||||
}
|
||||
if (n == 0) {
|
||||
return ESP_ERR_TIMEOUT;
|
||||
}
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
esp_err_t platform_test_uart_write_line(const char *line, uint32_t timeout_ms) {
|
||||
if (line == NULL) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
if (!s_ready || s_uart_port == UART_NUM_MAX) {
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
|
||||
size_t len = strlen(line);
|
||||
if (len == 0) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
if (!output_lock_take(timeout_ms)) {
|
||||
return ESP_ERR_TIMEOUT;
|
||||
}
|
||||
|
||||
flockfile(stdout);
|
||||
int n = uart_write_bytes(s_uart_port, line, len);
|
||||
if (n < 0 || (size_t)n != len) {
|
||||
funlockfile(stdout);
|
||||
output_lock_give();
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
int newline = uart_write_bytes(s_uart_port, "\r\n", 2);
|
||||
if (newline != 2) {
|
||||
funlockfile(stdout);
|
||||
output_lock_give();
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
esp_err_t rc = uart_wait_tx_done(s_uart_port, pdMS_TO_TICKS(timeout_ms));
|
||||
funlockfile(stdout);
|
||||
output_lock_give();
|
||||
return rc;
|
||||
}
|
||||
@@ -148,6 +148,11 @@ static void set_stb_level_locked(int level) {
|
||||
set_gpio_level_if_valid(CONFIG_TQ_PRINT_STB_56_PIN, out_level);
|
||||
}
|
||||
|
||||
static void set_stb_pin_level_locked(int gpio_num, int level) {
|
||||
int out_level = level ? strobe_active_level_locked() : strobe_idle_level_locked();
|
||||
set_gpio_level_if_valid(gpio_num, out_level);
|
||||
}
|
||||
|
||||
static void motor_apply_pattern_locked(uint8_t pattern) {
|
||||
set_gpio_level_if_valid(CONFIG_TQ_PRINT_OUTA_P_PIN, (pattern >> 0) & 0x01);
|
||||
set_gpio_level_if_valid(CONFIG_TQ_PRINT_OUTA_N_PIN, (pattern >> 1) & 0x01);
|
||||
@@ -176,15 +181,21 @@ static void pulse_latch_locked(void) {
|
||||
set_gpio_level_if_valid(CONFIG_TQ_PRINT_LAT_PIN, 1);
|
||||
}
|
||||
|
||||
static void fire_strobe_locked(uint16_t on_us, uint16_t interval_us) {
|
||||
set_stb_level_locked(1);
|
||||
static void fire_strobe_pin_locked(int gpio_num, uint16_t on_us, uint16_t interval_us) {
|
||||
set_stb_pin_level_locked(gpio_num, 1);
|
||||
esp_rom_delay_us(on_us);
|
||||
set_stb_level_locked(0);
|
||||
set_stb_pin_level_locked(gpio_num, 0);
|
||||
if (interval_us > 0) {
|
||||
esp_rom_delay_us(interval_us);
|
||||
}
|
||||
}
|
||||
|
||||
static void fire_strobe_locked(uint16_t on_us, uint16_t interval_us) {
|
||||
fire_strobe_pin_locked(CONFIG_TQ_PRINT_STB_12_PIN, on_us, interval_us);
|
||||
fire_strobe_pin_locked(CONFIG_TQ_PRINT_STB_34_PIN, on_us, interval_us);
|
||||
fire_strobe_pin_locked(CONFIG_TQ_PRINT_STB_56_PIN, on_us, interval_us);
|
||||
}
|
||||
|
||||
static void motor_step_once_locked(uint16_t step_delay_us) {
|
||||
uint8_t pattern = k_motor_step_table[s_state.motor_phase & 0x03];
|
||||
motor_apply_pattern_locked(pattern);
|
||||
@@ -384,18 +395,26 @@ static void sample_sensors_locked(platform_printer_sensors_t *out_sensors) {
|
||||
out_sensors->has_paper = read_paper_present_locked(&paper_level);
|
||||
out_sensors->paper_gpio_level = (int8_t)paper_level;
|
||||
out_sensors->paper_present_level = runtime_policy_printer_paper_present_level();
|
||||
out_sensors->battery_adc_ready = s_state.battery_adc.ready;
|
||||
out_sensors->ntc_adc_ready = s_state.ntc_adc.ready;
|
||||
out_sensors->battery_adc_raw = -1;
|
||||
out_sensors->ntc_adc_raw = -1;
|
||||
out_sensors->battery_mv = 0;
|
||||
out_sensors->battery_percent = 100;
|
||||
out_sensors->temperature_c = 25.0f;
|
||||
out_sensors->updated_ms = esp_timer_get_time() / 1000;
|
||||
|
||||
int battery_raw = 0;
|
||||
if (read_adc_raw_locked(&s_state.battery_adc, &battery_raw) == ESP_OK) {
|
||||
out_sensors->battery_adc_raw = battery_raw;
|
||||
uint16_t batt_mv = battery_raw_to_mv(battery_raw);
|
||||
out_sensors->battery_mv = batt_mv;
|
||||
out_sensors->battery_percent = battery_mv_to_percent(batt_mv);
|
||||
}
|
||||
|
||||
int ntc_raw = 0;
|
||||
if (read_adc_raw_locked(&s_state.ntc_adc, &ntc_raw) == ESP_OK) {
|
||||
out_sensors->ntc_adc_raw = ntc_raw;
|
||||
out_sensors->temperature_c = ntc_raw_to_temp_c(ntc_raw);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user