rm_balance/User/device/mrobot.c
2026-02-04 04:10:37 +08:00

444 lines
16 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.

/* Includes ----------------------------------------------------------------- */
#include "device/mrobot.h"
#include "component/freertos_cli.h"
#include "bsp/uart.h"
#include <string.h>
#include <stdio.h>
#include <FreeRTOS.h>
#include <task.h>
/* 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 <path>: 切换目录\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, &param_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, &param_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);
}