/* Includes ----------------------------------------------------------------- */ #include "device/mrobot.h" #include "component/freertos_cli.h" #include "bsp/uart.h" #include #include #include #include /* Private variables -------------------------------------------------------- */ static MRobot_Device_t devices[MROBOT_MAX_DEVICES]; static uint8_t device_count = 0; static char current_path[64] = "/"; static char output_buffer[MROBOT_MAX_OUTPUT_LEN]; /* UART 相关变量 */ static uint8_t uart_rx_char; static uint8_t cmd_buffer[128]; static volatile uint8_t cmd_index = 0; static volatile bool cmd_ready = false; static volatile bool htop_mode = false; static volatile bool htop_exit = false; static volatile bool tx_complete = true; /* Private function prototypes ---------------------------------------------- */ static BaseType_t cmd_help(char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString); static BaseType_t cmd_htop(char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString); static BaseType_t cmd_cd(char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString); static BaseType_t cmd_ls(char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString); static BaseType_t cmd_show(char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString); static BaseType_t cmd_pwd(char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString); /* CLI 命令定义 */ static const CLI_Command_Definition_t cmd_def_help = { "help", "help: 显示所有可用命令\r\n", cmd_help, 0 }; static const CLI_Command_Definition_t cmd_def_htop = { "htop", "htop: 动态显示 FreeRTOS 任务状态 (按 'q' 退出)\r\n", cmd_htop, 0 }; static const CLI_Command_Definition_t cmd_def_cd = { "cd", "cd : 切换目录\r\n", cmd_cd, 1 }; static const CLI_Command_Definition_t cmd_def_ls = { "ls", "ls: 列出当前目录内容\r\n", cmd_ls, 0 }; static const CLI_Command_Definition_t cmd_def_show = { "show", "show [device]: 显示设备信息\r\n", cmd_show, -1 /* 可变参数 */ }; static const CLI_Command_Definition_t cmd_def_pwd = { "pwd", "pwd: 显示当前目录\r\n", cmd_pwd, 0 }; /* Private functions -------------------------------------------------------- */ /* help 命令实现 */ static BaseType_t cmd_help(char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString) { (void)pcCommandString; snprintf(pcWriteBuffer, xWriteBufferLen, "MRobot CLI v1.0\r\n" "可用命令:\r\n" " help - 显示帮助信息\r\n" " htop - 动态显示任务状态 (按 'q' 退出)\r\n" " cd - 切换目录\r\n" " ls - 列出目录内容\r\n" " pwd - 显示当前路径\r\n" " show - 显示设备信息\r\n" "\r\n"); return pdFALSE; } /* htop 命令实现 - 由 cli.c 处理动态显示 */ static BaseType_t cmd_htop(char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString) { (void)pcCommandString; (void)pcWriteBuffer; (void)xWriteBufferLen; /* htop 命令在 cli.c 中被特殊处理,这里返回空 */ return pdFALSE; } /* pwd 命令实现 */ static BaseType_t cmd_pwd(char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString) { (void)pcCommandString; snprintf(pcWriteBuffer, xWriteBufferLen, "%s\r\n", current_path); return pdFALSE; } /* cd 命令实现 */ static BaseType_t cmd_cd(char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString) { const char *param; BaseType_t param_len; param = FreeRTOS_CLIGetParameter(pcCommandString, 1, ¶m_len); if (param != NULL) { char path[64]; strncpy(path, param, param_len); path[param_len] = '\0'; if (strcmp(path, "/") == 0 || strcmp(path, "..") == 0) { strcpy(current_path, "/"); } else if (strcmp(path, "dev") == 0 || strcmp(path, "/dev") == 0) { strcpy(current_path, "/dev"); } else if (strcmp(path, "modules") == 0 || strcmp(path, "/modules") == 0) { strcpy(current_path, "/modules"); } else { snprintf(pcWriteBuffer, xWriteBufferLen, "错误: 目录不存在\r\n"); return pdFALSE; } snprintf(pcWriteBuffer, xWriteBufferLen, "切换到: %s\r\n", current_path); } else { snprintf(pcWriteBuffer, xWriteBufferLen, "错误: 缺少路径参数\r\n"); } return pdFALSE; } /* ls 命令实现 */ static BaseType_t cmd_ls(char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString) { (void)pcCommandString; int offset = 0; if (strcmp(current_path, "/") == 0) { offset = snprintf(pcWriteBuffer, xWriteBufferLen, "dev/\r\nmodules/\r\n"); } else if (strcmp(current_path, "/dev") == 0) { offset = snprintf(pcWriteBuffer, xWriteBufferLen, "设备列表:\r\n"); for (uint8_t i = 0; i < device_count && offset < (int)xWriteBufferLen; i++) { offset += snprintf(pcWriteBuffer + offset, xWriteBufferLen - offset, " %s\r\n", devices[i].name); } if (device_count == 0) { offset += snprintf(pcWriteBuffer + offset, xWriteBufferLen - offset, " (无设备)\r\n"); } } else if (strcmp(current_path, "/modules") == 0) { offset = snprintf(pcWriteBuffer, xWriteBufferLen, "(模块功能暂未实现)\r\n"); } return pdFALSE; } /* show 命令实现 */ static BaseType_t cmd_show(char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString) { const char *param; BaseType_t param_len; param = FreeRTOS_CLIGetParameter(pcCommandString, 1, ¶m_len); if (strcmp(current_path, "/dev") != 0) { snprintf(pcWriteBuffer, xWriteBufferLen, "错误: show 命令仅在 /dev 目录下可用\r\n"); return pdFALSE; } if (param == NULL) { /* 显示所有设备 */ int offset = snprintf(pcWriteBuffer, xWriteBufferLen, "所有设备信息:\r\n"); for (uint8_t i = 0; i < device_count && offset < (int)xWriteBufferLen; i++) { offset += snprintf(pcWriteBuffer + offset, xWriteBufferLen - offset, "\r\n=== %s ===\r\n", devices[i].name); if (devices[i].print_callback != NULL) { devices[i].print_callback(devices[i].data, pcWriteBuffer + offset, xWriteBufferLen - offset); offset = strlen(pcWriteBuffer); } } } else { /* 显示特定设备 */ char device_name[32]; strncpy(device_name, param, param_len); device_name[param_len] = '\0'; bool found = false; for (uint8_t i = 0; i < device_count; i++) { if (strcmp(devices[i].name, device_name) == 0) { found = true; int offset = snprintf(pcWriteBuffer, xWriteBufferLen, "=== %s ===\r\n", devices[i].name); if (devices[i].print_callback != NULL) { devices[i].print_callback(devices[i].data, pcWriteBuffer + offset, xWriteBufferLen - offset); } else { snprintf(pcWriteBuffer + offset, xWriteBufferLen - offset, "无打印函数\r\n"); } break; } } if (!found) { snprintf(pcWriteBuffer, xWriteBufferLen, "错误: 设备 '%s' 未找到\r\n", device_name); } } return pdFALSE; } /* UART 发送完成回调 */ static void mrobot_uart_tx_callback(void) { tx_complete = true; } /* UART 接收中断回调 */ static void mrobot_uart_rx_callback(void) { uint8_t ch = uart_rx_char; /* 如果在 htop 模式,检查退出键 */ if (htop_mode) { if (ch == 'q' || ch == 'Q' || ch == 27) { /* q 或 ESC */ htop_exit = true; } /* 重新启动接收 */ BSP_UART_Receive(BSP_UART_VOFA, &uart_rx_char, 1, false); return; } if (ch == '\r' || ch == '\n') { if (cmd_index > 0) { cmd_buffer[cmd_index] = '\0'; cmd_ready = true; /* 换行使用中断方式发送(数据量小) */ BSP_UART_Transmit(BSP_UART_VOFA, (uint8_t *)"\r\n", 2, false); } } else if (ch == 127 || ch == 8) { /* 退格键 */ if (cmd_index > 0) { cmd_index--; /* 回显退格(中断方式) */ const char *backspace = "\b \b"; BSP_UART_Transmit(BSP_UART_VOFA, (uint8_t *)backspace, 3, false); } } else if (ch >= 32 && ch < 127 && cmd_index < sizeof(cmd_buffer) - 1) { /* 只接受可打印字符 */ cmd_buffer[cmd_index++] = ch; /* 回显字符(中断方式) */ BSP_UART_Transmit(BSP_UART_VOFA, &ch, 1, false); } /* 重新启动接收 */ BSP_UART_Receive(BSP_UART_VOFA, &uart_rx_char, 1, false); } /* Exported functions ------------------------------------------------------- */ void MRobot_Init(void) { /* 初始化设备数组 */ memset(devices, 0, sizeof(devices)); device_count = 0; /* 注册 CLI 命令 */ FreeRTOS_CLIRegisterCommand(&cmd_def_help); FreeRTOS_CLIRegisterCommand(&cmd_def_htop); FreeRTOS_CLIRegisterCommand(&cmd_def_cd); FreeRTOS_CLIRegisterCommand(&cmd_def_ls); FreeRTOS_CLIRegisterCommand(&cmd_def_show); FreeRTOS_CLIRegisterCommand(&cmd_def_pwd); /* 注册 UART 回调 */ BSP_UART_RegisterCallback(BSP_UART_VOFA, BSP_UART_RX_CPLT_CB, mrobot_uart_rx_callback); BSP_UART_RegisterCallback(BSP_UART_VOFA, BSP_UART_TX_CPLT_CB, mrobot_uart_tx_callback); /* 启动 UART 接收 */ BSP_UART_Receive(BSP_UART_VOFA, &uart_rx_char, 1, false); /* 发送欢迎消息 */ const char *welcome = "\r\n\r\n" "================================\r\n" " MRobot CLI v1.0\r\n" " 输入 'help' 获取帮助\r\n" "================================\r\n" "root@mrobot:~$ "; tx_complete = false; BSP_UART_Transmit(BSP_UART_VOFA, (uint8_t *)welcome, strlen(welcome), true); while (!tx_complete) { osDelay(1); } /* 等待发送完成 */ } int8_t MRobot_RegisterDevice(const char *name, MRobot_DeviceType_t type, void *data, MRobot_PrintCallback_t print_callback) { if (device_count >= MROBOT_MAX_DEVICES) { return -1; } if (name == NULL || data == NULL) { return -1; } strncpy(devices[device_count].name, name, sizeof(devices[device_count].name) - 1); devices[device_count].type = type; devices[device_count].data = data; devices[device_count].print_callback = print_callback; device_count++; return 0; } void MRobot_Run(void) { /* 动态 htop 模式 */ if (htop_mode) { /* 清屏并重置光标 */ const char *clear = "\033[2J\033[H"; tx_complete = false; BSP_UART_Transmit(BSP_UART_VOFA, (uint8_t *)clear, strlen(clear), true); while (!tx_complete) { osDelay(1); } /* 等待发送完成 */ /* 显示 htop 头部 */ const char *header = "MRobot Task Monitor (按 'q' 退出)\r\n" "================================================================================\r\n"; tx_complete = false; BSP_UART_Transmit(BSP_UART_VOFA, (uint8_t *)header, strlen(header), true); while (!tx_complete) { osDelay(1); } /* 等待发送完成 */ /* 获取任务列表 */ char task_buffer[1024]; vTaskList(task_buffer); /* 格式化输出 */ char display_buffer[1536]; int offset = snprintf(display_buffer, sizeof(display_buffer), "%-16s %-8s %-4s %-8s %-4s\r\n" "--------------------------------------------------------------------------------\r\n", "Task Name", "State", "Prio", "Stack", "Num"); /* 解析并美化任务列表 */ char *line = strtok(task_buffer, "\r\n"); while (line != NULL && offset < (int)sizeof(display_buffer) - 100) { char name[17] = {0}; char state[9] = {0}; int prio = 0; int stack = 0; int num = 0; if (sscanf(line, "%16s %c %d %d %d", name, &state[0], &prio, &stack, &num) == 5) { /* 状态字符转换 */ const char *state_str = "?"; switch(state[0]) { case 'R': state_str = "Running"; break; case 'B': state_str = "Blocked"; break; case 'S': state_str = "Suspend"; break; case 'D': state_str = "Deleted"; break; default: state_str = "Unknown"; break; } offset += snprintf(display_buffer + offset, sizeof(display_buffer) - offset, "%-16s %-8s %-4d %-8d %-4d\r\n", name, state_str, prio, stack, num); } line = strtok(NULL, "\r\n"); } /* 添加运行时统计 */ offset += snprintf(display_buffer + offset, sizeof(display_buffer) - offset, "--------------------------------------------------------------------------------\r\n" "System Tick: %lu\r\n", (unsigned long)xTaskGetTickCount()); tx_complete = false; BSP_UART_Transmit(BSP_UART_VOFA, (uint8_t *)display_buffer, strlen(display_buffer), true); while (!tx_complete) { osDelay(1); } /* 等待发送完成 */ /* 检查退出标志 */ if (htop_exit) { htop_mode = false; htop_exit = false; /* 清屏 */ tx_complete = false; BSP_UART_Transmit(BSP_UART_VOFA, (uint8_t *)clear, strlen(clear), true); while (!tx_complete) { osDelay(1); } /* 等待发送完成 */ /* 显示提示符 */ char prompt[128]; snprintf(prompt, sizeof(prompt), "root@mrobot:%s$ ", current_path); tx_complete = false; BSP_UART_Transmit(BSP_UART_VOFA, (uint8_t *)prompt, strlen(prompt), true); while (!tx_complete) { osDelay(1); } /* 等待发送完成 */ } osDelay(200); /* 每 200ms 刷新一次,5fps */ return; } /* 检查是否有命令需要处理 */ if (cmd_ready) { /* 检查是否是 htop 命令 */ if (strcmp((char *)cmd_buffer, "htop") == 0) { htop_mode = true; htop_exit = false; } else { /* 处理其他命令 */ BaseType_t result; int offset = 0; do { result = FreeRTOS_CLIProcessCommand((char *)cmd_buffer, output_buffer + offset, sizeof(output_buffer) - offset); offset = strlen(output_buffer); } while (result != pdFALSE && offset < (int)sizeof(output_buffer)); if (strlen(output_buffer) > 0) { tx_complete = false; BSP_UART_Transmit(BSP_UART_VOFA, (uint8_t *)output_buffer, strlen(output_buffer), true); while (!tx_complete) { osDelay(1); } /* 等待发送完成 */ } /* 发送提示符 */ char prompt[128]; snprintf(prompt, sizeof(prompt), "root@mrobot:%s$ ", current_path); tx_complete = false; BSP_UART_Transmit(BSP_UART_VOFA, (uint8_t *)prompt, strlen(prompt), true); while (!tx_complete) { osDelay(1); } /* 等待发送完成 */ } /* 重置状态 */ cmd_index = 0; cmd_ready = false; } osDelay(10); }