/** * @file mrobot.h * @brief MRobot CLI - 基于 FreeRTOS CLI 的嵌入式调试命令行系统 * * 功能特性: * - 设备注册与监控(IMU、电机、传感器等) * - 类 Unix 文件系统命令(cd, ls, pwd) * - htop 风格的任务监控 * - 自定义命令扩展 * - 线程安全设计 * * @example IMU 设备注册示例 * @code * // 1. 定义 IMU 数据结构 * typedef struct { * bool online; * float accl[3]; * float gyro[3]; * float euler[3]; // roll, pitch, yaw (deg) * float temp; * } MyIMU_t; * * MyIMU_t my_imu; * * // 2. 实现打印回调 * static int print_imu(const void *data, char *buf, size_t size) { * const MyIMU_t *imu = (const MyIMU_t *)data; * char ax[16], ay[16], az[16], r[16], p[16], y[16], t[16]; * MRobot_FormatFloat(ax, 16, imu->accl[0], 3); * MRobot_FormatFloat(ay, 16, imu->accl[1], 3); * MRobot_FormatFloat(az, 16, imu->accl[2], 3); * MRobot_FormatFloat(r, 16, imu->euler[0], 2); * MRobot_FormatFloat(p, 16, imu->euler[1], 2); * MRobot_FormatFloat(y, 16, imu->euler[2], 2); * MRobot_FormatFloat(t, 16, imu->temp, 1); * return snprintf(buf, size, * " Status: %s\r\n" * " Accel : X=%s Y=%s Z=%s\r\n" * " Euler : R=%s P=%s Y=%s\r\n" * " Temp : %s C\r\n", * imu->online ? "Online" : "Offline", ax, ay, az, r, p, y, t); * } * * // 3. 注册设备 * MRobot_RegisterDevice("imu", &my_imu, print_imu); * @endcode * * @example 电机设备注册示例 * @code * typedef struct { * bool online; * float angle; // deg * float speed; // RPM * float current; // A * } MyMotor_t; * * MyMotor_t motor[4]; * * static int print_motor(const void *data, char *buf, size_t size) { * const MyMotor_t *m = (const MyMotor_t *)data; * char ang[16], spd[16], cur[16]; * MRobot_FormatFloat(ang, 16, m->angle, 2); * MRobot_FormatFloat(spd, 16, m->speed, 1); * MRobot_FormatFloat(cur, 16, m->current, 3); * return snprintf(buf, size, * " Status : %s\r\n" * " Angle : %s deg\r\n" * " Speed : %s RPM\r\n" * " Current: %s A\r\n", * m->online ? "Online" : "Offline", ang, spd, cur); * } * * // 注册 4 个电机 * MRobot_RegisterDevice("motor0", &motor[0], print_motor); * MRobot_RegisterDevice("motor1", &motor[1], print_motor); * MRobot_RegisterDevice("motor2", &motor[2], print_motor); * MRobot_RegisterDevice("motor3", &motor[3], print_motor); * @endcode * * @example 自定义校准命令示例 * @code * // 校准数据 * static float gyro_offset[3] = {0}; * * // 命令回调: cali gyro / cali accel / cali save * static long cmd_cali(char *buf, size_t size, const char *cmd) { * const char *param = FreeRTOS_CLIGetParameter(cmd, 1, NULL); * * if (param == NULL) { * return snprintf(buf, size, "Usage: cali \r\n"); * } * if (strncmp(param, "gyro", 4) == 0) { * // 采集 1000 次陀螺仪数据求平均 * snprintf(buf, size, "Calibrating gyro... keep IMU still!\r\n"); * // ... 校准逻辑 ... * return 0; * } * if (strncmp(param, "save", 4) == 0) { * // 保存到 Flash * snprintf(buf, size, "Calibration saved to flash.\r\n"); * return 0; * } * return snprintf(buf, size, "Unknown: %s\r\n", param); * } * * // 注册命令 * MRobot_RegisterCommand("cali", "cali : IMU calibration\r\n", cmd_cali, -1); * @endcode */ #pragma once #ifdef __cplusplus extern "C" { #endif /* Includes ----------------------------------------------------------------- */ #include #include #include #include "bsp/uart.h" /* Configuration ------------------------------------------------------------ */ /* 可在编译时通过 -D 选项覆盖这些默认值 */ #ifndef MROBOT_MAX_DEVICES #define MROBOT_MAX_DEVICES 32 /* 最大设备数 */ #endif #ifndef MROBOT_MAX_CUSTOM_COMMANDS #define MROBOT_MAX_CUSTOM_COMMANDS 16 /* 最大自定义命令数 */ #endif #ifndef MROBOT_CMD_BUFFER_SIZE #define MROBOT_CMD_BUFFER_SIZE 128 /* 命令缓冲区大小 */ #endif #ifndef MROBOT_OUTPUT_BUFFER_SIZE #define MROBOT_OUTPUT_BUFFER_SIZE 512 /* 输出缓冲区大小 */ #endif #ifndef MROBOT_DEVICE_NAME_LEN #define MROBOT_DEVICE_NAME_LEN 32 /* 设备名最大长度 */ #endif #ifndef MROBOT_PATH_MAX_LEN #define MROBOT_PATH_MAX_LEN 64 /* 路径最大长度 */ #endif #ifndef MROBOT_HTOP_REFRESH_MS #define MROBOT_HTOP_REFRESH_MS 200 /* htop 刷新间隔 (ms) */ #endif #ifndef MROBOT_UART_PORT #define MROBOT_UART_PORT BSP_UART_VOFA /* 默认 UART 端口 */ #endif #ifndef MROBOT_USER_NAME #define MROBOT_USER_NAME "Robofish" /* CLI 用户名 */ #endif #ifndef MROBOT_HOST_NAME #define MROBOT_HOST_NAME "balance_infantry" /* CLI 主机名 */ #endif /* Error codes -------------------------------------------------------------- */ typedef enum { MROBOT_OK = 0, /* 成功 */ MROBOT_ERR_FULL = -1, /* 容量已满 */ MROBOT_ERR_NULL_PTR = -2, /* 空指针 */ MROBOT_ERR_INVALID_ARG = -3, /* 无效参数 */ MROBOT_ERR_NOT_FOUND = -4, /* 未找到 */ MROBOT_ERR_ALLOC = -5, /* 内存分配失败 */ MROBOT_ERR_BUSY = -6, /* 设备忙 */ MROBOT_ERR_NOT_INIT = -7, /* 未初始化 */ } MRobot_Error_t; /* CLI 运行状态 */ typedef enum { MROBOT_STATE_IDLE, /* 空闲状态,等待输入 */ MROBOT_STATE_HTOP, /* htop 模式 */ MROBOT_STATE_PROCESSING, /* 正在处理命令 */ } MRobot_State_t; /* Callback types ----------------------------------------------------------- */ /** * @brief 设备打印回调函数类型 * @param device_data 用户注册时传入的设备数据指针 * @param buffer 输出缓冲区 * @param buffer_size 缓冲区大小 * @return 实际写入的字节数 * @note 用户需要自行实现此函数来格式化设备数据 */ typedef int (*MRobot_PrintCallback_t)(const void *device_data, char *buffer, size_t buffer_size); /** * @brief 命令处理回调函数类型(与 FreeRTOS CLI 兼容) */ typedef long (*MRobot_CommandCallback_t)(char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString); /* Device structure --------------------------------------------------------- */ typedef struct { char name[MROBOT_DEVICE_NAME_LEN]; /* 设备名称 */ void *data; /* 用户设备数据指针 */ MRobot_PrintCallback_t print_cb; /* 用户打印回调函数 */ } MRobot_Device_t; /* Public API --------------------------------------------------------------- */ /** * @brief 初始化 MRobot CLI 系统 * @note 必须在 FreeRTOS 调度器启动后调用 */ void MRobot_Init(void); /** * @brief 反初始化 MRobot CLI 系统,释放资源 */ void MRobot_DeInit(void); /** * @brief 获取当前 CLI 状态 * @return MRobot_State_t 当前状态 */ MRobot_State_t MRobot_GetState(void); /** * @brief 注册设备到 MRobot 系统 * @param name 设备名称(会被截断到 MROBOT_DEVICE_NAME_LEN-1) * @param data 设备数据指针(不能为 NULL) * @param print_cb 打印回调函数(可为 NULL,但无法用 show 命令查看) * @return MRobot_Error_t 错误码 */ MRobot_Error_t MRobot_RegisterDevice(const char *name, void *data, MRobot_PrintCallback_t print_cb); /** * @brief 注销设备 * @param name 设备名称 * @return MRobot_Error_t 错误码 */ MRobot_Error_t MRobot_UnregisterDevice(const char *name); /** * @brief 注册自定义命令 * @param command 命令名称 * @param help_text 帮助文本 * @param callback 命令回调函数 * @param param_count 参数个数(-1 表示可变参数) * @return MRobot_Error_t 错误码 */ MRobot_Error_t MRobot_RegisterCommand(const char *command, const char *help_text, MRobot_CommandCallback_t callback, int8_t param_count); /** * @brief 获取已注册设备数量 * @return 设备数量 */ uint8_t MRobot_GetDeviceCount(void); /** * @brief 根据名称查找设备 * @param name 设备名称 * @return 设备指针,未找到返回 NULL */ const MRobot_Device_t *MRobot_FindDevice(const char *name); /** * @brief MRobot 主循环,在 CLI 任务中周期性调用 * @note 建议调用周期 10ms */ void MRobot_Run(void); /** * @brief 发送字符串到 CLI 终端(线程安全) * @param str 要发送的字符串 * @return MRobot_Error_t 错误码 */ MRobot_Error_t MRobot_Print(const char *str); /** * @brief 格式化输出到 CLI 终端(线程安全) * @param fmt 格式字符串 * @param ... 可变参数 * @return 实际输出的字符数,失败返回负数 */ int MRobot_Printf(const char *fmt, ...); /* Utility functions -------------------------------------------------------- */ /** * @brief 格式化浮点数为字符串(嵌入式环境不支持 %f) * @param buf 输出缓冲区 * @param size 缓冲区大小 * @param val 要格式化的浮点数 * @param precision 小数位数 (0-6) * @return 写入的字符数 * * @example * char buf[16]; * MRobot_FormatFloat(buf, sizeof(buf), 3.14159f, 2); // "3.14" * MRobot_FormatFloat(buf, sizeof(buf), -0.001f, 4); // "-0.0010" */ int MRobot_FormatFloat(char *buf, size_t size, float val, int precision); #ifdef __cplusplus } #endif