实现命令

FreeRTOS-Plus-CLI 是一个可扩展的框架, 应用程序写入器可以通过该框架定义并注册自己的命令行输入命令。本页介绍了 如何编写实现命令行为的函数。

函数输入和输出

实现用户定义命令行为的函数必须具有以下 接口(原型):

1
2
3
BaseType_t xFunctionName(char *pcWriteBuffer,
size_t xWriteBufferLen,
const char *pcCommandString );

参数:

  • pcWriteBuffer:缓冲区,任何输出都应写入其中。例如,如果函数只返回固定的字符串 “Hello World”,则该字符串将写入 pcWriteBuffer。 输出必须始终\0 结尾。
  • xWriteBufferLen:pcWriteBuffer 参数所指向的缓冲区的大小。向 pcWriteBuffer 写入超过 xWriteBufferLen 个字符 将导致缓冲区溢出。
  • pcCommandString:指向整个命令字符串的指针。如果可以访问整个命令字符串, 函数执行就可以提取命令参数(如有)。FreeRTOS-Plus-CLI 提供了接受命令字符串并返回命令参数的辅助函数 ——因此不需要明确的字符串解析。本页 提供了相关示例。

返回:

执行某些命令将导致产生不止一行输出。例如, 文件系统 “dir”(或 “Is”)命令将为目录下的每个文件生成一行输出。如果 目录下有三个文件,则输出可能如下所示:

1
2
3
file1.txt
file2.txt
file3.txt

为将 RAM 的使用率降至最低,并确定 RAM 的使用率,FreeRTOS-Plus-CLI 允许实现命令行为的函数每次输出一行。函数返回值用于指示输出行是否是输出的末尾,或者是否要生成更多行。
如果生成的输出是输出的末尾,则返回 pdFALSE, 这意味着不需再生成更多行,并且命令执行已完成。
如果返回的输出不是输出的末尾,并且在命令执行完成之前仍有一行或多行要生成,则返回 pdTRUE 。

再来看一下“dir”命令。在该示例中,此命令输出三个文件名称:

  1. 实现 dir 命令的函数第一次调用时, 可能只输出第一行 (file1.txt)。完成此操作后,该函数须返回 pdTRUE, 以指示后面还有更多行。
  2. 实现 dir 命令的函数第二次调用时, 可能只输出第二行 (file2.txt)。完成此操作后,该函数须再次返回 pdTRUE, 以指示后面还有更多行。
  3. 实现 dir 命令的函数第三次调用时,只会输出第三行 (file3.txt) 。此时,没有其他行需要输出,因此函数须返回 pdFALSE。

或者,如果有足够的 RAM,并且 xWriteBufferLen 中传递的值足够大, 则可以一次返回所有三行,在这种情况下,函数必须在第一次执行时返回 pdFALSE 。

每次执行命令时,FreeRTOS-Plus-CLI 将重复调用实现命令行为的函数, 直到函数返回 pdFALSE。

示例

原文
本页提供如下示例:

  1. 一种命令,该命令不带参数,并且返回单个字符串。
  2. 一种命令,该命令不带参数并且一次返回单行多个字符串。
  3. 一种命令,该命令需要固定数量的参数。
  4. 一种命令,该命令接受可变数量的参数并且一次返回单行可变数量的字符串 。

示例 1:不带参数的命令

FreeRTOS vTaskList() API 函数生成一个包含每个任务状态信息的表 。该表包含每个任务的单行文本。示例 1 中实现的命令可输出 此表。示例 1 演示了一次输出整张表的简单实例。代码中的注释 用于进一步解释说明。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/* This function implements the behaviour of a command, so must have the correct
prototype. */
static BaseType_t prvTaskStatsCommand( char *pcWriteBuffer,
size_t xWriteBufferLen,
const char *pcCommandString )
{
/* 为简单起见,此函数假设输出缓冲区足够大,可以容纳执行vTaskList() API函数生成的
所有文本,因此不使用xWriteBufferLen参数。 */
( void ) xWriteBufferLen;

/* pcWriteBuffer直接用作vTaskList()的参数,因此执行vTaskList()生成的表被直接
写入输出缓冲区。 */
vTaskList( pcWriteBuffer + strlen( pcHeader ) );

/* 整个表被直接写入输出缓冲区。该命令执行完毕,因此返回pdFALSE。 */
return pdFALSE;
}

