• No results found

The Persistent Data Server (PDS) component of the BitCloud stack implements interfaces and functionality for storing and restoring data in a non-volatile (NV) memory storage. Section 8.1 describes how to configure the PDS scheme. In PDS particular pieces of persistent data are called files and groups of parameters are called directories. Section 8.2 describes how to define such persistent items, while Section 8.3 gives an overview of PDS API functions that can be used to store and restore them.

Finally Section 8.4 explains how application can maintain internal stack data in PDS. Section 8.5 provides an example how to create own persistent item for application data.

8.1

PDS Configuration

Wear-leveling PDS implemented in BitCloud/Components/PersistDataServer/wl/ supports only internal flash as non-volatile memory. The main feature behind the wear leveling PDS is the mechanism designed to extend the lifetime of the NV storage as well as to protect data from being lost when a reset occurs during writing to the NV. This

mechanism is based on writing data evenly through the dedicated area, so that the storage’s lifetime in not limited by the number of reading and writing operations performed with more frequently used parameters. For this purpose, the non-volatile storage organized as a cyclic log with new versions of data being written at the end of the log, not in place where the previous versions of the same data are stored.

To use PDS with wear leveling, the PDS_ENABLE_WEAR_LEVELING label shall be set to 1 in application’s configuration.h file, and configure other PDS parameters as follows:

Define PDS_NO_BOOTLOADER_SUPPORT if application will run as standalone without AVR2054 bootloader [4]. If Serial/OTA bootloader is used with the application then this define shall be not present as Flash access functions from the AVR2054 bootloader area will be used.

PERSISTENT_NV_ITEMS_PLATFORM is normally set to NWK_SECURITY_COUNTERS_MEM_ID to ensure that network security counters are not erased on network rejoins and factory new resets

PERSISTENT_NV_ITEMS_APPLICATION is normally set to 0xFFFu to indicate that application will handle its data in PDS by itself. See Section 8.5.

If amount of application data files and directories exceeds default values then redefine

APPLICATION_MAX_FILES_AMOUNT and APPLICATION_MAX_DIRECTORIES_AMOUNT parameters with the new ones. See Section 8.5.

Make sure the PDS area reserved for wear-leveling is defined in the application linker script via D_NV_MEMORY_START and D_NV_MEMORY_SIZE parameters

8.2

Defining Files and Directories

In PDS particular pieces of persistent data are called files (or items), and groups of files are called directories. Note that directories are just the way to refer to particular files, and a file can belong to several directories at once. Files and directories contain the meta-information about the data that allows its maintenance within the NV – file descriptors and directory descriptors.

The PDS component defines a number of file units for individual stack parameters and directories to group files, for more subtle control (see Section 8.4). The application may define its own items (see Section 8.5).

8.2.1 File Descriptors

A file descriptor consists of the following parts:

memoryId: memory identifier associated with a file

size: the size of file’s data

ramAddr: the pointer to item’s entity in RAM (that is, to a variable holding file’s data), if one exists, or NULL otherwise

fileMarks: file marks, specifying specific characteristics of the file. File marks may be set either to following values:

• SIZE_MODIFICATION_ALLOWED: indicates that size of the file can be different in new firmware image after over-the-air upgrade. Usually is set for files storing table data, such as binding table, group table and others.

ITEM_UNDER_SECURITY_CONTROL: no impact, works same as NO_FILE_MARKS

NO_FILE_MARKS: no special characteristics for the file

A file descriptor tied to some data in RAM is defined by using the PDS_DECLARE_FILE macro in the code that may be used by both the stack and the application:

PDS_DECLARE_FILE(memoryId, size, ramAddr, fileMarks)

Section 8.5 provides an example how application can define a persistent data file for own data.

8.2.2 Directory Descriptors

Directory descriptors are special entities describing a group of file. A directory descriptor is defined in the code (the stack’s or the application’s one) and is placed to the separate flash memory segment.

The directory descriptor consists of the following parts:

list: pointer to the list of files IDs associated with the directory. This list should be placed in the flash memory (by the use of the PROGMEM_DECLARE macro – see an example below).

filesCount: the amount of files associated with the directory

memoryId: memory identifier associated with the directory

A directory is declared via the PDS_DECLARE_DIR macro in the following way:

PDS_DECLARE_DIR(const PDS_DirDescr_t csGeneralParamsDirDescr) = {

.list = CsGeneralMemoryIdsTable,

.filesCount = ARRAY_SIZE(CsGeneralMemoryIdsTable), .memoryId = BC_GENERAL_PARAMS_MEM_ID

};

//Where CsGeneralMemoryIdsTable is the list of objects defined in the following way: PROGMEM_DECLARE(const PDS_MemId_t CsGeneralMemoryIdsTable[]) =

