集成指南
XWSH 的集成指南:两种运行模式的详细对比、代码示例和最佳实践。
Categories:
6 分钟阅读
集成模式概览
XWSH 提供两种集成模式,适应不同的应用场景和资源约束。选择哪种模式取决于线程管理需求、资源可用性和系统架构。
模式对比矩阵
| 特性 | 独立线程模式 (xwsh_start()) |
嵌入式模式 (xwsh_init() + xwsh_loop()) |
|---|---|---|
| 线程资源 | 需要专用栈空间(1-2KB) | 使用调用者线程栈 |
| 线程管理 | XWSH 内部创建管理线程 | 用户控制循环调用 |
| 优先级 | XWSH_THD_PRIORITY(实时优先级降级) |
与调用者线程相同 |
| 阻塞方式 | 线程在 xwsh_loop() 中阻塞 |
在用户循环中阻塞 |
| 冻结支持 | 自动支持线程冻结 | 需要用户手动处理 |
| 适用场景 | 独立 CLI 任务、系统调试 | 集成到现有任务、资源受限环境 |
| 代码复杂度 | 低(自动管理) | 中(用户需要管理循环) |
独立线程模式
工作原理
独立线程模式创建一个专用线程运行 XWSH,线程由 XWSH 模块内部管理。
// xwmd/cli/xwsh/mi.c:24
#define XWSH_THD_PRIORITY XWOS_SKD_PRIORITY_DROP(XWOS_SKD_PRIORITY_RT_MAX, 0)
优先级说明:
XWOS_SKD_PRIORITY_RT_MAX:系统实时最高优先级XWOS_SKD_PRIORITY_DROP(max, n):从max降低n级XWSH_THD_PRIORITY:实时优先级降级 0 级,确保 CLI 响应性
使用步骤
1. 包含头文件
#include "xwmd/cli/xwsh/mi.h"
2. 定义线程栈
// 栈大小建议:1-2KB,取决于命令复杂度和递归深度
xwstk_t xwsh_stack[1024]; // 1024 * sizeof(xwstk_t) 字节
3. 添加外部命令(可选)
// 必须在 xwsh_start() 之前调用
const struct xwsh_cmd my_cmds[] = {
{ .name = "test", .func = my_test_cmd, .desc = "test command" },
};
xwsh_set_ext_cmd_table(my_cmds, 1);
4. 启动 XWSH
xwer_t rc = xwsh_start(xwsh_stack, sizeof(xwsh_stack));
if (rc < 0) {
// 错误处理
printf("Failed to start XWSH: %d\r\n", rc);
}
线程主函数
// xwmd/cli/xwsh/mi.c:59
xwer_t xwsh_thd_mainfunc(void * arg)
{
char buf[XWSH_MAXINPUT];
XWOS_UNUSED(arg);
xwsh_init(); // 显示logo,初始化readline
while (!xwos_cthd_shld_stop()) {
if (xwos_cthd_shld_frz()) {
xwos_cthd_freeze(); // 支持线程冻结
}
xwsh_loop(buf); // 读取并执行命令
}
return XWOK;
}
线程生命周期:
- 创建线程,优先级为
XWSH_THD_PRIORITY - 显示系统 logo 和版本信息
- 初始化 CherryRL 读行库
- 进入主循环,等待用户输入
- 支持线程冻结/恢复
- 线程停止条件:
xwos_cthd_shld_stop()返回 true
完整示例
#include <xwos/standard.h>
#include "xwmd/cli/xwsh/mi.h"
/* 自定义命令 */
xwer_t my_info_cmd(xwsz_t argc, char ** argv)
{
XWOS_UNUSED(argc);
XWOS_UNUSED(argv);
printf("System information:\r\n");
printf(" XWSH version: 1.0\r\n");
printf(" Build time: %s %s\r\n", __DATE__, __TIME__);
return XWOK;
}
xwer_t my_echo_cmd(xwsz_t argc, char ** argv)
{
for (xwsz_t i = 1; i < argc; i++) {
printf("%s ", argv[i]);
}
printf("\r\n");
return XWOK;
}
/* 命令表 */
const struct xwsh_cmd my_cmds[] = {
{ .name = "info", .func = my_info_cmd, .desc = "show system info" },
{ .name = "echo", .func = my_echo_cmd, .desc = "echo arguments" },
};
int main(void)
{
xwstk_t xwsh_stack[1024];
xwer_t rc;
/* 设置外部命令表(必须在启动前调用) */
rc = xwsh_set_ext_cmd_table(my_cmds,
sizeof(my_cmds) / sizeof(my_cmds[0]));
if (rc < 0) {
printf("Failed to set command table: %d\r\n", rc);
return rc;
}
/* 启动 XWSH */
rc = xwsh_start(xwsh_stack, sizeof(xwsh_stack));
if (rc < 0) {
printf("Failed to start XWSH: %d\r\n", rc);
return rc;
}
/* 主线程执行其他任务 */
while (1) {
// 其他应用逻辑
xwos_cthd_sleep_ms(1000);
}
return 0;
}
嵌入式模式
工作原理
嵌入式模式将 XWSH 集成到现有线程中,由用户代码控制命令循环的执行。
使用步骤
1. 包含头文件
#include "xwmd/cli/xwsh/mi.h"
2. 添加外部命令(可选)
// 必须在 xwsh_init() 之前调用
const struct xwsh_cmd my_cmds[] = {
{ .name = "test", .func = my_test_cmd, .desc = "test command" },
};
xwsh_set_ext_cmd_table(my_cmds, 1);
3. 初始化 XWSH
xwsh_init(); // 显示logo,初始化readline
4. 运行主循环
char buf[XWSH_MAXINPUT];
while (!exit_condition) {
xwsh_loop(buf);
// 可在此处添加其他任务逻辑
}
完整示例
#include <xwos/standard.h>
#include "xwmd/cli/xwsh/mi.h"
/* 自定义命令 */
xwer_t my_status_cmd(xwsz_t argc, char ** argv)
{
XWOS_UNUSED(argc);
XWOS_UNUSED(argv);
printf("System status: OK\r\n");
printf("Free memory: %d bytes\r\n", get_free_memory());
return XWOK;
}
/* 命令表 */
const struct xwsh_cmd my_cmds[] = {
{ .name = "status", .func = my_status_cmd, .desc = "show system status" },
};
/* 主任务函数 */
xwer_t main_task(void * arg)
{
char buf[XWSH_MAXINPUT];
xwer_t rc;
XWOS_UNUSED(arg);
/* 设置外部命令表 */
rc = xwsh_set_ext_cmd_table(my_cmds,
sizeof(my_cmds) / sizeof(my_cmds[0]));
if (rc < 0) {
printf("Failed to set command table: %d\r\n", rc);
return rc;
}
/* 初始化 XWSH */
xwsh_init();
/* 主循环 */
while (!xwos_cthd_shld_stop()) {
/* 处理 CLI 输入 */
xwsh_loop(buf);
/* 执行其他任务(非阻塞) */
process_background_tasks();
/* 短暂休眠,避免忙等待 */
xwos_cthd_sleep_ms(10);
}
return XWOK;
}
/* 带超时的版本 */
xwer_t main_task_with_timeout(void * arg)
{
char buf[XWSH_MAXINPUT];
xwtm_t timeout = 100; // 100ms 超时
XWOS_UNUSED(arg);
xwsh_init();
while (!xwos_cthd_shld_stop()) {
/* 设置 stdin 非阻塞模式(如支持) */
set_stdin_nonblocking();
/* 带超时的命令循环 */
xwtm_t start = xwos_cthd_get_timestamp();
while ((xwos_cthd_get_timestamp() - start) < timeout) {
xwsh_loop(buf);
}
/* 执行其他周期性任务 */
periodic_task();
}
return XWOK;
}
最佳实践
1. 模式选择指南
选择独立线程模式当:
- 需要独立的 CLI 线程,不影响主任务实时性
- 系统资源充足(有额外栈空间)
- CLI 需要特定的优先级设置
- 希望自动处理线程冻结/恢复
选择嵌入式模式当:
- 系统资源紧张(无法分配额外栈空间)
- 需要将 CLI 集成到现有任务循环中
- 需要更精细的控制命令执行时机
- 应用程序已有一个主循环架构
2. 优先级设置
独立线程模式优先级建议
// 高响应性(调试用途)
#define XWSH_HIGH_PRIORITY XWOS_SKD_PRIORITY_DROP(XWOS_SKD_PRIORITY_RT_MAX, 0)
// 中等优先级(一般用途)
#define XWSH_MEDIUM_PRIORITY XWOS_SKD_PRIORITY_DROP(XWOS_SKD_PRIORITY_RT_MAX, 5)
// 低优先级(后台任务)
#define XWSH_LOW_PRIORITY XWOS_SKD_PRIORITY_DROP(XWOS_SKD_PRIORITY_RT_MAX, 10)
修改方法(编辑 mi.c:22):
#define XWSH_THD_PRIORITY XWOS_SKD_PRIORITY_DROP(XWOS_SKD_PRIORITY_RT_MAX, 5)
嵌入式模式优先级
嵌入式模式的优先级取决于调用者线程。建议:
- 调试线程:较高优先级,确保快速响应
- 后台线程:较低优先级,不干扰关键任务
- 主线程:根据应用需求设置
3. 资源规划
栈大小估算
| 使用场景 | 建议栈大小 | 说明 |
|---|---|---|
| 简单命令 | 512-1024 字节 | 基本命令,无递归 |
| 复杂命令 | 1024-2048 字节 | 有格式化输出、字符串操作 |
| 递归命令 | 2048+ 字节 | 命令处理函数可能递归 |
栈使用分析:
// 在 xwsh_thd_mainfunc 中添加栈检查
xwsz_t stack_used = xwos_cthd_get_stackused();
xwsz_t stack_size = xwos_cthd_get_stacksize();
printf("Stack usage: %d/%d bytes (%.1f%%)\r\n",
stack_used, stack_size,
(stack_used * 100.0) / stack_size);
内存占用统计
| 组件 | 大小 | 备注 |
|---|---|---|
| XWSH 代码 | ~3-5 KB | 取决于编译优化 |
| 静态缓冲区 | ~1.2 KB | 提示符+历史记录 |
| 线程栈 | 1-2 KB | 独立模式需要 |
| CherryRL | ~1 KB | 库代码大小 |
4. 错误处理
启动失败处理
xwer_t rc = xwsh_start(stack, stack_size);
if (rc < 0) {
switch (rc) {
case -ENOMEM:
printf("Insufficient memory for XWSH thread\r\n");
break;
case -EINVAL:
printf("Invalid stack parameters\r\n");
break;
default:
printf("Failed to start XWSH: %d\r\n", rc);
break;
}
// 降级到嵌入式模式或禁用 CLI
fallback_to_embedded_mode();
}
命令执行错误处理
xwer_t safe_cmd_handler(xwsz_t argc, char ** argv)
{
xwer_t rc = XWOK;
// 参数验证
if (argc < 2) {
printf("Usage: %s <param>\r\n", argv[0]);
rc = -EINVAL;
goto err_param;
}
// 资源分配检查
if (!check_resource_available()) {
rc = -ENOMEM;
goto err_resource;
}
// 主逻辑(可能失败)
rc = perform_operation(argv[1]);
if (rc < 0) {
printf("Operation failed: %d\r\n", rc);
goto err_operation;
}
printf("Success\r\n");
return XWOK;
err_operation:
cleanup_operation();
err_resource:
err_param:
return rc;
}
5. 性能优化
减少阻塞时间
// 非阻塞输入检查(如平台支持)
if (stdin_has_data()) {
char buf[XWSH_MAXINPUT];
xwsh_loop(buf);
} else {
// 执行其他任务
process_other_tasks();
}
命令响应时间优化
// 复杂命令分步执行
xwer_t long_running_cmd(xwsz_t argc, char ** argv)
{
static xwsz_t step = 0;
static xwsz_t total = 100;
if (argc > 1 && strcmp(argv[1], "reset") == 0) {
step = 0;
printf("Reset progress\r\n");
return XWOK;
}
if (step < total) {
printf("Progress: %d/%d\r\n", step + 1, total);
perform_step(step);
step++;
if (step == total) {
printf("Completed\r\n");
}
} else {
printf("Already completed. Use 'cmd reset' to restart.\r\n");
}
return XWOK;
}
输出缓冲优化
// 批量输出减少系统调用
void batch_printf(const char *format, ...)
{
static char buffer[256];
va_list args;
va_start(args, format);
vsnprintf(buffer, sizeof(buffer), format, args);
va_end(args);
// 实际输出
printf("%s", buffer);
}
6. 安全考虑
输入验证
xwer_t secure_cmd(xwsz_t argc, char ** argv)
{
// 长度检查
for (xwsz_t i = 0; i < argc; i++) {
if (strlen(argv[i]) > MAX_ARG_LEN) {
printf("Argument %d too long\r\n", i);
return -E2BIG;
}
}
// 内容检查(防止注入)
for (xwsz_t i = 0; i < argc; i++) {
if (!is_valid_input(argv[i])) {
printf("Invalid characters in argument %d\r\n", i);
return -EINVAL;
}
}
// 执行安全操作
return XWOK;
}
权限控制
// 基于用户角色的命令访问控制
xwer_t privileged_cmd(xwsz_t argc, char ** argv)
{
if (!current_user_is_admin()) {
printf("Permission denied. Admin required.\r\n");
return -EACCES;
}
// 特权操作
return XWOK;
}
调试与测试
1. 单元测试框架
#include "xwmd/cli/xwsh/mi.h"
void test_command_parsing(void)
{
char line[] = "test arg1 arg2 arg3";
xwsz_t argc;
char *argv[XWSH_MAX_PARAM_NUM];
xwer_t rc;
rc = xwsh_split_cmdline(line, &argc, argv, XWSH_MAX_PARAM_NUM);
assert(rc == XWOK);
assert(argc == 4);
assert(strcmp(argv[0], "test") == 0);
assert(strcmp(argv[1], "arg1") == 0);
assert(strcmp(argv[2], "arg2") == 0);
assert(strcmp(argv[3], "arg3") == 0);
printf("Command parsing test passed\r\n");
}
2. 集成测试
void test_xwsh_integration(void)
{
xwstk_t stack[1024];
xwer_t rc;
// 测试独立线程模式
rc = xwsh_start(stack, sizeof(stack));
assert(rc == XWOK);
// 等待线程启动
xwos_cthd_sleep_ms(100);
// 测试命令执行(通过实际输入或模拟)
// ...
printf("Integration test passed\r\n");
}
3. 性能测试
void benchmark_command_execution(void)
{
xwtm_t start, end;
xwer_t rc;
char *test_cmds[] = {
"help",
"rd 0x20000000 16",
"wr 0x20000000 0x1234 w",
};
for (xwsz_t i = 0; i < sizeof(test_cmds)/sizeof(test_cmds[0]); i++) {
start = xwos_cthd_get_timestamp();
for (xwsz_t j = 0; j < 1000; j++) {
rc = xwsh_run_cmdline(test_cmds[i]);
assert(rc == XWOK);
}
end = xwos_cthd_get_timestamp();
printf("Command '%s': %lld us per execution\r\n",
test_cmds[i], (end - start) / 1000);
}
}
常见问题解答
Q1: 如何更改提示符?
A: 修改 readline.c 中的 chry_readline_prompt_edit() 调用,或实现自定义的提示符生成函数。
Q2: 支持多行命令吗?
A: 当前版本不支持。需要扩展 CherryRL 配置或修改命令解析逻辑。
Q3: 如何增加历史记录大小?
A: 修改 readline.c:33 的 XWSH_RL_HISTORY_MAXSIZE,必须保持为 2 的幂。
Q4: 命令执行超时如何实现?
A: 在嵌入式模式中,可以在循环中添加超时检查,或使用带超时的输入函数。
Q5: 如何禁用彩色输出?
A: 修改 chry_readline_prompt_edit() 调用,移除 SGR(Select Graphic Rendition)属性。
Q6: 支持命令别名吗?
A: 当前不支持,但可以在命令处理函数中实现,或扩展命令查找逻辑。
Q7: 如何记录所有执行的命令?
A: 在 xwsh_run_cmdline() 执行后添加日志记录,或修改命令执行流程。