示例 1:一次输出多行

示例 2 :一次返回多行

每个用 FreeRTOS-Plus-CLI 注册的命令都有自己的帮助字符串。帮助字符串是 演示如何使用命令的一行文本。FreeRTOS-Plus-CLI 包含一条“帮助”命令, 该命令能返回所有帮助字符串,为用户提供可用的命令列表 以及有关如何使用每条命令的说明。示例 2 演示了帮助命令的实现方式。与示例 1 (一次性生成所有输出)不同,示例 2 中,一次只生成单行输出。请注意, 该函数并非可重入函数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
/* This function implements the behaviour of a command, so must have the correct
prototype. */
static BaseType_t prvHelpCommand( char *pcWriteBuffer,
size_t xWriteBufferLen,
const char *pcCommandString )
{
/* 执行“help”命令将生成多行文本,但此函数一次只输出一行。因此,要多次调用该函数来完成对
单个“help”命令的处理。这意味着它必须记住哪些帮助字符串已经输出,哪些还有待输出。
静态pxCommand变量用于指向需要输出的下一个帮助字符串。*/
static const xCommandLineInputListItem *pxCommand = NULL;
signed BaseType_t xReturn;

if( pxCommand == NULL )
{
/* pxCommand在执行“help”命令之间为NULL,因此,如果在进入该函数时为NULL,则
它是新“help”命令的开始,并返回第一个帮助字符串。下面一行将pxCommand指向在
FreeRTOS-Plus-CLI中注册的第一个命令。*/
pxCommand = &xRegisteredCommands;
}

/* 输出pxCommand所指向的命令的帮助字符串,注意不要溢出输出缓冲区。 */
strncpy( pcWriteBuffer,
pxCommand->pxCommandLineDefinition->pcHelpString,
xWriteBufferLen );

/* 移动到列表中的下一个命令,准备在下次调用该函数时输出该命令的帮助字符串。 */
pxCommand = pxCommand->pxNext;

if( pxCommand == NULL )
{
/* 如果列表中的下一个命令为NULL,则没有更多的命令要处理,并且可以返回pdFALSE。 */
xReturn = pdFALSE;
}
else
{
/* 如果列表中的下一个命令不为NULL,则需要处理更多的命令,因此需要生成
更多的输出行。在这种情况下,返回pdTRUE。 */
xReturn = pdTRUE;
}

return xReturn;
}

示例 2:生成多行输出结果(一次一行)

示例 3 :具有固定数量参数的命令

有些命令需要参数。例如,文件系统 “copy” 命令需要 带有源文件的名称和目标文件的名称。示例 3 是复制命令的框架, 用于演示如何访问和使用命令参数。

