This post shows how to implement CLI ( Command Line Interpreter ) in your Cortex M0 using FreeRTOS.
Meterials
I used thease meterials in this project.
- Platform : WIZwiki-W7500ECO
- RTOS : FreeRTOS
FreeRTOS
FreeRTOS is a popular[1] real-time operating system kernel[2][3] for embedded devices, that has been ported to 35 microcontrollers. It is distributed under the GPL with an optional exception. The exception permits users’ proprietary code to remain closed source while maintaining the kernel itself as open source, thereby facilitating the use of FreeRTOS in proprietary applications.[4]
Key Features
- Very small memory footprint, low overhead, and very fast execution.
- Tick-less option for low power applications.
- Equally good for hobbyists who are new to OSes, and professional developers working on commercial products.
- Scheduler can be configured for both preemptive or cooperative operation.
- Coroutine support (Coroutine in FreeRTOS is a very simple and lightweight task that has very limited use of stack)
Reference : https://en.wikipedia.org/wiki/FreeRTOS
CLI
CLI(Command Line Interpreter) A command-line interface or command language interpreter (CLI), also known as command-line user interface, console user interface,[1] and character user interface (CUI), is a means of interacting with a computer program where the user (or client) issues commands to the program in the form of successive lines of text (command lines).
Reference :https://en.wikipedia.org/wiki/Command-line_interface
FreeRTOS Porting Guide on W7500
If you’d like to know how to use freeRTOS on your Cortex M0, refer to this Link
Repository of Project There is repository of my CLI project. If you are heading to CLI Project, you can download and use it.
Explanation about structure
Serial.c
This file is serial driver code for using UART interface of W7500 in FreeRTOS. Default UART interface of WIZwiki-W7500ECO is UART2 so serial.c set UART2 and manage serial data using Queue.
- xCharsForTx : Queue for Tx data
- xRxedChars : Queue for Rx data
xComPortHandle xSerialPortInitMinimal( unsigned long ulWantedBaud, unsigned portBASE_TYPE uxQueueLength )
{
xComPortHandle xReturn;
/* Create the queues used to hold Rx/Tx characters. */
xRxedChars = xQueueCreate( uxQueueLength, ( unsigned portBASE_TYPE ) sizeof( signed char ) );
xCharsForTx = xQueueCreate( uxQueueLength + 1, ( unsigned portBASE_TYPE ) sizeof( signed char ) );
/* If the queue/semaphore was created correctly then setup the serial port
hardware. */
if( ( xRxedChars != serINVALID_QUEUE ) && ( xCharsForTx != serINVALID_QUEUE ) )
{
S_UART_Init(115200);
S_UART_ITConfig(S_UART_CTRL_RXI,ENABLE);
NVIC_EnableIRQ(UART2_IRQn);
xReturn = (xComPortHandle)UART2;
}
else
{
xReturn = ( xComPortHandle ) 0;
}
/* This demo file only supports a single port but we have to return
something to comply with the standard demo header file. */
return xReturn;
}
void UART2_Handler( void )
{
portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE;
char cChar;
if( S_UART_GetITStatus(S_UART_INTSTATUS_RXI) != RESET ) {
S_UART_ClearITPendingBit(S_UART_INTSTATUS_RXI);
cChar = S_UART_ReceiveData();
xQueueSendFromISR( xRxedChars, &cChar, &xHigherPriorityTaskWoken );
}
portEND_SWITCHING_ISR( xHigherPriorityTaskWoken );
}
signed portBASE_TYPE xSerialGetChar( xComPortHandle pxPort, signed char *pcRxedChar, TickType_t xBlockTime )
{
/* The port handle is not required as this driver only supports one port. */
( void ) pxPort;
/* Get the next character from the buffer. Return false if no characters
are available, or arrive before xBlockTime expires. */
if( xQueueReceive( xRxedChars, pcRxedChar, xBlockTime ) )
{
return pdTRUE;
}
else
{
return pdFALSE;
}
}
/*-----------------------------------------------------------*/
void vSerialPutString( xComPortHandle pxPort, const signed char * const pcString, unsigned short usStringLength )
{
signed char *pxNext;
/* A couple of parameters that this port does not use. */
( void ) usStringLength;
( void ) pxPort;
/* NOTE: This implementation does not handle the queue being full as no
block time is used! */
/* The port handle is not required as this driver only supports UART1. */
( void ) pxPort;
/* Send each character in the string, one at a time. */
pxNext = ( signed char * ) pcString;
while( *pxNext )
{
xSerialPutChar( pxPort, *pxNext, serNO_BLOCK );
pxNext++;
}
}
/*-----------------------------------------------------------*/
signed portBASE_TYPE xSerialPutChar( xComPortHandle pxPort, signed char cOutChar, TickType_t xBlockTime )
{
signed portBASE_TYPE xReturn;
char cChar;
portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE;
if( xQueueSend( xCharsForTx, &cOutChar, xBlockTime ) == pdPASS )
{
xReturn = pdPASS;
if( xQueueReceiveFromISR( xCharsForTx, &cChar, &xHigherPriorityTaskWoken ) == pdTRUE )
{
/* A character was retrieved from the queue so can be sent to the
THR now. */
S_UART_SendData( cChar );
}
}
else
{
xReturn = pdFAIL;
}
return xReturn;
}
UARTCommandConsole.c, FreeRTOS_CLI.c
Feature of thease files is as below.
First, it parses serial input data whether it is command or not and then if it is command, it will run task of command.
CLI-commands.c
It manages command list for using CLI. If you make CLI_Command_Definition_t as xSetNetConfig, you can add command.
In this example, I used SetNetConfig and GetNetConfig command.
static const CLI_Command_Definition_t xSetNetConfig =
{
"set-net",
"set-network <ip-addr> <subnet> <gateway>:\r\n",
prvSetNetworkConfigCommand, /* The function to run. */
3 /* Three parameters are expected, which can take any value. */
};
static const CLI_Command_Definition_t xGetNetConfig =
{
"get-net",
"get-network\r\n",
prvGetNetworkConfigCommand, /* The function to run. */
0
};
void vRegisterCLICommands(void)
{
/* Register all the command line commands defined immediately above. */
FreeRTOS_CLIRegisterCommand(&xSetNetConfig);
FreeRTOS_CLIRegisterCommand(&xGetNetConfig);
}
Thease codes are task for each command.
prvSetNetworkConfigCommand function is run when “set-net” command is input. This function can set IP address, Subnet mask and Gateway address of WIZwiki-W7500ECO.
prvGetNetworkConfigCommand is run when “get-net” command is input. This function can get network information of WIZwiki-W7500ECO.
static BaseType_t prvSetNetworkConfigCommand( char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString )
{
const char *pcParameter;
char ip[16]={0};
char subnet[16]={0};
char gateway[16]={0};
BaseType_t xParameterStringLength, xReturn;
/* Remove compile time warnings about unused parameters, and check the
write buffer is not NULL. NOTE - for simplicity, this example assumes the
write buffer length is adequate, so does not check for buffer overflows. */
( void ) pcCommandString;
( void ) xWriteBufferLen;
configASSERT( pcWriteBuffer );
pcParameter = FreeRTOS_CLIGetParameter(pcCommandString, 1, &xParameterStringLength);
strncat(ip, pcParameter, xParameterStringLength);
setSIPR( str_to_ip_array(ip) );
pcParameter = FreeRTOS_CLIGetParameter(pcCommandString, 2, &xParameterStringLength);
strncat(subnet, pcParameter, xParameterStringLength);
setSUBR( str_to_ip_array(subnet) ) ;
pcParameter = FreeRTOS_CLIGetParameter(pcCommandString, 3, &xParameterStringLength);
strncat(gateway, pcParameter, xParameterStringLength);
setGAR( str_to_ip_array(gateway) );
sprintf(pcWriteBuffer,SUCCESS_MESSAGE);
xReturn = pdFALSE;
return xReturn;
}
static BaseType_t prvGetNetworkConfigCommand( char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString )
{
BaseType_t xReturn;
uint8_t tmp[8];
static int paramCount = 0;
/* Remove compile time warnings about unused parameters, and check the
write buffer is not NULL. NOTE - for simplicity, this example assumes the
write buffer length is adequate, so does not check for buffer overflows. */
( void ) pcCommandString;
( void ) xWriteBufferLen;
configASSERT( pcWriteBuffer );
switch(paramCount)
{
case 0:
getSHAR(tmp);
sprintf(pcWriteBuffer,"MAC ADDRESS : %.2X:%.2X:%.2X:%.2X:%.2X:%.2X\r\n",tmp[0],tmp[1],tmp[2],tmp[3],tmp[4],tmp[5]);
xReturn = pdPASS;
paramCount++;
break;
case 1:
getSIPR(tmp);
sprintf(pcWriteBuffer,"IP ADDRESS : %d.%d.%d.%d\r\n",tmp[0],tmp[1],tmp[2],tmp[3]);
xReturn = pdPASS;
paramCount++;
break;
case 2:
getGAR(tmp);
sprintf(pcWriteBuffer,"GW ADDRESS : %d.%d.%d.%d\r\n",tmp[0],tmp[1],tmp[2],tmp[3]);
xReturn = pdPASS;
paramCount++;
break;
case 3:
getSUBR(tmp);
sprintf(pcWriteBuffer,"SN MASK : %d.%d.%d.%d\r\n",tmp[0],tmp[1],tmp[2],tmp[3]);
xReturn = pdPASS;
paramCount++;
break;
default:
paramCount=0;
xReturn = pdFALSE;
break;
}
return xReturn;
}
Demo
To check my example,I did test as below.
First, I checked default network information of WIZwiki-W7500ECO using get-net command and then I send ping data on my PC.
Second, I changed IP address to 192.168.77.50 using set-net command and then I send ping again.
Future Work
This project is prototype for using FreeRTOS on WIZwiki-W7500ECO so It needs to add more commands.
And, In current version, It can’t use network libraries of W7500 because It handles socket event using polling method.
So I have to change network libraries for using interrupt method.
Comments