DongEun Koak (kaizen)
Created September 24, 2015 © Apache-2.0

How to implement CLI in your Cortex M0

This post shows how to implement CLI ( Command Line Interpreter ) in your Cortex M0 using FreeRTOS.

IntermediateProtip334
How to implement CLI in your Cortex M0

Things used in this project

Hardware components

WIZwiki-W7500
WIZnet WIZwiki-W7500
×1

Story

Read more

Code

Code

C/C++
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 );
}

Code

C/C++
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;
}

Code

C/C++
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);

}

Code

C/C++
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;
}

Code

C/C++
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 );
}

Code

C/C++
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;
}

Code

C/C++
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);

}

Code

C/C++
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;
}

Github

https://github.com/kaizen8501/W7500_FreeRTOS

Credits

DongEun Koak (kaizen)

DongEun Koak (kaizen)

6 projects • 8 followers

Comments