请注意,如果在注册时声明该命令需要两个参数,那么除非提供两个参数,否则 FreeRTOS-Plus-CLI 甚至不会调用该命令。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
/* This function implements the behaviour of a command, so must have the correct
prototype. */
static BaseType_t prvCopyCommand( char *pcWriteBuffer,
size_t xWriteBufferLen,
const char *pcCommandString )
{
char *pcParameter1, *pcParameter2;
BaseType_t xParameter1StringLength, xParameter2StringLength, xResult;

/* 从命令字符串中获取源文件的名称及其长度。源文件的名称是第一个参数。 */
pcParameter1 = FreeRTOS_CLIGetParameter(
/* 命令字符串本身。 */
pcCommandString,
/* 返回第一个参数。 */
1,
/* 存储参数字符串长度。 */
&xParameter1StringLength
);

/* 获取目标文件的名称及其名称的长度。 */
pcParameter2 = FreeRTOS_CLIGetParameter( pcCommandString,
2,
&xParameter2StringLength );

/* 终止两个文件名。 */
pcParameter1[ xParameter1StringLength ] = 0x00;
pcParameter2[ xParameter2StringLength ] = 0x00;

/* 执行复制操作本身。 */
xResult = prvCopyFile( pcParameter1, pcParameter2 );

if( xResult == pdPASS )
{
/* 复制成功了。没有什么可输出的。 */
*pcWriteBuffer = NULL;
}
else
{
/* 复制没有成功。通知用户。 */
snprintf( pcWriteBuffer, xWriteBufferLen, "Error during copy\r\n\r\n" );
}

/* 在所有情况下只产生一行输出。返回pdFALSE是因为没有更多的输出要生成。 */
return pdFALSE;
}

示例 3:访问和使用命令参数

示例 4 :具有可变数量参数的命令

示例 4 演示了如何创建和实现一个接受可变数量参数的命令。 FreeRTOS-Plus-CLI 不会检查所提供的参数的数量, 命令的执行只是简单的回传参数,一次一个。例如,如果分配的命令字符串为 “echo_parameters”, 则当用户输入echo_parameters one two three four时生成以下输出结果:

1
2
3
4
5
The parameters were:
1: one
2: two
3: three
4: four
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
static BaseType_t prvParameterEchoCommand( char *pcWriteBuffer,
size_t xWriteBufferLen,
const char *pcCommandString )
{
char *pcParameter;
BaseType_t lParameterStringLength, xReturn;

/* 注意,使用静态参数意味着该函数不可重入。 */
static BaseType_t lParameterNumber = 0;

if( lParameterNumber == 0 )
{
/* lParameterNumber为0,因此这是自输入命令以来第一次调用该函数。在返回
任何参数字符串之前,返回字符串“The parameters were:\r\n”。 */
sprintf( pcWriteBuffer, "The parameters were:\r\n" );

/* 下次调用该函数时,将回显第一个参数。 */
lParameterNumber = 1L;

/* 由于还没有回显参数,因此需要返回更多的数据,因此将xReturn设置为pdPASS,
以便再次调用该函数。 */
xReturn = pdPASS;
}
else
{
/* lParameter不为0,因此保存应该返回的参数的编号。获取完整的参数字符串。 */
pcParameter = ( char * ) FreeRTOS_CLIGetParameter
(
/* 命令字符串本身。 */
pcCommandString,
/* 返回下一个参数。 */
lParameterNumber,
/* 存储参数字符串长度。 */
&lParameterStringLength
);

if( pcParameter != NULL )
{
/* 还需要返回另一个参数。将其复制到pcWriteBuffer中。格式为
“[number]:[Parameter String]”。 */
memset( pcWriteBuffer, 0x00, xWriteBufferLen );
sprintf( pcWriteBuffer, "%d: ", lParameterNumber );
strncat( pcWriteBuffer, pcParameter, lParameterStringLength );
strncat( pcWriteBuffer, "\r\n", strlen( "\r\n" ) );

/* 在此参数之后可能还需要返回更多参数,因此再次将xReturn设置为pdTRUE。 */
xReturn = pdTRUE;
lParameterNumber++;
}
else
{
/* 没有找到更多的参数。确保写缓冲区不包含有效字符串,以防止打印出垃圾。 */
pcWriteBuffer[ 0 ] = 0x00;

/* 没有更多的数据要返回,所以这次将xReturn设置为pdFALSE。 */
xReturn = pdFALSE;

/* 在下次执行此命令时重新开始。 */
lParameterNumber = 0;
}
}

return xReturn;
}

示例 4 :访问可变数量的参数


实现命令
https://blog.zhaosn.top/FreeRTOS-plus-CLI/02-Implementing-a-command/
作者
Zhao SN
发布于
2026年1月8日
更新于
2026年1月21日
许可协议