Files
motor-controller/app/callback_task.c
robinson bbe8bd06bc refactor(callback_task): replace hardcoded dispatch with cmd_parser module
Separate command handlers into dedicated static functions registered
with cmd_parser, replacing the strcmp/strncmp chain.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-21 19:35:51 +08:00

263 lines
8.8 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#include "app.h"
#include "cmd_parser.h"
#include "cmsis_os2.h"
#include <string.h>
#include <stdlib.h>
#include "FreeRTOS.h"
#include "queue.h"
#include "stm32f4xx_hal.h"
typedef enum {
USER_CMD_IDLE = 0,
USER_CMD_RECEIVE,
} user_cmd_state;
static struct {
user_cmd_state state;
char buffer[MAX_CMD_LEN];
uint8_t index;
osMessageQueueId_t cmd_queue;
} g_cmd_parser;
/*
* 支持的命令(格式:@command\n:
* "motor enable" — 使能全部电机(零速启动)
* "motor enable yaw" — 使能 Yaw 电机
* "motor enable pitch" — 使能 Pitch 电机
* "motor disable" — 关闭全部电机(惰行 coast
* "motor disable yaw" — 关闭 Yaw 电机
* "motor disable pitch" — 关闭 Pitch 电机
* "sensor enable" — 恢复 IMU 读取
* "sensor disable" — 暂停 IMU 读取
* "sensorcali acc enable" — 开始加速度计标定
* "sensorcali acc disable" — 停止加速度计标定
* "sensorcali mag enable" — 开始磁场标定
* "sensorcali mag disable" — 停止磁场标定
*/
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
if (huart->Instance != USART1) return;
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
uint8_t rx = g_uart_rx_byte;
switch (g_cmd_parser.state) {
case USER_CMD_IDLE:
if (rx == '@') {
g_cmd_parser.state = USER_CMD_RECEIVE;
g_cmd_parser.index = 0;
}
break;
case USER_CMD_RECEIVE:
if (rx == '\n') {
/* 命令结束 —— null-terminate 并入队 */
if (g_cmd_parser.cmd_queue != NULL) {
g_cmd_parser.buffer[g_cmd_parser.index] = '\0';
xQueueSendFromISR(g_cmd_parser.cmd_queue,
g_cmd_parser.buffer,
&xHigherPriorityTaskWoken);
}
g_cmd_parser.state = USER_CMD_IDLE;
g_cmd_parser.index = 0;
} else if (rx == '\r') {
/* 忽略回车符(兼容终端发送 \r\n */
} else if (rx == '@') {
/* 重新开始 —— 取消当前输入 */
g_cmd_parser.index = 0;
} else {
if (g_cmd_parser.index < MAX_CMD_LEN - 1) {
g_cmd_parser.buffer[g_cmd_parser.index++] = (char)rx;
} else {
/* 缓冲区溢出 — 丢弃并等待下一个 @ */
g_cmd_parser.state = USER_CMD_IDLE;
g_cmd_parser.index = 0;
}
}
break;
}
/* 重新使能 UART 接收中断 */
HAL_UART_Receive_IT(huart, &g_uart_rx_byte, 1);
portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
}
/* ============================================================================
* Command handlers (registered with cmd_parser)
* ============================================================================ */
static int cmd_help(void *ctx, int argc, char **argv)
{
(void)ctx; (void)argc; (void)argv;
log_printf("[cmd] available commands:\r\n"
" help ==> show this message\r\n"
" motor enable [yaw|pitch] ==> enable motor(s), default both\r\n"
" motor disable [yaw|pitch] ==> disable motor(s), default both\r\n"
" sensor enable ==> resume IMU data publishing\r\n"
" sensor disable ==> pause IMU data publishing\r\n"
" sensorcali acc enable ==> start accelerometer calibration\r\n"
" sensorcali acc disable ==> stop accelerometer calibration\r\n"
" sensorcali mag enable ==> start magnetometer calibration\r\n"
" sensorcali mag disable ==> stop magnetometer calibration\r\n"
" pid ==> show all PID coefficients\r\n"
" pid <axis> <p> <v> ==> set PID param (v÷10=实际值, motor disabled)\r\n"
" axis: roll|pitch, p: kp|ki|kd, v: float\r\n");
return 0;
}
static int cmd_motor(void *ctx, int argc, char **argv)
{
(void)ctx;
if (argc < 2) return -1;
if (strcmp(argv[1], "enable") == 0) {
if (argc == 2) {
gimbal_motor_enable();
log_printf("[cmd] both motors enabled\r\n");
} else if (strcmp(argv[2], "yaw") == 0) {
gimbal_motor_enable_id(GIMBAL_MOTOR_YAW);
log_printf("[cmd] yaw motor enabled\r\n");
} else if (strcmp(argv[2], "pitch") == 0) {
gimbal_motor_enable_id(GIMBAL_MOTOR_PITCH);
log_printf("[cmd] pitch motor enabled\r\n");
} else {
log_printf("[cmd] unknown motor: %s\r\n", argv[2]);
}
return 0;
}
if (strcmp(argv[1], "disable") == 0) {
if (argc == 2) {
gimbal_motor_disable();
log_printf("[cmd] both motors disabled\r\n");
} else if (strcmp(argv[2], "yaw") == 0) {
gimbal_motor_disable_id(GIMBAL_MOTOR_YAW);
log_printf("[cmd] yaw motor disabled\r\n");
} else if (strcmp(argv[2], "pitch") == 0) {
gimbal_motor_disable_id(GIMBAL_MOTOR_PITCH);
log_printf("[cmd] pitch motor disabled\r\n");
} else {
log_printf("[cmd] unknown motor: %s\r\n", argv[2]);
}
return 0;
}
return -1;
}
static int cmd_sensor(void *ctx, int argc, char **argv)
{
(void)ctx;
if (argc < 2) return -1;
if (strcmp(argv[1], "enable") == 0) {
sensor_enable();
log_printf("[cmd] sensor enabled\r\n");
} else if (strcmp(argv[1], "disable") == 0) {
sensor_disable();
log_printf("[cmd] sensor disabled\r\n");
} else {
return -1;
}
return 0;
}
static int cmd_sensorcali(void *ctx, int argc, char **argv)
{
(void)ctx;
if (argc < 3) return -1;
if (strcmp(argv[1], "acc") == 0) {
if (strcmp(argv[2], "enable") == 0) {
sensor_acc_cali_enable();
log_printf("[cmd] acc calibration started\r\n");
} else if (strcmp(argv[2], "disable") == 0) {
sensor_acc_cali_disable();
log_printf("[cmd] acc calibration stopped\r\n");
} else {
return -1;
}
} else if (strcmp(argv[1], "mag") == 0) {
if (strcmp(argv[2], "enable") == 0) {
sensor_mag_cali_enable();
log_printf("[cmd] mag calibration started\r\n");
} else if (strcmp(argv[2], "disable") == 0) {
sensor_mag_cali_disable();
log_printf("[cmd] mag calibration stopped\r\n");
} else {
return -1;
}
} else {
return -1;
}
return 0;
}
static int cmd_pid(void *ctx, int argc, char **argv)
{
(void)ctx;
if (argc == 1) {
float kp, ki, kd;
gimbal_get_pid("roll", &kp, &ki, &kd);
log_printf("[cmd] Roll: Kp=%d Ki=%d Kd=%d\r\n",
(int)(kp * 10.0f), (int)(ki * 10.0f), (int)(kd * 10.0f));
gimbal_get_pid("pitch", &kp, &ki, &kd);
log_printf("[cmd] Pitch: Kp=%d Ki=%d Kd=%d\r\n",
(int)(kp * 10.0f), (int)(ki * 10.0f), (int)(kd * 10.0f));
return 0;
}
if (argc == 4) {
if (gimbal_is_motor_enabled()) {
log_printf("[cmd] ERROR: disable motor first (motor disable)\r\n");
return 0;
}
char *end;
long int_val = strtol(argv[3], &end, 10);
if (*end != '\0' || end == argv[3]) {
log_printf("[cmd] usage: pid <roll|pitch> <kp|ki|kd> <value>\r\n");
return 0;
}
float value = (float)int_val / 10.0f;
if (gimbal_set_pid(argv[1], argv[2], value) == 0) {
log_printf("[cmd] pid.%s.%s = %ld\r\n", argv[1], argv[2], int_val);
} else {
log_printf("[cmd] usage: pid <roll|pitch> <kp|ki|kd> <value>\r\n");
}
return 0;
}
return -1;
}
void callback_task(void)
{
char cmd_buf[MAX_CMD_LEN];
char disp_buf[MAX_CMD_LEN];
cmd_parser_t parser;
g_cmd_parser.state = USER_CMD_IDLE;
g_cmd_parser.index = 0;
g_cmd_parser.cmd_queue = g_cmd_queue;
cmd_parser_init(&parser);
cmd_parser_register(&parser, "help", cmd_help);
cmd_parser_register(&parser, "motor", cmd_motor);
cmd_parser_register(&parser, "sensor", cmd_sensor);
cmd_parser_register(&parser, "sensorcali", cmd_sensorcali);
cmd_parser_register(&parser, "pid", cmd_pid);
while (1) {
osStatus_t qstat = osMessageQueueGet(g_cmd_queue, cmd_buf, NULL, osWaitForever);
if (qstat != osOK) continue;
if (cmd_buf[0] == '\0') continue;
memcpy(disp_buf, cmd_buf, MAX_CMD_LEN);
if (cmd_parser_dispatch(&parser, cmd_buf, NULL) != 0) {
log_printf("[cmd] unknown: %s\r\n", disp_buf);
}
}
}