赞
踩
最近想用 ESP32-C3 做一个串口解析的应用程序。类似 ESP-AT,但实现的功能比 ESP-AT 少的多。使用 ESP-IDF 的版本为 release/v4.4,本来是想基于 uart_events example 自己来实现串口解析的逻辑,但突然发现 FREERTOS 竟然提供了一个组件 FreeRTOS-Plus-CLI,可以实现串口解析的逻辑,并且和 release/v4.4 完美衔接,省去了自己编写串口解析代码的烦恼,只需要专注于上层功能逻辑的实现即可,简直是太方便了,可以说是开发神器。
FreeRTOS-Plus-CLI (Command Line Interface) 简单点说就是提供了一种简单、小巧、易于扩展且占用 RAM 资源极少的方法,可以在 FREERTOS 的应用上处理命令行输入。
从 FreeRTOS V10.0.0 开始,FreeRTOS-Plus-CLI 使用和 FreeRTOS 内核相同的 MIT 许可。
想要将 FreeRTOS-Plus-CLI 使用起来,仅仅需要以下 4 步即可:
命令的实现行为很简单,仅需要实现以下接口即可:
BaseType_t xFunctionName( char *pcWriteBuffer,
size_t xWriteBufferLen,
const char *pcCommandString );
该接口的实现 FREERTOS 其实已经给了很好的 demo。这里就以可变参数数量的命令行为例,结合 FREERTOS 提供的 demo 简单讲解一下。(这里 FREERTOS 提供的 demo 小小的该动了一下)
BaseType_t prvParameterSwitchCommand(char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString) { char *pcParameter; BaseType_t lParameterStringLength, xReturn; /* Note that the use of the static parameter means this function is not reentrant. */ static BaseType_t lParameterNumber = 0; if( lParameterNumber == 0 ) { /* lParameterNumber is 0, so this is the first time the function has been called since the command was entered. Return the string "The parameters were:" before returning any parameter strings. */ sprintf( pcWriteBuffer, "The parameters were:\r\n" ); /* Next time the function is called the first parameter will be echoed back. */ lParameterNumber = 1L; /* There is more data to be returned as no parameters have been echoed back yet, so set xReturn to pdPASS so the function will be called again. */ xReturn = pdPASS; } else { /* lParameter is not 0, so holds the number of the parameter that should be returned. Obtain the complete parameter string. */ pcParameter = ( char * ) FreeRTOS_CLIGetParameter ( /* The command string itself. */ pcCommandString, /* Return the next parameter. */ lParameterNumber, /* Store the parameter string length. */ &lParameterStringLength ); if( pcParameter != NULL ) { /* There was another parameter to return. Copy it into pcWriteBuffer. in the format "[number]: [Parameter String". */ memset( pcWriteBuffer, 0x00, xWriteBufferLen ); sprintf( pcWriteBuffer, "%d: ", lParameterNumber ); strncat( pcWriteBuffer, pcParameter, lParameterStringLength ); printf("%s\r\n", pcWriteBuffer); /* There might be more parameters to return after this one, so again set xReturn to pdTRUE. */ xReturn = pdTRUE; lParameterNumber++; } else { /* No more parameters were found. Make sure the write buffer does not contain a valid string to prevent junk being printed out. */ pcWriteBuffer[ 0 ] = 0x00; /* There is no more data to return, so this time set xReturn to pdFALSE. */ xReturn = pdFALSE; /* Start over the next time this command is executed. */ lParameterNumber = 0; } } return xReturn; }
这里假设我们输入的命令行为 test 1 12 123 1234
,那么该接口执行完之后的输出如下:
1: 1
2: 12
3: 123
4: 1234
该接口的返回值决定了该接口是否会被继续调用。
这步其实很简单,说白了就是将命令和命令的实现接口进行绑定。绑定之后只需注册下命令即可。
命令由 CLI_Command_Definition_t 类型的结构定义。
typedef struct xCLI_COMMAND_DEFINITION { /* The command line input string. This is the string that the user enters to run the command. For example, the FreeRTOS-Plus-CLI help function uses the string "help". If a user types "help" the help command executes. */ const char * const pcCommand; /* A string that describes the command, and its expected parameters. This is the string that is output when the help command is executed. The string must start with the command itself, and end with "rn". For example, the help string for the help command itself is: "help: Returns a list of all the commandsrn" */ const char * const pcHelpString; /* A pointer to the function that implements the command behaviour (effectively the function name). */ const pdCOMMAND_LINE_CALLBACK pxCommandInterpreter; /* The number of parameters required by the command. FreeRTOS-Plus-CLI will only execute the command if the number of parameters entered on the command line matches this number. */ char cExpectedNumberOfParameters; } CLI_Command_Definition_t;
-1
表示参数个数可变。接口 FreeRTOS_CLIRegisterCommand 用来注册命令。原型如下:
/*
* Register the command passed in using the pxCommandToRegister parameter.
* Registering a command adds the command to the list of commands that are
* handled by the command interpreter. Once a command has been registered it
* can be executed from the command line.
*/
BaseType_t FreeRTOS_CLIRegisterCommand( const CLI_Command_Definition_t * const pxCommandToRegister );
注册成功返回 pdPASS,失败返回 pdFAIL。
对于 FREERTOS 来说,说白了就是建立一个 task 去一个字节一个字节的从 UART 的输入缓冲区读取数据进行命令解析(前提是命令已经通过 FreeRTOS_CLIRegisterCommand
注册过)。
由于使用的是 ESP32-C3,所以仅需要调用 uart_read_bytes
接口即可,ticks_to_wait
参数可设置为 portMAX_DELAY
。这样子可以将 task 进行阻塞,只在有数据的时候进行处理即可,不会占据 CPU 太多的处理时间。
void cmd_parse_task( void *pvParameters ) { char cRxedChar = 0; uint32_t cInputIndex = 0; BaseType_t xMoreDataToFollow; /* The input and output buffers are declared static to keep them off the stack. */ static int8_t pcOutputString[ MAX_OUTPUT_LENGTH ], pcInputString[ MAX_INPUT_LENGTH ]; for( ;; ) { /* This implementation reads a single character at a time. Wait in the Blocked state until a character is received. */ uart_read_bytes(COMM_UART_NUM, &cRxedChar, 1, portMAX_DELAY); if( cRxedChar == '\r' ) { /* The command interpreter is called repeatedly until it returns pdFALSE. See the "Implementing a command" documentation for an exaplanation of why this is. */ do { /* Send the command string to the command interpreter. Any output generated by the command interpreter will be placed in the pcOutputString buffer. */ xMoreDataToFollow = FreeRTOS_CLIProcessCommand ( (const char *)pcInputString, /* The command string.*/ (char *)pcOutputString, /* The output buffer. */ MAX_OUTPUT_LENGTH/* The size of the output buffer. */ ); } while( xMoreDataToFollow != pdFALSE ); /* All the strings generated by the input command have been sent. Processing of the command is complete. Clear the input string ready to receive the next command. */ cInputIndex = 0; memset( pcInputString, 0x00, MAX_INPUT_LENGTH ); } else { /* The if() clause performs the processing after a newline character is received. This else clause performs the processing if any other character is received. */ if( cRxedChar == '\r' ) { /* Ignore carriage returns. */ } else if( cRxedChar == '\b' ) { /* Backspace was pressed. Erase the last character in the input buffer - if there are any. */ if( cInputIndex > 0 ) { cInputIndex--; pcInputString[ cInputIndex ] = '\0'; } } else { /* A character was entered. It was not a new line, backspace or carriage return, so it is accepted as part of the input and placed into the input buffer. When a n is entered the complete string will be passed to the command interpreter. */ if( cInputIndex < MAX_INPUT_LENGTH ) { pcInputString[ cInputIndex ] = cRxedChar; cInputIndex++; } } } } }
这段代码中核心语句为
do
{
/* Send the command string to the command interpreter. Any
output generated by the command interpreter will be placed in the
pcOutputString buffer. */
xMoreDataToFollow = FreeRTOS_CLIProcessCommand
(
(const char *)pcInputString, /* The command string.*/
(char *)pcOutputString, /* The output buffer. */
MAX_OUTPUT_LENGTH/* The size of the output buffer. */
);
} while( xMoreDataToFollow != pdFALSE );
从 UART 的输入缓冲区中一个字节一个字节将数据放到 pcInputString
所指向的输入命令缓冲区中。然后接口 FreeRTOS_CLIProcessCommand
在内部会不断的将输入的命令和注册命令进行匹配,如果匹配到了就会跳到对应的命令实现接口中去执行。
例子中是以 CR(回车)
作为命令行的结束符。如果要将以 CR/LF (回车/换行)
作为命令行的结束符,可以将这里的 if( cRxedChar == '\r' )
替换成 if( cRxedChar == '\n' )
即可。
if( cRxedChar == '\r' ) { /* The command interpreter is called repeatedly until it returns pdFALSE. See the "Implementing a command" documentation for an exaplanation of why this is. */ do { /* Send the command string to the command interpreter. Any output generated by the command interpreter will be placed in the pcOutputString buffer. */ xMoreDataToFollow = FreeRTOS_CLIProcessCommand ( (const char *)pcInputString, /* The command string.*/ (char *)pcOutputString, /* The output buffer. */ MAX_OUTPUT_LENGTH/* The size of the output buffer. */ ); } while( xMoreDataToFollow != pdFALSE );
以上就是 FreeRTOS-Plus-CLI 的简单使用教程。如果还有不明白的,可以参考我 GitHub 上的 esp32-uart-parse 示例。该示例以一个 test <param_1>, <param_2>[, <param_3>, <param_4>]
命令为例完整的演示了该如何使用 FreeRTOS-Plus-CLI。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。