Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: set programming language for source code macros

...

To add your own variables, we simply start to declare them using some macros provided by goal_cm.h:

Code Block
languagec
/*              Name,        Data type,     Max. size,     Validation Cb,  Change Cb */   \
    GOAL_CM_VAR(<VAR_NAME>,  <DATA_TYPE>,   <DATA_SIZE>,   <VAL_CB>,       <CHG_CB>), 

...

So the following code snippet declares the according variables for us:

Code Block
languagec
#define APPL_CM_VARS \
/*              Name,                  Data type,       Max. size,            Validation Cb, Change Cb */   \
    GOAL_CM_VAR(APPL_CM_VAR_ENABLE,    GOAL_CM_UINT8,   sizeof(uint8_t),      NULL,          appl_cmChg),   \
    GOAL_CM_VAR(APPL_CM_VAR_BAUD,      GOAL_CM_UINT32,  sizeof(uint32_t),     NULL,          appl_cmChg),   \
    GOAL_CM_VAR(APPL_CM_VAR_PASSWORD,  GOAL_CM_GENERIC, APPL_CM_PASSWORD_LEN, NULL,          appl_cmChg),   \
    GOAL_CM_VAR(APPL_CM_VAR_USER,      GOAL_CM_STRING,  APPL_CM_STRING_LEN,   NULL,          appl_cmChg),   \
    GOAL_CM_VAR(APPL_CM_VAR_FWREV, GOAL_CM_STRING,  APPL_CM_STRING_LEN,   NULL,          NULL)

...

Now the GOAL CM has to generate the enumeration of the variable IDs of each defined variable. The macro GOAL_CM_VAR_IDS will do this for us:

Code Block
languagec
/* generate 'enum APPL_CM_VARS_ID_T' that contains all variable names */
#include <goal_cm_id.h>
GOAL_CM_VAR_IDS(APPL_CM_VARS_ID_T, APPL_CM_VARS);

We now can generate the variable list we would like to use using the GOAL_CM_VARLIST macro:

Code Block
languagec
/* generate 'GOAL_CM_VARENTRY_T cmVars[]' array that maps the above table */
#include <goal_cm_t.h>
GOAL_CM_VARLIST(cmVars, APPL_CM_VARS);

...

  1. Registering our module at the GOAL CM. This will reserve the according memory in the GOAL CM for handling our new module.

    Code Block
    languagec
    /* register application variables */
        res = goal_cmRegModule(cmVars);
  2. Adding our module to the GOAL CM. This will actually our variables to the GOAL CM.

    Code Block
    languagec
    /* add application variables */
        res = goal_cmAddModule(&cmMod, cmVars, NULL, NULL, NULL);

...

The GOAL CM module provides access functions to set and read values from our variables. First, lets set the initial baud rate for the serial interface to 115200 via goal_cmSetVarValue:

Code Block
languagec
    #define APPL_BAUD_INTIAL 115200
    ...
    val32 = APPL_BAUD_INITIAL;
    res = goal_cmSetVarValue(APPL_CM_MOD_ID, APPL_CM_VAR_BAUD, &val32, sizeof(val32), GOAL_TRUE, NULL);
    if (GOAL_RES_ERR(res)) {
        goal_logErr("error updating updating baud rate");
    }

We can read the current value using goal_cmGetVarValue:

Code Block
languagec
    val32 = 0;
    res = goal_cmGetVarById(APPL_CM_MOD_ID, APPL_CM_VAR_BAUD, &pCmVar);
    if (GOAL_RES_ERR(res)) {
        goal_logErr("error reading baud rate");
    } else {
        goal_logInfo("current baud rate: %d" FMT_x32, GOAL_CM_VAR_UINT32(pCmVar));
    }

...

But wait, shouldn’t we only accept valid values for our baud rate? Let’s assume our hardware guys have messed it up (again… 🤪) and our serial interface only works with 9600 and 115200. We can control which values are accepted using a validation callback for our variable. A validation callback is defined as:

