CmdProcessor

  1. Description
  2. API Overview
  3. Initialization
  4. Enqueue Functions
  5. App CmdProcessor
  6. Full Code Example

Description

With the release of Workbench 3.0, a new feature has been added, which is called CmdProcessor. This is essentially a combination of the features task and queue, both explained in separate articles, that lets the developer send functions to the CmdProcessor, which will then be processed by the internal task. This allows for more control of the environment in which a function will run, and provides a strict order of execution. Additionally, the functions AppController_Init(), AppControllerSetup() and AppControllerEnable() are also called in the context of a CmdProcessor and receive the handle for the CmdProcessor as their input. It will be explained later in this chapter.

Image

The CmdProcessor is provided by the header file BCDS_CmdProcessor.h. To make it available in your code, the header file must be included.

API Overview

The essential functions and types it implements are listed in the following table

APIDescription
CmdProcessor_TThis type holds the structure of the CmdProcessor. It has the internal task and queue as fields. Additionally, its name can be accessed. The reference to a CmdProcessor_T is required by every function of the API.
CmdProcessor_Initialize()This function initializes the CmdProcessor. The signature is similar to xTaskCreate. This function receives a name, the task priority, the task stack depth, and the queue size as inputs.
CmdProcessor_Enqueue()This function adds a function to the queue of the CmdProcessor. As input, it receives the function, which will be added to the CmdProcessor's queue and two input parameters for the function.

Initialization

To use the API, a variable of type CmdProcessor_T has to be declared and initialized via CmdProcessor_Initialize(). This is shown in the following code.

static CmdProcessor_T myCmdProcessor; // this should be global
static CmdProcessor_T *myCmdProcessor_ptr = &myCmdProcessor; // same here

CmdProcessor_Initialize(
    myCmdProcessor_ptr, // pointer to the CmdProcessor_T
    "my cmd processor", // the internal task's name
    tskIDLE_PRIORITY, // the internal task's priority
    UINT32_C(300), // stack depth (stack size is stack depth * 4)
    4 // the internal queue's size
);

The function has five inputs, a pointer to the CmdProcessor itself, a name for the task, a priority, a stack depth and a queue size. The priority and stack depth should be chosen according to the nature of the functions, this CmdProcessor has to process. In any case, the priority must be lower than the priority of the FreeRTOS scheduler. If the functions need much space, a higher stack depth should be chosen. The queue size determines how many functions can be queued, and thus be waiting for execution, at the same time.

Note: It is recommended to make the CmdProcessor and also the pointer a global variable. If the variables are deleted and their content overwritten, it might lead to unexpected behavior.

Enqueue Functions

For a function to be enqueued, it has to have a specific signature. The code below shows an example for such a function. It is static, has return-type void and the only inputs are two parameters. The first being a void pointer, the second one being of type uint32_t. These parameters will be given to the function at runtime by the function CmdProcessor_Enqueue().

#include "stdio.h" // if not already included

static void myFunction(void *param1, uint32_t param2)
{
  BCDS_UNUSED(param1);
  BCDS_UNUSED(param2);
  printf("Function processed!\r\n");
}

Note: The macro BCDS_UNUSED suppresses compiler warnings, caused by unused variables.

Now that a function is written, it has to be enqueued. The following shows how to enqueue the function myFunction() from the previous code. While this code only enqueues this function one time, it can be enqueued multiple times. There is essentially no limit to how often a function can be enqueued. The only limit is the queue size, which determines the number of functions that can be queued at the same time.

CmdProcessor_Enqueue(
    myCmdProcessor_ptr, // pointer to the CmdProcessor_T
    myFunction, // the function to be queued
    NULL, // parameter 1
    0 // parameter 2
);

These code snippets will be enough to get by with the CmdProcessor for most applications, but another great advantage compared to a task is, that the CmdProcessor can call the same function with different parameters every time. While the previous enqueue uses NULL and 0 as the parameters respectively, parameter 1 can be a pointer to a variable of any type and parameter 2 can be any unsigned 32-bit integer value. The code-snippet below demonstrates how to use these parameters. The first function myParameterFunction() will be enqueued, and parameter 1 will point to an integer. Before the integer is used inside the function, it should be verified that the pointer does not point to NULL (i.e. nothing). Parameter 2 can be safely used. The second function will enqueue the first function with predetermined values.

#include "stdio.h" // if not already included

static void myParameterFunction(void *param1, uint32_t param2)
{
  if(param1 != NULL){
    int *myInteger = param1;
    printf("My favorite integers are: %d and %d\n\r",
              *myInteger, (int) param2);
  }
  printf("Function processed!\r\n");
}

App CmdProcessor

As mentioned before, the entry points of every application AppController_Init(), followed by AppControllerSetup() and AppControllerEnable() are called within the context of a CmdProcessor as well. Additionally, the first parameter in every one of these, is the pointer to the CmdProcessor, which can be consequently reused within the application. The next code snippet shows how to retrieve the CmdProcessor with a pointer. To be able to use this CmdProcessor outside of the function, make sure to create a global variable for the pointer. Otherwise the pointer will be lost after AppControllerEnable() has been executed.

