Key Points

  • Basecamp apps use JSON files for parameter tables.
  • Each Basecamp app manages reading parameter values from the file and writing parameters to a JSON file. They do not use the cFS Table service that operates on binary files.
  • The Basecamp application framework library combined with design patterns make it easy to define and access the JSON configuration parameters.
  • Code snippets from Basecamp’s demo app serve as examples.

cFS Parameter Tables

Tables are logical groups of parameters that are managed as a named entity. cFS table files are binary files that contain a cFS file header, a table header and the parameter data. The default table is defined in a C source file that is converted to a binary table file during the build process. The cFS Table Service manages the ground interface processes for loading and dumping an app’s parameter table. The loading process includes verifying the table file content, copying the data to a cFS buffer and ‘activating’ the table so an app uses the new table data.  The dumping process includes copying data from a cFS table buffer to a table file. Since tables are binary files, tools are required for creating the binary from text and for displaying text from the binary.   

Basecamp apps use JSON files for parameter tables that are the focus of this article. Code snippets are from Basecamp’s demo app.

JSON Parameter Table Files

The Basecamp demo app creates a histogram that records how many times randomly generated data samples fall within a set of data ranges.  Each data range is called a bin. The data is called device data because it generically represents data that comes from any type of component on a spacecraft.

The demo app’s default histogram parameter table is shown below.  The JSON object definitions are up to the app developer, however by convention Basecamp app include app-name, tbl-name and description as the first three objects.  Description is an array of strings that serves as a comment block.  The histogram is defined as 5 bins that equally divide a range of data from 0 to 99.  As noted in the description the device data range is defined in the demo app’s initialization table by the DEVICE_DATA_MODULO parameter.  Modulo is a mathematical operator that returns the remainder after dividing one number by another.  A modulo operator applied to a randomly generated number will return a value from 0 to 99.

Functional Object Design

Demo App’s object diagram illustrates the Basecamp table design pattern. A separate object is created for managing the table, in this case HistogramTbl. This object defines load and dump command functions and local storage, TblData for storing data during the load process.  The object that owns the table (e.g. Histogram) defines the instance data for the table object. This data is used by the object as it executes. For successful table loads, the table object’s data is copied to the owning object’s table instance data.

App Framework Table Manager

Basecamp’s app framework library includes a Table Manager service that takes care of table file management and JSON parser interface details. Developers only need to concentrate on writing table load and dump command functions. The Table Manager object is owned by the app’s main object. The following code snippets illustrate the demo app’s main object table responsibilities.

app_c-demo.h

Declare a Table Manager object in the class structure:

TBLMGR_Class_t    TblMgr;

app_c-demo.c

Optionally define the following macro to improve readability since a pointer to the TblMgr object is frequently referenced.

#define  TBLMGR_OBJ  (&(AppCDemo.TblMgr))

In the app’s initialization function perform the following steps:

  1. Construct the table manager object

TBLMGR_Constructor(TBLMGR_OBJ, INITBL_GetStrConfig(INITBL_OBJ, CFG_APP_CFE_NAME));

2. Construct the object that owns the table.

HISTOGRAM_Constructor(HISTOGRAM_OBJ, INITBL_OBJ, TBLMGR_OBJ);

3. Register the table load and dump command functions. Note that the table manager’s functions are registered and not the table object’s functions. Table commands contain a table ID parameter so the table manager can call the appropriate table object function. Table IDs are assigned when the owner of a table object registers the table with the table manager.

CMDMGR_RegisterFunc(CMDMGR_OBJ, APP_C_DEMO_LOAD_TBL_CC, TBLMGR_OBJ, TBLMGR_LoadTblCmd, sizeof(APP_C_DEMO_LoadTbl_CmdPayload_t));

CMDMGR_RegisterFunc(CMDMGR_OBJ, APP_C_DEMO_DUMP_TBL_CC, TBLMGR_OBJ, TBLMGR_DumpTblCmd, sizeof(APP_C_DEMO_DumpTbl_CmdPayload_t));

3. Call table manager’s reset function in the app’s reset command function.

TBLMGR_ResetStatus(TBLMGR_OBJ);

4. Optionally send table status in telemetry. Telemetry content and rates are tuned for each mission. The demo app includes table manager’s last attempted action and the status of that action.  If an app has more than one table TBLMGR_GetLastTblStatus() returns the status of the last table operated upon.

const TBLMGR_Tbl_t *LastTbl = TBLMGR_GetLastTblStatus(TBLMGR_OBJ);  APP_C_DEMO_StatusTlm_Payload_t *Payload = &AppCDemo.StatusTlm.Payload;

Payload->LastTblAction       = LastTbl->LastAction;

Payload->LastTblActionStatus = LastTbl->LastActionStatus;

Table Owning Object

Histogram.h

Declare a Table object in the class structure:

HISTOGRAM_TBL_Class_t  Tbl;

histogram.c

In the constructor, construct the table object and register it with the table manager. Pass the object table’s load and dump command functions. These are called by the table manager’s load and dump commands that are registered with Command Manager by the main app object. This example loads default table values from a file the which is typically done during registration.

HISTOGRAM_TBL_Constructor(&Histogram->Tbl, AcceptNewTbl);

TBLMGR_RegisterTblWithDef(TblMgr, HISTOGRAM_TBL_NAME, HISTOGRAM_TBL_LoadCmd, HISTOGRAM_TBL_DumpCmd,  INITBL_GetStrConfig(IniTbl, CFG_HIST_TBL_LOAD_FILE));

Table Object

The best way to create a table object for your app is to copy an existing table object, change the global names and modify the load and dump functions. The dump function is a series of sprintf() function calls and will not be covered here.  The load process is governed by a data structure that simplifies customization.  Here are the key fields of demo app’s table load data structure:

The first two columns specify where the JSON data is loaded, address and length, and the last two columns are used by the core JSON parser to retrieve the data.  Developers don’t have to directly invoke the JSON parser. Basecamp’s app framework’s CJSON object reduces the app developer’s code to the following function calls:   

CJSON_ProcessFile(Filename, HistogramTbl->JsonBuf, HISTOGRAM_TBL_JSON_FILE_MAX_CHAR, LoadJsonData);

CJSON_LoadObjArray(JsonTblObjs, HistogramTbl->JsonObjCnt, HistogramTbl->JsonBuf, HistogramTbl->JsonFileLen);

CJSON_ProcessFile() validates the JSON and reads the contents into memory. The last parameter. LoadJsonData , is a pointer to a function and in this function is a call to CJSON_LoadObjArray().  This function processes the JSON from memory and loads the data into the table object using the JsonTblObjs[] described above.

Concluding Remarks

The best way to create a table object for your app is to copy an existing table object, change the global names and modify the load and dump functions. Note some apps like KIT_TO have commands that can modify the parameters that were originally loaded from a table. The table object owner should provide an interface for these commands because it owns the data that is being used.  

Apps may have more than one table.  Table IDs are assigned based on the order of table registrations which is not the best design. Basecamp issue #103 https://github.com/cfs-tools/cfs-basecamp/issues/103 has more information.

Each app’s JSON parameter table filename must be added to the “FILELIST’ in targets.cmake.

Related Articles

  1. cFS Basecamp App Design
  2. cFS Basecamp App Framework
  3. cFS Basecamp JSON
  4. cFS Basecamp App JSON Initialization Files

Discover more from Space Steps

Subscribe now to keep reading and get access to the full archive.

Continue reading