Code Block
languagec
typedef GOAL_STATUS_T (* goal_cm_validate)(
  uint32_t modId, 
  uint32_t varId, 
  GOAL_CM_VAR_T *var, v
  oid *newData, 
  uint32_t size
);

...

Our validation function can be implemented as in the following code snippet:

Code Block
languagec
#define APPL_BAUD_9600    9600
#define APPL_BAUD_115200  115200
...

/****************************************************************************/
/** Handle Baud Rate Changes
 *
 * This function is called by the configuration management when baud rate variable
 * shall be changed.
 */
GOAL_STATUS_T appl_baudVal(
    uint32_t modId,                             /**< module ID */
    uint32_t varId,                             /**< variable ID */
    GOAL_CM_VAR_T *var,                         /**< variable pointer */
    void *newData,                              /**< the new value */
    uint32_t size                               /**< size of new data */
)
{
    GOAL_STATUS_T res;                          /**< Result */
    uint32_t baud;                              /**< Value */
    res = GOAL_ERR_ACCESS;

    /* Check for correct module and variable id */
    if (APPL_CM_MOD_ID == modId && APPL_CM_VAR_BAUD == varId) {
        baud = *((uint32_t*) newData);

        /* Only allow 9600 and 115200 */
        if (APPL_BAUD_9600 == baud || APPL_BAUD_115200 == baud) {
            res = GOAL_OK;
        }
    }

    return res;
}

We need to change our variable declaration for GOAL_CM_VAR_BAUD to let GOAL CM know that we wish to validate any input to this variable:

Code Block
languagec
#define APPL_CM_VARS \
/*              Name,                  Data type,       Max. size,            Validation Cb,      Change Cb */   \
...
    GOAL_CM_VAR(APPL_CM_VAR_BAUD,      GOAL_CM_UINT32,  sizeof(uint32_t),     appl_baudVal,       appl_cmChg),   \
...    

...

Calling goal_cmSave stores the data of all modules using the specific target-dependent function goal_targetNvsWrite:

Code Block
languagec
/****************************************************************************/
/** Saves all variables to permanent storage using the appropriate target
 *  function
 *
 * @retval GOAL_OK Values saved
 * @retval other failed
 */
GOAL_STATUS_T goal_cmSaveImpl(
    void
);

To get the data back from storage, use goal_cmLoad which uses the target-specific goal_targetNvsReadData function:

Code Block
languagec
/****************************************************************************/
/** Loads the variables from permanent storage using the appropriate target
 *  function
 *
 * @retval GOAL_OK Values loaded
 * @retval other failed
 */
GOAL_STATUS_T goal_cmLoad(
    void
);

...

For such uses cases, GOAL CM offers so called virtual variables. Those variables can be created using an API and are excluded from the storage functionality. To declare such a variable, use the function goal_cmRegVarVirtual:

Code Block
languagec
/****************************************************************************/
/** Register a callback to handle access to virtual variables of a specific
 * module id.
 *
 * @retval other failed
 */
GOAL_STATUS_T goal_cmRegVarVirtual(
    uint32_t modId,                             /**< module ID */
    uint32_t varId,                             /**< variable ID */
    GOAL_CM_DATATYPE_T type,                    /**< variable type */
    uint32_t sizeMax,                           /**< maximum size */
    goal_cm_validate validate,                  /**< validate callback */
    goal_cm_changed changed                     /**< change callback */
);

...

So let’s declare our firmware variable as virtual! First, remove the declaration from the variable list. Now we redeclare our variable as virtual in our application:

Code Block
languagec
#define APPL_CM_FWVERSION_VIRTUAL_ID (1024)
...
    /* register virtual fw revision variable. Module must be known to the cm */
    res = goal_cmRegVarVirtual(APPL_CM_MOD_ID, APPL_CM_FWREV_VIRTUAL_ID, GOAL_CM_GENERIC, APPL_CM_STRING_LEN, NULL, NULL);
    if (GOAL_RES_ERR(res)) {
        goal_logErr("error registering virtual fw revision variable");
    }

...