RT-Thread之rt_memset函数

RT-Thread内存设置优化

在rtthread中,自带了内存设置函数rt_memset,其目的是将某段内存的内容设置为指定的数值。该函数接受三个参数:源内存地址s,要设置的值c,以及要设置的长度count。在函数中,首先判断了是否使用了RT_USING_TINY_SIZE宏,如果使用了,则通过循环逐个设置内存的值,然后返回源内存地址。

如果没有使用RT_USING_TINY_SIZE宏,则会根据内存对齐情况和设置的值大小进行不同的处理。如果设置的长度大于等于一个块的大小并且内存地址是块对齐的,就会使用较高效的方式进行设置,否则会通过逐个字节设置的方式来完成设置操作。

下面是这个函数的具体内容:

/**
 * This function will set the content of memory to specified value
 *
 * @param s the address of source memory
 * @param c the value shall be set in content
 * @param count the copied length
 *
 * @return the address of source memory
 */
void *rt_memset(void *s, int c, rt_ubase_t count)
{
#ifdef RT_USING_TINY_SIZE
    char *xs = (char *)s;

    while (count--)
        *xs++ = c;

    return s;
#else
#define LBLOCKSIZE      (sizeof(rt_int32_t))
#define UNALIGNED(X)    ((rt_int32_t)X & (LBLOCKSIZE - 1))
#define TOO_SMALL(LEN)  ((LEN) < LBLOCKSIZE)

    int i;
    char *m = (char *)s;
    rt_uint32_t buffer;
    rt_uint32_t *aligned_addr;
    rt_uint32_t d = c &
<think>我们正在讨论RT-Thread中使用单向链表(rt_slist)存储命令,并添加命令到链表。用户的问题是:将回调函数添加到链表后如何执行? 回顾用户提供的代码片段: 1. 定义了一个静态的单向链表头:`static rt_slist_t cmd_list = RT_SLIST_OBJECT_INIT(cmd_list);` 2. 定义了一个命令结构体`rt_console_cmd`,其中包含命令名、描述和回调函数。 3. 函数`console_cmd_add`用于将命令添加到链表中。 现在,用户想知道:将回调函数(命令处理函数)添加到链表后,如何执行这些回调函数? 在RT-Thread中,命令通常是通过控制台输入的。因此,执行命令的流程一般是: 1. 解析控制台输入的命令字符串,拆分成命令名和参数(argc, argv)。 2. 在命令链表中查找匹配的命令名。 3. 如果找到,则调用该命令节点中的回调函数(即`cmd->func(argc, argv)`)。 因此,我们需要一个命令解析和执行函数,通常称为`console_cmd_exec`(或类似名称)。这个函数负责上述流程。 以下是实现命令执行的大致步骤: 步骤1:实现命令解析函数 - 输入:一个字符串(例如:"led on") - 输出:参数个数(argc)和参数数组(argv),例如: argc = 2 argv[0] = "led", argv[1] = "on" 步骤2:实现命令查找和执行函数 - 遍历命令链表`cmd_list`,查找命令名与argv[0]匹配的节点。 - 找到后,调用该节点的回调函数:`cmd->func(argc, argv)` 注意:命令链表中存储的是`rt_console_cmd`结构体,我们通过`rt_slist_for_each`遍历链表,然后通过`rt_slist_entry`获取结构体实例。 示例代码: ```c // 命令执行函数 int console_cmd_exec(char *cmd_line) { int argc; char *argv[RT_CONSOLE_ARG_MAX]; // 假设最大参数个数 // 步骤1: 解析命令行为参数数组 argc = console_parse_cmd(cmd_line, argv); if (argc == 0) { return -1; // 没有命令 } // 步骤2: 在命令链表中查找命令 rt_slist_t *node; struct rt_console_cmd *cmd; rt_enter_critical(); rt_slist_for_each(node, &cmd_list) { cmd = rt_slist_entry(node, struct rt_console_cmd, list); if (rt_strcmp(cmd->name, argv[0]) == 0) { // 找到命令,执行回调函数 rt_exit_critical(); return cmd->func(argc, argv); } } rt_exit_critical(); // 没有找到命令 rt_kprintf("Unknown command: %s\n", argv[0]); return -1; } ``` 其中,`console_parse_cmd`是一个命令解析函数,用于将输入字符串拆分成参数数组。RT-Thread通常提供了`finsh_parse`(在finsh组件中)或类似函数,但这里我们假设自己实现一个简单的版本。 简单命令解析函数示例(按空格分割): ```c #define RT_CONSOLE_ARG_MAX 8 // 最大参数个数 #define RT_CONSOLE_CMD_SIZE 80 // 命令行最大长度 int console_parse_cmd(char *cmd, char **argv) { int argc = 0; char *ptr; // 跳过开头的空格 while (*cmd == ' ') cmd++; ptr = cmd; while (*ptr) { if (*ptr == ' ') { *ptr = '\0'; // 将空格替换为字符串结束符 ptr++; // 跳过连续空格 while (*ptr == ' ') ptr++; if (*ptr != '\0') { argv[argc] = ptr; argc++; } } else { ptr++; } } // 第一个参数就是命令名 if (cmd[0] != '\0') { argv[argc] = cmd; argc++; } return argc; } ``` 注意:上面的解析函数是一个简化版本,实际应用中可能需要处理引号、转义等。 综上所述,将命令添加到链表后,我们需要通过一个命令执行函数来解析用户输入,查找命令并执行回调函数。 另外,在RT-Thread中,通常有一个控制台线程(或使用finsh组件)不断读取用户输入,然后调用`console_cmd_exec`执行命令。 例如,一个简单的控制台线程: ```c static void console_thread_entry(void *parameter) { char cmd[RT_CONSOLE_CMD_SIZE]; while (1) { rt_kprintf("> "); rt_memset(cmd, 0, sizeof(cmd)); rt_device_read(console_dev, 0, cmd, sizeof(cmd)); // 假设console_dev是控制台设备 console_cmd_exec(cmd); } } ``` 这样,当用户输入命令并按下回车后,控制台线程读取输入,然后调用`console_cmd_exec`执行命令。 总结: 1. 添加命令:使用`console_cmd_add`将命令结构体添加到链表。 2. 执行命令:用户输入命令字符串,解析后查找链表节点,调用节点的回调函数。 需要注意的是,我们在遍历链表时使用了临界区保护(rt_enter_critical和rt_exit_critical),这是因为链表可能在中断或另一个线程中被修改(比如添加命令)。如果系统支持多线程且链表可能被多个线程访问,建议使用互斥锁(rt_mutex_t)来保护链表操作。 最后,请确保在添加命令时正确初始化了链表节点(`rt_slist_init`),并且添加操作是线程安全的。 希望这能解答您的疑问。 §§相关问题§§ 1. 在RT-Thread中如何实现一个简单的命令行解析器? 2. 如何保护命令链表免受多线程并发访问的影响? 3. 如何实现命令的自动补全和帮助功能? </think>### RT-Thread中执行链表中的回调函数RT-Thread中,通过`rt_slist_append`将回调函数添加到链表后,需要通过以下步骤执行这些回调函数--- ### 1. **遍历链表获取回调函数** 使用单向链表操作API遍历链表,获取存储回调函数的结构体: ```c /* 定义链表头 */ static rt_slist_t cmd_list = RT_SLIST_OBJECT_INIT(cmd_list); /* 定义命令结构体 */ struct rt_console_cmd { const char *name; int (*func)(int argc, char **argv); // 回调函数指针 rt_slist_t list; }; /* 遍历执行回调函数 */ void execute_commands(void) { rt_slist_t *node; struct rt_console_cmd *cmd; // 获取链表首节点 rt_slist_for_each(node, &cmd_list) { // 通过链表节点获取包含它的结构体 cmd = rt_slist_entry(node, struct rt_console_cmd, list); // 执行回调函数(假设传递空参数) if (cmd->func) { cmd->func(0, RT_NULL); } } } ``` 关键API说明: - `rt_slist_for_each()`:遍历链表宏[^1] - `rt_slist_entry()`:通过链表节点获取父结构体(计算偏移量) - `cmd->func()`:执行回调函数 --- ### 2. **触发执行时机** 根据实际场景选择触发方式: #### (1) **事件驱动执行** ```c /* 定义事件标志 */ static rt_event_t cmd_event; void command_thread_entry(void *param) { while (1) { // 等待执行命令事件 rt_event_recv(cmd_event, 0x01, RT_EVENT_FLAG_OR, RT_WAITING_FOREVER, RT_NULL); execute_commands(); // 执行所有回调 } } // 在需要执行命令的地方触发 void trigger_command_exec(void) { rt_event_send(cmd_event, 0x01); } ``` #### (2) **定时轮询执行** ```c static rt_timer_t cmd_timer; void timer_callback(void *param) { execute_commands(); // 定期执行 } void init_timer(void) { // 创建1秒周期的定时器 cmd_timer = rt_timer_create("cmd_tmr", timer_callback, RT_NULL, RT_TICK_PER_SECOND, RT_TIMER_FLAG_PERIODIC); rt_timer_start(cmd_timer); } ``` #### (3) **控制台命令触发** ```c // 注册系统命令 MSH_CMD_EXEC(exec_all, "execute all commands") { execute_commands(); return 0; } ``` 在控制台输入`exec_all`即可执行所有回调[^2] --- ### 3. **关键注意事项** 1. **线程安全** ```c void execute_commands(void) { rt_enter_critical(); // 进入临界区 /* 遍历执行代码 */ rt_exit_critical(); // 退出临界区 } ``` 2. **参数传递** 若需传递参数,可修改回调执行: ```c cmd->func(argc, argv); // 传递实际参数 ``` 3. **错误处理** ```c int ret = cmd->func(0, RT_NULL); if (ret != RT_EOK) { rt_kprintf("Command %s failed: %d\n", cmd->name, ret); } ``` --- ### 执行流程示意图 ```mermaid graph LR A[添加命令到链表] --> B{触发条件} B -->|事件触发| C[执行所有回调] B -->|定时触发| C B -->|命令触发| C C --> D[遍历链表] D --> E[获取回调函数] E --> F[执行函数] ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值