Mesh configuration is a mesh submodule designed to abstract and simplify persistent key-value storage. It provides a high-level API with swappable storage backends that can be used to store mesh and application state.
Table of contents
The mesh config module organizes data in files, where each file has a set of records. A mesh config entry is uniquely identified by a file/record pair, and it can represent any immutable structure with a predefined size.
An entry is owned by a state owner module in the user-space. The state owner holds the entry structure and is responsible for sanitizing and storing the live representation of the value. It provides access to the live value through a setter
/getter
/deleter
interface.
There is no requirement that the state owner must keep the live value in RAM, but it must be able to produce the value on the mesh config module's request atomically. The live value should never be altered outside the state owner's setter
callback, and the getter
callback should always return the value set in the previous setter
callback. The state owner can specify a default value to use if the entry has not been set. If no default value is defined, attempts to read the value will result in an error until the value has been set or loaded from persistent storage.
The state owner is notified of deleted entries through the deleter
callback. It cannot interfere with the deletion, only observe it.
The state owner may choose to reject values it considers invalid by returning an error code from its setter
callback.
In some cases, other modules need to passively listen to changes to a specific entry. For instance, the internal mesh Heartbeat module needs to know when the Proxy feature is enabled, as this should trigger the Heartbeat module to publish a message. This pattern is a common source of unwanted coupling between modules, and to reduce this, the mesh config module provides a Mesh config listener interface for registering passive change listeners without needing to involve the state owner. Any module can register a listener for any entry and is then notified of any state changes after they have been sanitized by the state owner.
setter
/getter
/deleter
or listener callbacks only by means of the SoftDevice NVIC APIs.The mesh config module is designed to work on top of any key-value storage backend. In the initial version of mesh config, the only supported backend is the Flash Manager, but support for other backends is planned for future releases.
The mesh config backend API is considered internal and should never be called directly.
All user interaction with the mesh config module should go through the mesh_config API. Manipulating the live value directly causes the mesh config module to fall out of sync.
Note that the state owner's setter
callback is called before the value is stored persistently. The entry should only be considered safely stored after the mesh config module emits an NRF_MESH_EVT_CONFIG_STABLE event. The user can also call mesh_config_is_busy to determine whether the live values are in sync with the persistent storage.
The mesh config module is used internally in the mesh to store options (through the Mesh options API API) as well as runtime state. The mesh reserves the following file IDs:
File ID | Owner | Purpose |
---|---|---|
0x0000 | net_state | Network runtime state, such as sequence number and IV index. |
0x0001 | dsm | Device State manager state, such as keys and addresses. |
0x0002 | access | Access state, such as model key bindings. |
0x0003 | mesh_opt | Mesh runtime options. |
0x0004 - 0x000F | - | Reserved for future use. |
The application may use the mesh config module to store their own state. To do this, first declare a mesh config file with a unique file ID using the MESH_CONFIG_FILE macro:
The file will automatically be registered in mesh config. The CONTINUOUS
storage strategy will ensure that the file's entries will be stored in persistent memory as soon as they are set.
To create entries, invoke the Mesh config entry macro with a setter and a getter function. This example creates an entry with record number 0x0001
in the m_app_file
created above. The value is a uint32_t, configured to only accept values below 10000, with the default value 5000.
The config entry is registered automatically, and the user may set and get the value: