nRF51 SDK - S110 SoftDevice
|
A typical Bluetooth low energy (BLE) example is when a bonded peer configuration needs to be cached to store the bond identification, GATT Server configuration, and/or GATT Server attribute handles. This is just one example of several reasons why persistent data storage is needed.
The Persistent Storage Manager has a generic API (Persistent Storage Interface) used by SDK modules for common storage access. A generic API allows for SDK modules to be reused directly on other platforms. All modules using the Persistent Storage Manager are decoupled from accessing the nRF51822 flash directly. This allows for improved re-usability of SDK modules. For example, the Bond Manager can be used on processors other than nRF51822. This can be achieved by implementing a storage module according to the Persistent Storage Manager API for the targeted platform.
To summarize, the application interface of this module is as defined in the header and should not be altered to have zero impact on other SDK modules. However, the implementation of the interface is expected to vary based on storage solution identified for the system. Hence, pstorage.h defines the application interface, while pstorage_platform.h is use case and system specific file that can contain defines and routines needed for a specific implementation of the identified interface. The source file, pstorage.c shall implement the needed APIs. SDK examples include implementation of the interface using the SoftDevice APIs for flash access on the chip.
Multiple SDK modules and application itself may be require storing data, each module may have its own data size requirements. Therefore, this module allows registering with it with various block size and block count, each with a separate event handler to be notified of result of flash access.
Any SDK or application component that requires storing its data registers with the module using the pstorage_register, requesting at the time of registry number of blocks of storage it needs and how many such blocks. The interface is designed to be asynchronous and application is also expected to register a callback to know the result of a storage access operation. Identified storage access operations include load, store and clear. Once application is successfully registered, application is assigned a handle for all future operations needed for accessing these storage blocks. pstorage_handle_t (in the platform-specific header file) abstracts this handle.
Application does not have to remember a handle or an identifier for each of the blocks, instead it just needs to remember one identifier for all the blocks. When, reference to a specific block for flash access is required, pstorage_block_identifier_get API shall be used to get a block specific handle. Base handle and block number counting from 0 are provided as input to the API.
As mentioned earlier, an asynchronous interface is defined for storage access as storing data or clearing data can take time. However no copy of data to be stored is made by the implementation included in the SDK. Therefore, data source provided for store operation using the Store Data API, expects resident memory, meaning that the memory pointed to by data source for this API should not be reused or freed unless client is notified of completion of store operation using the asynchronous notification callback registered with the module by the client.
The storage module must be initialized before using any other API of the module.
A module that requires storage must register with the storage module in order to allocate storage blocks for data. The application must register the asynchronous event notification handler, number of blocks, and block size which should be in range of PSTORAGE_MIN_BLOCK_SIZE and PSTORAGE_MAX_BLOCK_SIZE. A reference handle is given to the application once registration is successful and is remembered by the application to reference the storage blocks.
This API provides a specific block reference to the application in allocated blocks. Allocated blocks are identified by the base block identifier provided at the time of registration. Block offset are indexed starting from zero to (number of blocks allocated - 1).
This API shall be called before a load or store operation to a specific block.
This API is used to read data from a storage block. It is permitted to read a part of the block using the offset field. The application should ensure the destination has enough memory to copy data from the storage block to the destination pointer provided in the API.
This API is used to write data to a storage block. It is permitted to write only a part of the block using the offset field. Application cannot free or reuse the memory that is the source of data until this operation is complete. The event notified using registered callback will indicate when this operation is complete. Event result indicates whether the operation was successful or not.
This API is used to update data in storage blocks. Application cannot free or reuse the memory that is the source of data until this operation is complete. The event notified using registered callback will indicate when this operation is complete. Event result indicates whether the operation was successful or not.
This API is used to clear data in storage blocks. The event notified using registered callback will indicate when this operation is complete. Event result indicates whether the operation was successful or not.
The size requested to be erased has to be within or equal the size of a block. If a size less than block size is given, the API will clear the requested number of bytes beginning at the first memory location in the block. It is not possible to request a size which spans to the next block in the module.
The Persistent Storage Manager allows application to get a count of how many storage access operations are pending with it using the pstorage_access_status_get API. This is particularly useful when you want to enter power off mode or want to enter a radio intense operation, but before doing so, want to ensure that the storage operations have been completed.
Certain use cases require complete control of the entire flash region and do not have typical storage requirements. The storage module then provisions for one application to be registered with it in the 'raw' mode. In raw mode, the application is responsible for conceptualizing the flash region as blocks and their management. Dedicated APIs, register, store, and clear, are provided to distinguish raw mode from the normal mode. Raw mode APIs have a similar signature to the normal mode.
As this is not a typical use case, and is included for a targeted few applications like the DFU, the raw mode by default is disabled and is included only if PSTORAGE_RAW_MODE_ENABLE is defined in the pstorage_platform.h header.
Additional requirements and a few limitations exist when implementing the example included. Some have already been mentioned but the following is a summarized list with more detailed information.
General:
Registration:
Store:
Update:
Clear: