FreeRTOS提供有不同的组件为用户提供不同的功能,本文移植其中的FreeRTOS-CLI命令行工具到RA4L1-Sensor开发板上。
1、工程配置
参考下面的帖子中创建工程的过程,创建使用开发板串口的应用程序。
【RA4L1-SENSOR】1、开箱、Keil环境开发和官方示例移植 - 瑞萨单片机论坛 - 电子技术论坛 - 广受欢迎的专业电子论坛! https://bbs.elecfans.com/jishu_2492367_1_1.html
不同的地方是在RTOS Selection界面选择FreeRTOS。

工程中添加一个FreeRTOS任务,并设置任务的相关属性,并设置内存分配方式为动态分配。

在配置中设置自定义的FreeRTOSConfig.h文件路径,可以在工程中使用自定义的FreeRTOSConfig.h文件来配置FreeRTOS功能。

同时添加串口模块,并设置串口模块的参数。

2、移植FreeRTOS-CLI
在FreeRTOS仓库的FreeRTOS-Plus/Source/FreeRTOS-Plus-CLI路径中有FreeRTOS_CLI的源代码。

在工程目录中添加Drivers文件夹用于存放CLI和串口相关的代码,文件夹的结构如下图所示。

其中uart_ep.c和uart_ep.h文件中的代码和前一篇帖子一致。这里主要介绍其中cli_app.c和cli_app.h文件中的代码。
cli_app.h中声明几个用户应用的函数
#ifndef INC_CLI_APP_H_
#define INC_CLI_APP_H_
#include "stdint.h"
void processRxedChar(uint8_t rxChar);
void handleNewline(const char *const pcInputString, char *cOutputBuffer, uint8_t *cInputIndex);
void handleCharacterInput(uint8_t *cInputIndex, char *pcInputString);
void vRegisterCLICommands(void);
void vCommandConsoleTask(void *pvParameters);
#endif
cli_app.c中添加以下头文件、宏定义以及不同变量。
#include "FreeRTOS.h"
#include "task.h"
#include "FreeRTOS_CLI.h"
#include "cli_app.h"
#include "stdbool.h"
#include "string.h"
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include "uart_ep.h"
#include "hal_data.h"
#define MAX_INPUT_LENGTH 50
#define USING_VS_CODE_TERMINAL 0
#define USING_OTHER_TERMINAL 1
char cOutputBuffer[configCOMMAND_INT_MAX_OUTPUT_SIZE], pcInputString[MAX_INPUT_LENGTH];
int8_t cRxedChar;
const char * cli_prompt = "\r\ncli> ";
uint8_t backspace[] = "\b \b";
uint8_t backspace_tt[] = " \b";
上述代码中的configCOMMAND_INT_MAX_OUTPUT_SIZE需要在自定义的FreeRTOSConfig.h中添加该宏定义如下
#define configCOMMAND_INT_MAX_OUTPUT_SIZE 200
添加两个注册指令以及相关的指令数组,用于CLI注册指令,一个指令的功能为清屏,一个指令功能为两数相加并返回求和结果。同时封装函数注册流程到函数vRegisterCLICommands中。
BaseType_t cmd_clearScreen(char *pcWriteBuffer, size_t xWriteBufferLen,
const char *pcCommandString)
{
(void)pcCommandString;
(void)xWriteBufferLen;
memset(pcWriteBuffer, 0x00, xWriteBufferLen);
printf("\033[2J\033[1;1H");
return pdFALSE;
}
BaseType_t cmd_add(char *pcWriteBuffer, size_t xWriteBufferLen,
const char *pcCommandString)
{
char *pcParameter1, *pcParameter2;
BaseType_t xParameter1StringLength, xParameter2StringLength;
pcParameter1 = FreeRTOS_CLIGetParameter
(
pcCommandString,
1,
&xParameter1StringLength
);
pcParameter2 = FreeRTOS_CLIGetParameter
(
pcCommandString,
2,
&xParameter2StringLength
);
int32_t xValue1 = strtol(pcParameter1, NULL, 10);
int32_t xValue2 = strtol(pcParameter2, NULL, 10);
int32_t xResultValue = xValue1 + xValue2;
char cResultString[10];
sprintf(cResultString,"%d",xResultValue);
strcpy(pcWriteBuffer, cResultString);
return pdFALSE;
}
const CLI_Command_Definition_t xCommandList[] = {
{
.pcCommand = "cls",
.pcHelpString = "cls:\r\n Clears screen\r\n\r\n",
.pxCommandInterpreter = cmd_clearScreen,
.cExpectedNumberOfParameters = 0
},
{
.pcCommand = "add",
.pcHelpString = "add n:\r\n add two numbers\r\n\r\n",
.pxCommandInterpreter = cmd_add,
.cExpectedNumberOfParameters = 2
},
{
.pcCommand = NULL
}
};
void vRegisterCLICommands(void){
for (int i = 0; xCommandList[i].pcCommand != NULL; i++)
{
FreeRTOS_CLIRegisterCommand(&xCommandList[i]);
}
}
定义处理换行符并调用FreeRTOS_CLIProcessCommand执行指令解析、回车符以及输入字符串处理函数,用于处理从串口接收的字符串信息。
void cliWrite(const char *str)
{
printf("%s", str);
fflush(stdout);
}
void handleNewline(const char *const pcInputString, char *cOutputBuffer, uint8_t *cInputIndex)
{
cliWrite("\r\n");
BaseType_t xMoreDataToFollow;
do
{
xMoreDataToFollow = FreeRTOS_CLIProcessCommand(pcInputString, cOutputBuffer, configCOMMAND_INT_MAX_OUTPUT_SIZE);
cliWrite(cOutputBuffer);
} while (xMoreDataToFollow != pdFALSE);
cliWrite(cli_prompt);
*cInputIndex = 0;
memset((void*)pcInputString, 0x00, MAX_INPUT_LENGTH);
}
void handleBackspace(uint8_t *cInputIndex, char *pcInputString)
{
if (*cInputIndex > 0)
{
(*cInputIndex)--;
pcInputString[*cInputIndex] = '\0';
#if USING_VS_CODE_TERMINAL
cliWrite((char *)backspace);
#elif USING_OTHER_TERMINAL
cliWrite((char *)backspace_tt);
#endif
}
else
{
#if USING_OTHER_TERMINAL
uint8_t right[] = "\x1b\x5b\x43";
cliWrite((char *)right);
#endif
}
}
void handleCharacterInput(uint8_t *cInputIndex, char *pcInputString)
{
if (cRxedChar == '\r')
{
return;
}
else if (cRxedChar == (uint8_t)0x08 || cRxedChar == (uint8_t)0x7F)
{
handleBackspace(cInputIndex, pcInputString);
}
else
{
if (*cInputIndex < MAX_INPUT_LENGTH)
{
pcInputString[*cInputIndex] = cRxedChar;
(*cInputIndex)++;
}
}
}
最后,定义控制台指令任务函数,调用上述定义好的函数,实现指令注册以及后续的字符接收处理流程。
void vCommandConsoleTask(void *pvParameters)
{
uint8_t cInputIndex = 0;
uint32_t receivedValue;
FSP_PARAMETER_NOT_USED(pvParameters);
vRegisterCLICommands();
for (;;)
{
xTaskNotifyWait(pdFALSE,
0,
&receivedValue,
portMAX_DELAY);
cRxedChar = receivedValue & 0xFF;
cliWrite((char *)&cRxedChar);
if (cRxedChar == '\r' || cRxedChar == '\n')
{
handleNewline(pcInputString, cOutputBuffer, &cInputIndex);
}
else
{
handleCharacterInput(&cInputIndex, pcInputString);
}
}
}
在生成的cli_thread_entry中初始化串口,创建运行vCommandConsoleTask的FreeRTOS任务对串口接收到的字符串进行指令解析。
void cli_thread_entry(void * pvParameters)
{
fsp_err_t err = FSP_SUCCESS;
err = uart_initialize();
BaseType_t cli_thread_create_err = xTaskCreate(
vCommandConsoleTask,
(const char *)"UART_CLI",
1024/4,
0,
1,
&cli_command_task
);
while(1)
{
vTaskDelay(1000);
}
}
3、运行效果
编译并下载程序后,串口控制台的运行效果如视频所示。
4、总结
FreeRTOS-CLI对使用FreeRTOS的用户来说,提供一种串口调试函数的方式,本文介绍如何在RA4L1上移植FreeRTOS-CLI,实现串口控制台实现不同的控制指令。
*附件:RA4L1_FreeRTOS_CLI.7z