{

CS_UID_MEM_ID,

CS_RF_TX_POWER_MEM_ID,

//other parameters in this list }

Note that each file in this list shall be defined using the PDS_DECLARE_FILE macro as described in Section 8.2.1. Linker will form the complete list of directory descriptors at compile time.

8.3

PDS API Functions

The API functions are used to perform actions with data prepared for storing in the NV memory and identified via memory IDs: with files and directories. The functions are listed and explained in Table 8-1. Most of the functions have the memoryId argument, which should be set to the ID of a file or a directory. For details on using the API see BitCloud API Reference [3], which is available with the BitCloud SDK.

Caution: Although the HAL component also provides read/write functions for Flash, it is strongly recommended to use the PDS component for such purposes to eliminate the risk of overwriting stack-specific variables.

Table 8-1. PDS API Functions.

Function Description

PDS_Store(memoryId) Writes the object (a file or a directory) with the specified memory ID to the NV storage.

PDS_StoreByEvents(memoryId) The specified stack object will be written to the NV storage each time one of the events, to which the object is subscribed, occurs. Such mapping is done inside PDS via EVENT_TO_MEM_ID_MAPPING macro.

PDS_Restore(memoryId) Reads the latest version of the object from the NV storage.

PDS_Delete(memoryId) Marks a file or all files in a directory as deleted. The space occupied by deleted files is considered unoccupied.

PDS_IsAbleToRestore(memoryId) Determines if the specified object can be restored from the NV storage.

To save data attributed to a file or a directory into the NV storage the application should call the PDS_Store() function, providing memory identifier of a file or a directory as an argument. For example, to force saving of all BitCloud stack parameters use the following code:

PDS_Store(BC_ALL_MEMORY_MEM_ID);

To be able to store several specific files at once, define a directory containing these files (this may be done at compile time only) and provide the memory ID of this directory to the PDS_Store() function.

To restore data from the NV storage to the data variables the application should call the PDS_Restore() function, providing an identifier of a file or a directory to be restored. Before trying to restore data, the application may check that restoring of a specific item is possible, using the PDS_IsAbleToRestore() function. If the item specified in the argument cannot be restored (because, for instance, it has not been filled with data and saved) the function will return false. For example, the application may use the following code to restore an application directory with the

BC_ALL_MEMORY_MEM_ID identifier:

if (PDS_IsAbleToRestore(BC_ALL_MEMORY_MEM_ID)) PDS_Restore(BC_ALL_MEMORY_MEM_ID);

8.4

Maintaining Stack Data in the NV Storage

PDS implements a simple interface to maintain in persistent memory important network-related ConfigServer

parameters including various internal tables (neighbor table, binding table, etc.). PDS memory identifiers for such files and directories are declared in and Components/PersistDataServer/wl/include/wlPdsMemIds.h file. The files and directories themselves for stack data are defined in the CS component in the

/ConfigServer/src/csPersistentMem.c file (to understand how files and directories are defined see Section8.2). The application can maintain stack parameters as follows:

Rely on the BitCloud stack for automatic storing of stack parameters on pre-defined events that are likely to change their values. For this the application should call the PDS_StoreByEvents() function once to specify a file or a directory that should be taken under maintenance by events (for example,

BC_ALL_MEMORY_MEM_ID – to store all stack files).

Store stack data at arbitrary moments by itself, using the PDS_Store() function

Stack data should also be restored in the application via the PDS_Restore() function, for example during initialization, as described in Section 8.3.

8.5

Maintaining Application Data in the NV Storage

An application can maintain arbitrary application data in the NV storage, using simple interface of the PDS component. For the application data, the user shall define file descriptors, tying them to particular variables, and, if necessary, define directories to organize files in groups. The PDS API is then used to store and restore the defined items.

The application can use APP_DIR1_MEM_ID and APP_DIR2_MEM_ID identifiers for application directories and identifiers formatted as APP_PARAM<number>_MEM_ID for files.

Among the memory IDs there are some IDs intended to be used by the application (APP_*), and the application can define more IDs if needed. There are also two important constants set in this file: APPLICATION_MAX_FILES_AMOUNT

limiting the number of files that can be defined in the system and APPLICATION_MAX_DIRECTORIES_AMOUNT limiting the number of directories.

The application should first define file descriptors, using the PDS_DECLARE_FILE macro for each file, providing it with the ID, the size of data, the pointer to the RAM memory storing the data itself, and file marks.

For example, consider an application that needs to store instances called scenes and server attributes of the Scenes cluster.

//The variables that store the application data extern Scene_t scenes[MAX_NUMBER_OF_SCENES];

extern ZCL_SceneClusterServerAttributes_t scenesClusterServerAttributes; PDS_DECLARE_FILE(APP_PARAM1_MEM_ID, sizeof(Scene_t)*MAX_NUMBER_OF_SCENES, &scenes, NO_FILE_MARKS); PDS_DECLARE_FILE(APP_PARAM2_MEM_ID, sizeof(ZCL_SceneClusterServerAttributes_t), &scenesClusterServerAttributes), NO_FILE_MARKS);

The next step is to define a separate list of memory IDs assigned to the files, using the PRGMEM_DECLARE macro: PROGMEM_DECLARE(const PDS_MemId_t appMemoryIdsTable[]) =

{

APP_PARAM1_MEM_ID, APP_PARAM2_MEM_ID, }

Finally, the application should define a directory descriptor, using the PDS_DECLARE_DIR macro, in the following way: PDS_DECLARE_DIR(const PDS_DirDescr_t appMemoryDirDescr) =

{

.list = appMemoryIdsTable,

.filesCount = ARRAY_SIZE(appMemoryIdsTable), .memoryId = APP_DIR1_MEM_ID //Directory ID };

The provided code samples completely define auxiliary structures to store the application data in the NV storage. PDS API function (see Section 8.3) such as PDS_Store() and PDS_Restore() can be used with

APP_PARAM1_MEM_ID, APP_PARAM2_MEM_ID and APP_DIR1_MEM_ID as an argument to maintain the contents of these variables in the NV storage.

To simplify the file and directory management in the application code, it is also possible to map own memory ID to the target one for example:

#define APP_LIGHT_DATA_MEM_ID APP_DIR1_MEM_ID