...
To add your own variables, we simply start to declare them using some macros provided by goal_cm.h
:
Code Block | ||
---|---|---|
| ||
/* 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 | ||
---|---|---|
| ||
#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 | ||
---|---|---|
| ||
/* 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 | ||
---|---|---|
| ||
/* generate 'GOAL_CM_VARENTRY_T cmVars[]' array that maps the above table */ #include <goal_cm_t.h> GOAL_CM_VARLIST(cmVars, APPL_CM_VARS); |
...
Registering our module at the GOAL CM. This will reserve the according memory in the GOAL CM for handling our new module.
Code Block language c /* register application variables */ res = goal_cmRegModule(cmVars);
Adding our module to the GOAL CM. This will actually our variables to the GOAL CM.
Code Block language c /* 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 | ||
---|---|---|
| ||
#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 | ||
---|---|---|
| ||
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 | ||
---|---|---|
| ||
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 | ||
---|---|---|
| ||
#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 | ||
---|---|---|
| ||
#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 | ||
---|---|---|
| ||
/****************************************************************************/ /** 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 | ||
---|---|---|
| ||
/****************************************************************************/ /** 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 | ||
---|---|---|
| ||
/****************************************************************************/ /** 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 | ||
---|---|---|
| ||
#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"); } |
...