增加了语音抽签控制屏幕显示
增加了校准和财位控制电机旋转
This commit is contained in:
@@ -25,12 +25,15 @@ typedef enum {
|
||||
typedef enum {
|
||||
CONTROL_PLANE_MODEL_COMMAND_UNKNOWN = 0,
|
||||
CONTROL_PLANE_MODEL_COMMAND_DIRECTION,
|
||||
CONTROL_PLANE_MODEL_COMMAND_CALIBRATE
|
||||
CONTROL_PLANE_MODEL_COMMAND_CALIBRATE,
|
||||
CONTROL_PLANE_MODEL_COMMAND_CHOUQIAN
|
||||
} control_plane_model_command_type_t;
|
||||
|
||||
typedef void (*control_plane_model_command_callback_t)(
|
||||
control_plane_model_command_type_t command_type,
|
||||
const char *value,
|
||||
size_t value_index,
|
||||
bool value_index_valid,
|
||||
void *user_data);
|
||||
|
||||
typedef enum {
|
||||
|
||||
@@ -20,7 +20,9 @@ control_plane_direction_command_t control_plane_direction_parse_command_internal
|
||||
bool control_plane_extract_model_command(const char *text,
|
||||
control_plane_model_command_type_t *out_command_type,
|
||||
char *out_value,
|
||||
size_t out_value_capacity);
|
||||
size_t out_value_capacity,
|
||||
size_t *out_value_index,
|
||||
bool *out_value_index_valid);
|
||||
const char *control_plane_multimodal_resolve_upstream_mode(void);
|
||||
bool control_plane_multimodal_is_push2talk_mode(void);
|
||||
const char *control_plane_multimodal_resolve_voice_id(const char *auth_voice_id);
|
||||
|
||||
@@ -51,10 +51,44 @@ static const char *find_command_prefix(const char *text)
|
||||
return strstr(cursor, "/*{");
|
||||
}
|
||||
|
||||
static bool text_contains_chouqian_result(const char *text)
|
||||
{
|
||||
return text != NULL &&
|
||||
(strstr(text, "签文:") != NULL || strstr(text, "签文:") != NULL);
|
||||
}
|
||||
|
||||
static bool resolve_chouqian_result_index(const char *value, size_t *out_index)
|
||||
{
|
||||
static const char *const s_chouqian_result_names[] = {
|
||||
"卜运签",
|
||||
"和平签",
|
||||
"上上签",
|
||||
"小吉签",
|
||||
"中上签",
|
||||
};
|
||||
|
||||
if (value == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < sizeof(s_chouqian_result_names) / sizeof(s_chouqian_result_names[0]); ++i) {
|
||||
if (strcmp(value, s_chouqian_result_names[i]) == 0) {
|
||||
if (out_index != NULL) {
|
||||
*out_index = i;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool control_plane_extract_model_command(const char *text,
|
||||
control_plane_model_command_type_t *out_command_type,
|
||||
char *out_value,
|
||||
size_t out_value_capacity)
|
||||
size_t out_value_capacity,
|
||||
size_t *out_value_index,
|
||||
bool *out_value_index_valid)
|
||||
{
|
||||
if (text == NULL || out_command_type == NULL ||
|
||||
out_value == NULL || out_value_capacity == 0U) {
|
||||
@@ -63,9 +97,20 @@ bool control_plane_extract_model_command(const char *text,
|
||||
|
||||
*out_command_type = CONTROL_PLANE_MODEL_COMMAND_UNKNOWN;
|
||||
out_value[0] = '\0';
|
||||
if (out_value_index != NULL) {
|
||||
*out_value_index = 0U;
|
||||
}
|
||||
if (out_value_index_valid != NULL) {
|
||||
*out_value_index_valid = false;
|
||||
}
|
||||
|
||||
const char *command_start = find_command_prefix(text);
|
||||
if (command_start == NULL || command_start[0] != '/' || command_start[1] != '*') {
|
||||
if (text_contains_chouqian_result(text)) {
|
||||
*out_command_type = CONTROL_PLANE_MODEL_COMMAND_CHOUQIAN;
|
||||
strlcpy(out_value, "签文", out_value_capacity);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -101,6 +146,7 @@ bool control_plane_extract_model_command(const char *text,
|
||||
bool found = false;
|
||||
cJSON *direction = cJSON_GetObjectItemCaseSensitive(cmd_json, "转向");
|
||||
cJSON *calibrate = cJSON_GetObjectItemCaseSensitive(cmd_json, "校准");
|
||||
cJSON *chouqian = cJSON_GetObjectItemCaseSensitive(cmd_json, "抽签");
|
||||
|
||||
if (cJSON_IsString(direction) && direction->valuestring != NULL) {
|
||||
if (is_supported_model_direction(direction->valuestring)) {
|
||||
@@ -114,6 +160,19 @@ bool control_plane_extract_model_command(const char *text,
|
||||
strlcpy(out_value, calibrate->valuestring, out_value_capacity);
|
||||
found = true;
|
||||
}
|
||||
} else if (cJSON_IsString(chouqian) && chouqian->valuestring != NULL) {
|
||||
size_t result_index = 0U;
|
||||
if (resolve_chouqian_result_index(chouqian->valuestring, &result_index)) {
|
||||
*out_command_type = CONTROL_PLANE_MODEL_COMMAND_CHOUQIAN;
|
||||
strlcpy(out_value, chouqian->valuestring, out_value_capacity);
|
||||
if (out_value_index != NULL) {
|
||||
*out_value_index = result_index;
|
||||
}
|
||||
if (out_value_index_valid != NULL) {
|
||||
*out_value_index_valid = true;
|
||||
}
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
|
||||
cJSON_Delete(cmd_json);
|
||||
|
||||
@@ -197,7 +197,14 @@ static void control_plane_responding_text_bridge(const char *text,
|
||||
|
||||
control_plane_model_command_type_t command_type = CONTROL_PLANE_MODEL_COMMAND_UNKNOWN;
|
||||
char value[32] = {0};
|
||||
if (!control_plane_extract_model_command(text, &command_type, value, sizeof(value))) {
|
||||
size_t value_index = 0U;
|
||||
bool value_index_valid = false;
|
||||
if (!control_plane_extract_model_command(text,
|
||||
&command_type,
|
||||
value,
|
||||
sizeof(value),
|
||||
&value_index,
|
||||
&value_index_valid)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -213,8 +220,13 @@ static void control_plane_responding_text_bridge(const char *text,
|
||||
return;
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "Device command: type=%d value=%s", (int)command_type, value);
|
||||
cb(command_type, value, cb_user_data);
|
||||
ESP_LOGI(TAG,
|
||||
"Device command: type=%d value=%s index=%u valid=%d",
|
||||
(int)command_type,
|
||||
value,
|
||||
(unsigned int)value_index,
|
||||
value_index_valid ? 1 : 0);
|
||||
cb(command_type, value, value_index, value_index_valid, cb_user_data);
|
||||
}
|
||||
|
||||
static esp_err_t control_plane_prepare_for_multimodal_start(void)
|
||||
|
||||
@@ -47,6 +47,7 @@
|
||||
/* Liveness safety bound for the fixed two-cycle wealth spin intro (not the
|
||||
* animation length). On timeout the worker proceeds to reveal + rotate anyway. */
|
||||
#define CONTROL_PLANE_SPIN_INTRO_TIMEOUT_MS 6000
|
||||
#define CONTROL_PLANE_COMMAND_ROTATION_DEG 45.0f
|
||||
|
||||
#if (configSUPPORT_STATIC_ALLOCATION == 1) && \
|
||||
((defined(CONFIG_FREERTOS_TASK_CREATE_ALLOW_EXT_MEM) && CONFIG_FREERTOS_TASK_CREATE_ALLOW_EXT_MEM) || \
|
||||
@@ -128,6 +129,8 @@ typedef struct {
|
||||
control_plane_model_command_type_t command_type;
|
||||
bool stop_requested;
|
||||
char value[32];
|
||||
size_t value_index;
|
||||
bool value_index_valid;
|
||||
} control_plane_model_command_t;
|
||||
|
||||
typedef enum {
|
||||
@@ -654,6 +657,8 @@ static void control_plane_task_start_gate(void *arg)
|
||||
|
||||
static void control_plane_on_model_command(control_plane_model_command_type_t command_type,
|
||||
const char *value,
|
||||
size_t value_index,
|
||||
bool value_index_valid,
|
||||
void *user_data)
|
||||
{
|
||||
(void)user_data;
|
||||
@@ -667,6 +672,8 @@ static void control_plane_on_model_command(control_plane_model_command_type_t co
|
||||
.command_type = command_type,
|
||||
.stop_requested = false,
|
||||
.value = {0},
|
||||
.value_index = value_index,
|
||||
.value_index_valid = value_index_valid,
|
||||
};
|
||||
if (value != NULL) {
|
||||
strlcpy(cmd.value, value, sizeof(cmd.value));
|
||||
@@ -707,7 +714,33 @@ static esp_err_t control_plane_apply_wealth_direction(size_t direction_index,
|
||||
ESP_LOGW(TAG, "Wealth reveal request failed: %s", esp_err_to_name(reveal_err));
|
||||
}
|
||||
|
||||
return control_plane_rotate_to_direction(direction_index);
|
||||
(void)direction_index;
|
||||
|
||||
float current_angle = domain_get_current_angle();
|
||||
return control_plane_rotate_to_angle(current_angle + CONTROL_PLANE_COMMAND_ROTATION_DEG);
|
||||
}
|
||||
|
||||
static esp_err_t control_plane_run_model_calibration_motion(void)
|
||||
{
|
||||
float start_angle = domain_get_current_angle();
|
||||
|
||||
esp_err_t err = control_plane_rotate_to_angle(start_angle + CONTROL_PLANE_COMMAND_ROTATION_DEG);
|
||||
if (err != ESP_OK) {
|
||||
return err;
|
||||
}
|
||||
|
||||
return control_plane_rotate_to_angle(start_angle);
|
||||
}
|
||||
|
||||
static esp_err_t control_plane_show_chouqian_expression(size_t result_index, bool result_index_valid)
|
||||
{
|
||||
const domain_expression_request_t request = {
|
||||
.id = DOMAIN_EXPRESSION_CHOUQIAN,
|
||||
.trigger = DOMAIN_EXPRESSION_TRIGGER_MODEL_DIRECTION,
|
||||
.chouqian_result_index = result_index,
|
||||
.chouqian_result_index_valid = result_index_valid,
|
||||
};
|
||||
return domain_runtime_request_expression(&request);
|
||||
}
|
||||
|
||||
static void control_plane_model_command_task(void *arg)
|
||||
@@ -750,15 +783,22 @@ static void control_plane_model_command_task(void *arg)
|
||||
ESP_LOGW(TAG, "Unknown model direction: %s", cmd.value);
|
||||
}
|
||||
} else if (cmd.command_type == CONTROL_PLANE_MODEL_COMMAND_CALIBRATE) {
|
||||
ESP_LOGI(TAG, "Calibration triggered by model command");
|
||||
esp_err_t err = control_plane_calibrate();
|
||||
ESP_LOGI(TAG, "Calibration motion triggered by model command");
|
||||
esp_err_t err = control_plane_run_model_calibration_motion();
|
||||
if (err != ESP_OK) {
|
||||
if (err == ESP_ERR_TIMEOUT || err == ESP_ERR_INVALID_STATE) {
|
||||
ESP_LOGI(TAG, "Calibrate not completed: %s", esp_err_to_name(err));
|
||||
ESP_LOGI(TAG, "Calibration motion not completed: %s", esp_err_to_name(err));
|
||||
} else {
|
||||
ESP_LOGW(TAG, "Calibrate failed: %s", esp_err_to_name(err));
|
||||
ESP_LOGW(TAG, "Calibration motion failed: %s", esp_err_to_name(err));
|
||||
}
|
||||
}
|
||||
} else if (cmd.command_type == CONTROL_PLANE_MODEL_COMMAND_CHOUQIAN) {
|
||||
ESP_LOGI(TAG, "Chouqian triggered by model command: %s", cmd.value);
|
||||
esp_err_t err = control_plane_show_chouqian_expression(cmd.value_index,
|
||||
cmd.value_index_valid);
|
||||
if (err != ESP_OK && err != ESP_ERR_INVALID_STATE) {
|
||||
ESP_LOGW(TAG, "Chouqian expression failed: %s", esp_err_to_name(err));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user