FreeRTOS-Plus-CLI + static memory allocation

Static memory allocation for FreeRTOS has been available since 2016, but while trying to use it along with FreeRTOS-Plus-CLI, I found out that this library does not support it.

But! I implemented the feature, in what I believe is an FreeRTOS-y way and if the community wants it, I would like to contribute.

It works in the following way:
1- The type definition for CLI_Definition_List_Item_t is moved from the FreeRTOS_CLI.c to FreeRTOS_CLI.h

typedef struct xCOMMAND_INPUT_LIST
{
	const CLI_Command_Definition_t *pxCommandLineDefinition;
	struct xCOMMAND_INPUT_LIST *pxNext;
} CLI_Definition_List_Item_t;

2- In FreeRTOS_CLI.h, a new API is added to register a command on the static list of commands:

BaseType_t FreeRTOS_CLIRegisterCommandStatic( const CLI_Command_Definition_t * const pxCommandToRegister, CLI_Definition_List_Item_t *  );

3- In FreeRTOS_CLI.c, the FreeRTOS_CLIRegisterCommand is renamed and modified as follows to remove the malloc and accept the pointer as an argument instead.

static BaseType_t FreeRTOS_CLIRegisterCommandInternal( const CLI_Command_Definition_t * const pxCommandToRegister, CLI_Definition_List_Item_t * pxNewListItem )
{
static CLI_Definition_List_Item_t *pxLastCommandInList = &xRegisteredCommands;
BaseType_t xReturn = pdFAIL;
    
    /* Check the parameters are not NULL. */
	configASSERT( pxCommandToRegister );
    configASSERT( pxNewListItem );
    
    if( pxNewListItem != NULL )
	{
		taskENTER_CRITICAL();
		{
			/* Reference the command being registered from the newly created
			list item. */
			pxNewListItem->pxCommandLineDefinition = pxCommandToRegister;

			/* The new list item will get added to the end of the list, so
			pxNext has nowhere to point. */
			pxNewListItem->pxNext = NULL;

			/* Add the newly created list item to the end of the already existing
			list. */
			pxLastCommandInList->pxNext = pxNewListItem;

			/* Set the end of list marker to the new list item. */
			pxLastCommandInList = pxNewListItem;
		}
		taskEXIT_CRITICAL();

		xReturn = pdPASS;
	}
    
    return xReturn;
}

4- Finally, in FreeRTOS_CLI.c, the set of register commands is included using the configSUPPPORT_DYNAMIC_ALLOCATION and configSUPPORT_STATIC_ALLOCATION macros

/*-----------------------------------------------------------*/
#if configSUPPORT_STATIC_ALLOCATION == 1
BaseType_t FreeRTOS_CLIRegisterCommandStatic( const CLI_Command_Definition_t * pxCommandToRegister, CLI_Definition_List_Item_t * pxNewListItem )
{
    return  FreeRTOS_CLIRegisterCommandInternal( pxCommandToRegister, pxNewListItem );
}
#endif

/*-----------------------------------------------------------*/
#if configSUPPPORT_DYNAMIC_ALLOCATION == 1
BaseType_t FreeRTOS_CLIRegisterCommand( const CLI_Command_Definition_t * const pxCommandToRegister )
{
CLI_Definition_List_Item_t *pxNewListItem;

	/* Create a new list item that will reference the command being registered. */
	pxNewListItem = ( CLI_Definition_List_Item_t * ) pvPortMalloc( sizeof( CLI_Definition_List_Item_t ) );
	
    return FreeRTOS_CLIRegisterCommandInternal( pxCommandToRegister, pxNewListItem );
}
#endif
/*-----------------------------------------------------------*/

I can provide the complete modified files on request.

1 Like

To use it with static memory allocation:
1- Enable the configSUPPORT_STATIC_ALLOCATION macro in FreeRTOSConfig.h
2- Define all your commands as you would normally

const CLI_Command_Definition_t xTerminal_CommandsReset = 
{
    .pcCommand = "reset",
    .pcHelpString = "reset: resets the MCU\r\n",
    .pxCommandInterpreter = xTerminal_CommandsResetCallback,
    .cExpectedNumberOfParameters = INT8_C(0),
};

3- Create an array containing the pointers to all the command definitions:

// Complete list of all commands goes here
const CLI_Command_Definition_t *pxTerminalCommands[] = 
{
    &xTerminal_CommandsFileWrite,
    &xTerminal_CommandsFileRead,
    &xTerminal_CommandsLs,
    &xTerminal_CommandsMv,
    &xTerminal_CommandsRm,
    &xTerminal_CommandsReset,
};

4- (static only) Create the list of all the commands:

//buffer automatically allocated for the list of all commands
CLI_Definition_List_Item_t xTerminal_CommandsList[sizeof(pxTerminalCommands)/sizeof(pxTerminalCommands[0])];

5- Register the commands as you would normally, but using the static API

void vTerminal_CommandsRegisterCallbacks()
{
    for (int i=0; i<sizeof(pxTerminalCommands)/sizeof(pxTerminalCommands[0]); ++i)
    {
        FreeRTOS_CLIRegisterCommandStatic( pxTerminalCommands[i], 
                                           &xTerminal_CommandsList[i] );
    }
}

@maharvey thank you so much for posting. This looks really cool! Not to mention, it does read pretty FreeRTOS-y to me :slight_smile: I’m not the +CLI resident expert on our team so I’ll bring this up with the team.

In the meantime, if you have the code in a workable state please feel free to post a pull request to our repository! Doing so will help us discuss the implementation.

I created the following pull request on GitHub:

Marking your PR as solving the problem. Your PR was merged today. Thanks for contributing to FreeRTOS :smile:

1 Like