static CmdProcessor_T * AppCmdProcessor;

static void AppControllerEnable(void * param1, uint32_t param2) {
    BCDS_UNUSED(param1);
    BCDS_UNUSED(param2);

    vTaskDelay(5000);

    AppCmdProcessor = (CmdProcessor_T *) param1;
    CmdProcessor_Enqueue(myCmdProcessor_ptr, myFunction, NULL, 0);
}

Full Code Example

Note: The full code examples are intended for XDK-Workbench versions 3.4.0 and higher.

/* --------------------------------------------------------------------------- |
 * INCLUDES & DEFINES ******************************************************** |
 * -------------------------------------------------------------------------- */

/* own header files */
#include "XdkAppInfo.h"
#undef BCDS_MODULE_ID  /* Module ID define before including Basics package*/
#define BCDS_MODULE_ID XDK_APP_MODULE_ID_APP_CONTROLLER

/* system header files */
#include <stdio.h>

/* additional interface header files */
#include "BCDS_CmdProcessor.h"
#include "FreeRTOS.h"
#include "task.h"

/* --------------------------------------------------------------------------- |
 * HANDLES ******************************************************************* |
 * -------------------------------------------------------------------------- */

static CmdProcessor_T * AppCmdProcessor;/**< Handle to store the main Command processor handle to be used by run-time event driven threads */
static CmdProcessor_T myCmdProcessor; // this should be global
static CmdProcessor_T *myCmdProcessor_ptr = &myCmdProcessor; // same here

/* --------------------------------------------------------------------------- |
 * VARIABLES ***************************************************************** |
 * -------------------------------------------------------------------------- */

/* --------------------------------------------------------------------------- |
 * EXECUTING FUNCTIONS ******************************************************* |
 * -------------------------------------------------------------------------- */

static void myFunction(void *param1, uint32_t param2)
{
  BCDS_UNUSED(param1);
  BCDS_UNUSED(param2);
  printf("Function Processed!\r\n");
}

static void myParameterFunction(void *param1, uint32_t param2)
{
if(param1 != NULL){
  int *myInteger = param1;
  printf("My favorite integers are: %d and %d\n\r",
            *myInteger, (int) param2);
}
  printf("Function Processed!\r\n");
}

/* --------------------------------------------------------------------------- |
 * BOOTING- AND SETUP FUNCTIONS ********************************************** |
 * -------------------------------------------------------------------------- */

static void AppControllerEnable(void * param1, uint32_t param2)
{
    BCDS_UNUSED(param1);
    BCDS_UNUSED(param2);

    /* Enable necessary modules for the application and check their return values */

    vTaskDelay(5000);

    AppCmdProcessor = (CmdProcessor_T *) param1;
    CmdProcessor_Enqueue(myCmdProcessor_ptr, myFunction, NULL, 0);

    CmdProcessor_Initialize(
        myCmdProcessor_ptr, // pointer to the CmdProcessor_T
        "my cmd processor", // the internal task's name
        tskIDLE_PRIORITY, // the internal task's priority
        UINT32_C(300), // stack depth (stack size is stack depth * 4)
        4 // the internal queue's size
    );

    CmdProcessor_Enqueue(
        myCmdProcessor_ptr, // pointer to the CmdProcessor_T
        myFunction, // the function to be queued
        NULL, // parameter 1
        0 // parameter 2
    );

    static int myInteger = 5;
    CmdProcessor_Enqueue(
        myCmdProcessor_ptr, // pointer to the CmdProcessor_T
        myParameterFunction, // the function to be queued
        &myInteger, // parameter 1
        7  // parameter 2
    );

}

static void AppControllerSetup(void * param1, uint32_t param2)
{
    BCDS_UNUSED(param1);
    BCDS_UNUSED(param2);
    Retcode_T retcode = RETCODE_OK;

    /* Setup the necessary modules required for the application */

    retcode = CmdProcessor_Enqueue(AppCmdProcessor, AppControllerEnable, NULL, UINT32_C(0));
    if (RETCODE_OK != retcode)
    {
        printf("AppControllerSetup : Failed \r\n");
        Retcode_RaiseError(retcode);
        assert(0); /* To provide LED indication for the user */
    }
}

void AppController_Init(void * cmdProcessorHandle, uint32_t param2)
{
    BCDS_UNUSED(param2);

    Retcode_T retcode = RETCODE_OK;

    if (cmdProcessorHandle == NULL)
    {
        printf("AppController_Init : Command processor handle is NULL \r\n");
        retcode = RETCODE(RETCODE_SEVERITY_ERROR, RETCODE_NULL_POINTER);
    }
    else
    {
        AppCmdProcessor = (CmdProcessor_T *) cmdProcessorHandle;
        retcode = CmdProcessor_Enqueue(AppCmdProcessor, AppControllerSetup, NULL, UINT32_C(0));
    }

    if (RETCODE_OK != retcode)
    {
        Retcode_RaiseError(retcode);
        assert(0); /* To provide LED indication for the user */
    }
}

/** ************************************************************************* */