Project Structure#
This section explains the application project structure and the mandatory and optional resources available in the project.
A Bluetooth Mesh project is a collection of C source and header files that is built using makefiles. The Simplicity Studio 5 installation generates build files and either generates, copies, or links all SDK or component source files, based on the selection made during project creating. After a project is created, the following directories are created:
The config directory: This directory is autogenerated and aggregates the component configuration files. Files are all headers and contain macros that are specific to each component. The UI tools used to generate the GATT database as well as the DCD for Bluetooth Mesh are in this directory.
The autogen directory: This directory aggregates the C code generated by Simplicity Studio and the SDK. It is a mix of header and source files that constitute the skeleton of the project. Silicon Labs recommends that you do not edit the files in this directory, as they will be overwritten the next time files are generated.
The gecko_sdk_3.x directory: This directory copies or links to the SDK resources. Only sources that are relevant to your project and how it is configured are copied or linked.
The GNU ARM Vxyz – Debug/Release directory: This is the build directory when the GCC compiler is used.
Application code is implemented at the root of the project in app.c/h and main.c. The following table shows the typical layout of a project:
Bluetooth Mesh Library Files#
The Bluetooth stack libraries are:
binapploader.o: Binary image of the Bluetooth AppLoader for Series 1, provides the optional Bluetooth LE Over-the-Air (OTA) functionality.
binapploader_nvm3.o: Binary image of the Bluetooth AppLoader for Series 1 with NVM3 support.
libbluetooth.a: Bluetooth stack library.
libnvm3_CMxx_gcc.a: NVM3 functionality for Bluetooth LE and Bluetooth Mesh stacks. NVM3 is the unique memory management system used for non-volatile memory. For more information how to use NVM3, see AN1135: Using Third Generation Non-Volatile Memory (NVM3) Data Storage.
libbluetooth_mesh.a: This library includes the radio driver layer and the Bluetooth LE stack, with the Bluetooth Mesh stack built on top of it.
RAIL (Radio Application Interface Layer): The Bluetooth LE and mesh stacks use RAIL to access the radio. RAIL libraries are linked to the Bluetooth Mesh stack under libbluetooth_mesh.a. RAIL has separate libraries for each device family and for single- and multi-protocol environments. RAIL libraries are provided in the Gecko Platform. For more information refer to RAIL Fundamentals and other RAIL documentation.
EMLIB and EMDRV: The Bluetooth LE and mesh stacks use EMLIB and EMDRV libraries to access EFR32 hardware. EMLIB and EMDRV peripheral libraries are provided in source code and they must be included in the project. EMLIB and EMDRV are part of the Gecko Platform. For more details on EMLIB and EMDRV, refer to the Gecko Bootloader API reference in <Simplicity Studio Gecko SDK>\platform\bootloader\documentation\Gecko_Bootloader_API_Reference\index.html, along with the documentation in their respective folders under <Simplicity Studio Gecko SDK>\platform\.
mbedTLS: The mbedTLS security library is a C library that implements cryptographic primitives, X.509 certificate manipulation and the SSL/TLS and DTLS protocols. Its small code footprint makes it suitable for embedded systems.
Among other header files generated by the SDK, the following defines the APIs for both the Bluetooth Mesh and LE stack. These files serve two purposes: first they contain the actual Bluetooth LE and mesh stack API and the commands and events for the stack, and second they provide configuration, event, and sleep management API to the Bluetooth LE and mesh stack.
sl_btmesh_api.h: This file is part of the SDK directory and defines the Bluetooth mesh API available to the user. It contains all routine definitions as well as types, structures and event definitions needed in order to write a Bluetooth Mesh application.
sl_bt_api.h: This file is part of the SDK directory and defines the API available to the user. It contains all routine definitions as well as types, structures and event definitions needed in order to write a Bluetooth LE application.
Note that an application may use both APIs if the developer wished to use both Bluetooth LE and mesh in the project.
Stack#
The Bluetooth Mesh stack initialization is autogenerated and takes place in sl_btmesh.c under the autogen directory. Sequentially, in the user application code, a system init function sl_system_init()
is called in main.c. This function is defined in the generated file sl_system_init.c. The stack is then initialized from there.
void sl_system_init(void)
{
sl_platform_init();
sl_driver_init();
sl_service_init();
sl_stack_init();
sl_internal_app_init();
}
The sl_stack_init()
function initializes the radio transmitter/receiver and makes the call to both the Bluetooth LE and mesh stack initialization functions (sl_event_handler.c).
void sl_stack_init(void)
{
sl_rail_util_pa_init();
sl_rail_util_pti_init();
sl_bt_init();
sl_btmesh_init();
}
Additionally, the default Bluetooth LE stack configuration structure and macros can be found under the config directory, in the sl_bluetooth_config.h file. The content of that file is generated by the SDK via the Bluetooth LE and mesh components. For more information on how to configure the Bluetooth Mesh stack, refer to UG472: Bluetooth® Mesh Stack and Bluetooth® Mesh Configurator User's Guide for SDK v2.x.
static sl_bt_configuration_t config = SL_BT_CONFIG_DEFAULT;
sl_status_t err = sl_bt_init_stack(&config);
This function takes a single argument: a pointer to a sl_bt_configuration_t
struct. Its purpose is to configure and initialize the Bluetooth stack with the parameters provided in the struct. More information on the sl_bt_init_stack()
routine is available in the HTML API documentation.
Node#
A device configured as a node in a Bluetooth Mesh network is initialized by the sl_btmesh_node_init()
routine. The call to that function is usually present in the Bluetooth Mesh user application state machine (switch/case statements) in the app.c file:
sl_status_t sl_btmesh_node_init();
Each node can be configured in various ways. Some nodes may support a set of models and features that other nodes are not meant to support. This is specific to the user and the network.
In order to make a model or feature functional, make sure the corresponding initialization class routine are called. For example, if a node supports the same generic server and/or client models (On/Off, Level, and so on), follow this procedure.
Make sure that the corresponding model components are installed in your project. When a component is installed, a blue check symbols appears in front of it. If the component is configurable, a Configure control (gear symbol) is available next to the component name, and as a button in the top right corner.
Make sure the models are properly added to your DCD configuration. If the model is not supported as a component, it has to be manually added to the corresponding element using the Bluetooth Mesh Configurator.
Make sure the corresponding Bluetooth Mesh classes are properly initialized.
/** @brief Table of used BGAPI classes */
static const struct sli_bgapi_class * const btmesh_class_table[] =
{
SL_BTMESH_BGAPI_CLASS(health_server),
SL_BTMESH_BGAPI_CLASS(proxy),
SL_BTMESH_BGAPI_CLASS(proxy_server),
SL_BTMESH_BGAPI_CLASS(node),
SL_BTMESH_BGAPI_CLASS(generic_server),
NULL
};
Note: This section only describes the common pitfalls that a user might encounter when setting up a node using generic client/server as an illustration. It is not an exhaustive list of steps that are necessary to have a generic On/Off or Battery client/server up and running, which would require a much longer description.
In the case of a generic On/Off server model for example, the following steps would need to be implemented on the server:
Register a generic server handler.
static void init_models(void)
{
mesh_lib_generic_server_register_handler(MESH_GENERIC_ON_OFF_SERVER_MODEL_ID,
BTMESH_GENERIC_ONOFF_SERVER_MAIN,
onoff_request,
onoff_change,
onoff_recall);
}
Populate the corresponding request/change/recall functions.
static void onoff_request(uint16_t model_id,
uint16_t element_index,
uint16_t element_index,
uint16_t client_addr,
uint16_t server_addr,
uint16_t appkey_index,
const struct mesh_generic_request *request,
uint32_t transition_ms,
uint16_t delay_ms,
uint8_t request_flags)
static void onoff_change(uint16_t model_id,
uint16_t element_index,
const struct mesh_generic_state *current,
const struct mesh_generic_state *target,
uint32_t remaining_ms)
static void onoff_recall(uint16_t model_id,
uint16_t element_index,
const struct mesh_generic_state *current,
const struct mesh_generic_state *target,
uint32_t transition_ms)
Note that this is only an example based on the generic On/Off model. It is commonly more difficult to start from scratch with generic models as it would require a very good understanding of both the Bluetooth Mesh technology and the stack.
To set up a working node configured as a light client/server model, Silicon Labs recommends using the sample application in Simplicity Studio. For more information, refer to Lighting Demonstration for SDK v6.x and Higher.
Provisioner#
To configure a device as a provisioner, first install the Provisioner component.
A provisioner must support the configuration client model. As a result the corresponding models should be added in the Bluetooth Mesh Configurator. Check that the configuration client model is part of the Bluetooth Mesh init class table, generated by the SDK, in the sl_btmesh.c file:
static const struct sli_bgapi_class * const btmesh_class_table[] =
{
…
SL_BTMESH_BGAPI_CLASS(config_client),
NULL
};
This should also now be visible in the Bluetooth Mesh Configurator user interface.
Additionally, configure the Bluetooth Mesh Stack component so that the following parameters are set to values corresponding to your network:
Maximum number of provisioned devices allowed.
Maximum number of App keys allowed for each Provisioned device.
Maximum number of Net keys allowed for each Provisioned device.
These three are required for successful provisioning in any network size, and may be enough for a very small network consisting of one or two nodes. In more complicated networks, provisioner configuration depends on many other parameters. For more information on Bluetooth Mesh stack parameters, refer to UG472: Bluetooth® Mesh Stack and Bluetooth® Mesh Configurator User's Guide for SDK v2.x.
The following table shows an example. Note that the parameters are set to 4 as an example, not as a recommendation.
The Provisioner is initialized using the following routine. The call to that function is usually present in the Bluetooth Mesh user application state machine (switch/case statement) in the app.c file:
sl_status_t sl_btmesh_prov_init();
No Bluetooth Mesh API routine can be called before this one. Additionally, the node-initializing routine sl_btmesh_node_init()
must not be called on a provisioner.
GATT Database#
The GATT (Generic Attribute Profile) database is a standardized way of describing a Bluetooth device’s profiles, services, and characteristics. With the Silicon Labs Bluetooth stack, the GATT definitions are either directly edited in the Bluetooth GATT Configurator in Simplicity Studio or are written in XML. For more information on how to create GATT databases and the syntax, refer to the Blue Gecko Bluetooth Smart Profile Toolkit Developer's Guide.
gatt_db.c and gatt_db.h
The gatt_db.c file defines the GATT database structure and content. It is autogenerated by the Bluetooth GATT configurator. gatt_db.h includes this database and the handles of local characteristics and services. Type definitions of GATT are automatically included from gatt_db_def.h to gatt_db.h. In the case of Bluetooth Mesh, only the Bluetooth Mesh services are relevant:
Mesh Proxy service (UUID 0x1828): The Bluetooth Mesh Proxy Service is used to enable a server to send and receive Proxy PDUs with a proxy client .
Mesh Proxy Data In (UUID 0x2ADD)
Mesh Proxy Data Out (UUID 0x2ADE)
Mesh Provisioning service (UUID 0x1827): The Bluetooth Mesh Provisioning Service allows a Provisioning Client to provision a Provisioning server to allow it to participate in the Bluetooth Mesh network.
Mesh Provisioning Data In (UUID 0x2ADB)
Mesh Provisioning Data Out (UUID 0x2ADC)
Those services and characteristics can be thought of as duplex communication channels for provisioning and proxy PDUs. The "data in" and "out" characteristics are then the Tx and Rx channel, respectively.
A device may support the Bluetooth Mesh Provisioning Service or the Mesh Proxy Service or both. If both are supported, only one of these services should be exposed in the GATT database at a time.
Bluetooth Mesh Device Composition Data#
The device composition data, or DCD, is a set of data indicating which features are supported, how many elements are present on a node with their description, and a set of identifiers defining the model layout across the elements of the node.
The Composition Data state contains information about a node, the elements it includes, and the supported models. The Composition Data is composed of a number of pages of information. Composition Data Page 0 is mandatory. All other pages are optional. All Composition Data Pages not defined in this specification are reserved for future use. The size of the state must not exceed the maximum useful access payload size.
The following code snippet illustrate how this is defined for the Bluetooth Mesh stack:
const uint8_t __mesh_dcd[] = {
U16TOA(0x02ff), /* Company ID */
U16TOA(0xf0b0), /* Product ID */
U16TOA(0x1234), /* Version Number */
U16TOA(SL_BTMESH_CONFIG_RPL_SIZE), /* Capacity of Replay Protection List */
U16TOA(SL_BTMESH_FEATURE_BITMASK), /* Features Bitmask */
/* Main */
U16TOA(0x0000), /* Location */
0x04, /* Number of SIG Models = 4 */
0x00, /* Number of Vendor Models = 0 */
/* SIG Models */
U16TOA(0x0000), /* Configuration Server */
U16TOA(0x0002), /* Health Server */
U16TOA(0x0001), /* Configuration Client */
U16TOA(0x0003), /* Health Client */
};
const uint8_t *__mesh_dcd_ptr = __mesh_dcd;
The structure called __mesh_dcd is passed via a pointer to the C Bluetooth Mesh library.
After provisioning, the Provisioner typically retrieves the DCD of the newly provisioned node in order to determine the node’s features and functionalities so that it can be configured to operate in the network.
RTOS Support#
Typical Bluetooth Mesh examples have been running on bare metal. RTOS support has been available for the Bluetooth Mesh start-ing from Simplicity SDK 2024.12. There are selected examples also running on FreeRTOS and Micrium OS.
Note that multiprotocol applications are not supported by the Bluetooth Mesh protocol.