In the version 2.3.2 of our Bluetooth Mesh Mobile ADK we have introduced a new feature which allows the User to reduce the amount of separate GATT connections necessary for provisioning of the Node with configuration. Enabling it should not only improve the performance of the operation but also increase reliability and success rates during those procedures. That's because both the provisioning process and the initial proxy session with configuration of the Node is going to take place under a single connection.
The main aim of this article is to give you a simple instruction on how to implement all the necessary changes into the application which are required to reduce number of GATT connections needed.
2. Android
2.1 BluetoothConnectableDevice modifications
First of all, for the new solution to work it is necessary to make the following changes to the BluetoothConnectableDevice class.
Warning: The following modifications have been already applied in the Bluetooth Mesh by Silicon Labs demo application released with ADK 2.3.2 and the full class implementation can be found in the attachment to this article.
var bluetoothGatt: BluetoothGatt? = null
...
override fun hasService(service: UUID?): Boolean {
return if (bluetoothGatt?.services?.isNotEmpty() == true) {
bluetoothGatt!!.getService(service) != null
} else {
scanResult.scanRecord?.serviceUuids?.contains(ParcelUuid(service))
?: false
}
}
var bluetoothGatt: BluetoothGatt? = null
var refreshGattServicesCallback: RefreshGattServicesCallback? = null
lateinit var bluetoothGattCallback: BluetoothGattCallback
...
bluetoothGattCallback = object : BluetoothGattCallback() {
override fun onServicesDiscovered(gatt: BluetoothGatt, status: Int) {
...
if (status == BluetoothGatt.GATT_SUCCESS) {
refreshGattServicesCallback?.onSuccess()
} else {
refreshGattServicesCallback?.onFail()
}
refreshGattServicesCallback = null
...
}
}
...
override fun refreshGattServices(refreshGattServicesCallback: RefreshGattServicesCallback) {
if (refreshDeviceCache()) {
this.refreshGattServicesCallback = refreshGattServicesCallback
bluetoothGatt!!.discoverServices(bluetoothGatt)
} else {
refreshGattServicesCallback.onFail()
}
}
...
fun refreshDeviceCache(): Boolean {
var result = false
try {
val refreshMethod: Method = bluetoothGatt!!.javaClass.getMethod("refresh")
result = refreshMethod.invoke(bluetoothGatt!!, *arrayOfNulls(0)) as? Boolean ?: false
} catch (exception: Exception) {
}
return result
}
2.2 Provision with configuration under one connection
Having successfully incorporated the code attached above, the Developer may proceed to make changes that will make the provisioning and configuration to happen at the same GATT connection. It would require a change in the execution order which is presented below.
2.2.1 Execution modification
The User of the ADK needs to make sure that he/she creates a ProvisionerConfiguration object, sets the isUsingOneGattConnection property to true and then adds that object as an argument for the provision method.
Note: It is also possible to add other initial configuration to that object such as setting the Node as Proxy or Relay.
val provisionerConnection: ProvisionerConnection
val provisioningCallback: ProvisioningCallback
...
val provisionerConfiguration = ProvisionerConfiguration().apply {
isUsingOneGattConnection = true
}
provisionerConnection.provision(provisionerConfiguration, null, provisioningCallback)
3. iOS
On the iOS the situation looks very similar to the Android. The appropriate steps have been covered below
3.1 SBMConnectableDevice modifications
Firstly, it is necessary to make modifications to class implementing SBMConnectableDevice protocol by implementation for new method and calling SBMConnectableDeviceDelegate.didModifyServices(, for:) method of delegate object.
Warning: Those changes have been already applied in the Bluetooth Mesh by Silicon Labs demo application released with ADK 2.3.2 and the full class implementation can be found in the attachment to this article.
SBMConnectableDevice:
let peripheral: CBPeripheral
var delegate: SBMConnectableDeviceDelegate?// delegate is set by BluetoothMesh framework, do NOT override it
var callback: SBMConnectableDeviceOperationCallback?
// (...)
// SBMConnectableDevice
func unsubscribe(fromService service: String, characteristic: String, completion: @escaping SBMConnectableDeviceOperationCallback) {
let cbCharacteristic = peripheral.services?.first { $0.uuid.uuidString == service }?.characteristics?.first { $0.uuid.uuidString == characteristic}
if cbCharacteristic != nil {
callback = completion
peripheral.setNotifyValue(false, for: cbCharacteristic!)
} else {
completion(self, CBUUID(string: service).data, CBUUID(string: characteristic).data, false)
}
}
// CBCentralManagerDelegate
func peripheral(_ peripheral: CBPeripheral, didUpdateValueFor characteristic: CBCharacteristic, error: Error?) {
self.delegate?.didUpdate(characteristic.value, forDevice: self, service: characteristic.service.uuid.data, characteristic: characteristic.uuid.data)
}
// CBCentralManagerDelegate
func peripheral(_ peripheral: CBPeripheral, didUpdateNotificationStateFor characteristic: CBCharacteristic, error: Error?) {
callback(self, characteristic.service.uuid.data, characteristic.uuid.data, error == nil && !characteristic.isNotifying)
}
3.2 Provision with configuration under one connection
Once the Developer has successfully incorporated all the above changes, he or she can proceed to modify the execution sequence which is required to enable the usage of One Gatt connection.
3.2.1 Execution modification
The User of the ADK needs to make sure that he/she creates a ProvisionerConfiguration object, sets the useOneGattConnection property to true and then adds that object as an argument for the provision method.
Note: It is also possible to add other initial configuration to that object such as setting the Node as Proxy or Relay.
let connectableDevice: SBMConnectableDevice
let subnet: SBMSubnet
...
let provisionerConnection = SBMProvisionerConnection(for: connectableDevice, subnet: subnet)
let provisionerConfiguration = SBMProvisionerConfiguration(proxyEnabled: true, nodeIdentityEnabled: true, useOneGattConnection: true, keepOneConnection: false)
...
provisionerConnection.provision(withConfiguration: provisionerConfiguration, parameters: nil, retryCount: 3) { (connection, node, error) in
//Handle result of provisioning
}
4. Keeping connection after the provisioning
Apart from the feature described above, in the 2.3.2 version of the ADK we have also introduced a possibility of keeping the Proxy connection after the successful provisioning. Enabling that might also lead to improvements in performance and reliability of the application.
The following points describe the necessary actions which need to be implemented in the application for each platform.
4.1 Android
4.1.1 Execution modification
Firstly, it is necessary to set the keepingProxyConnection to true in the ProvisionerConfiguration object and add it as an argument for the provision method.
Note: It is also possible to add other initial configuration to that object such as setting the Node as Proxy or Relay.
val provisionerConnection: ProvisionerConnection
val provisioningCallback: ProvisioningCallback
...
val provisionerConfiguration = ProvisionerConfiguration().apply {
keepingProxyConnection = true
}
provisionerConnection.provision(provisionerConfiguration, null, provisioningCallback)
4.1.2 Obtaining active Proxy Connection object
When the provisioning session finishes, it is going to be necessary to obtain the still active ProxyConnection to use it for other operations depending on the Developer requirements. It can be done by implementing a following solution into the provisioning callback.
It is important to highlight the importance of replacing the error callback for handling unexpected connection issues such as sudden disconnects. Please make sure you carefully analyse the following code example.
val provisionerConnection: ProvisionerConnection
val provisioningCallback: ProvisioningCallback
val proxyConnection: ProxyConnection? = null
val errorCallback: ProxyConnection.ErrorCallback
...
provisioningCallback = object: ProvisioningCallback{
override fun success(device: ConnectableDevice?, subnet: Subnet?, node: Node?) {
proxyConnection = provisionerConnection.getProxyConnection()
proxyConnection!!.replaceErrorCallback(errorCallback)
}
override fun error(device: ConnectableDevice?, subnet: Subnet?, error: ErrorType?) {
}
})
4.2 iOS
4.2.1 Execution modification
It is important to notice that if one wishes to close proxy connection after configuration, init method with keepProxyConnection set to false needs to be explicitly used.
let oldProvisionerConfiguration = SBMProvisionerConfiguration(proxyEnabled: true, nodeIdentityEnabled: true)
let newProvisionerConfiguration = SBMProvisionerConfiguration(proxyEnabled: true, nodeIdentityEnabled: true, useOneGattConnection: true, keepProxyConnection: true)
//both oldProvisionerConfiguration and newProvisionerConfiguration can be used to keep proxy connection open
provisionerConnection.provision(withConfiguration: oldProvisionerConfiguration, parameters: nil, retryCount: 3) { (connection, node, error) in
//Handle result of provisioning
}
4.2.2 Obtaining active Proxy Connection object
When the provisioning session finishes, it is going to be necessary to obtain the still active ProxyConnection to use it for other operations depending on the Developer requirements. It can be done by implementing a following solution into the provisioning callback.
It is important to highlight the importance of replacing the error callback for handling unexpected connection issues such as sudden disconnects. Please make sure you carefully analyse the following code example.
let errorCallback: (SBMConnectableDevice, Error) -> () = { device, error in
//handle error
}
let provisionerConfiguration = SBMProvisionerConfiguration(proxyEnabled: true, nodeIdentityEnabled: true, useOneGattConnection: true, keepProxyConnection: true)
var proxyConnetion: SBMProxyConnection? = nil
provisionerConnection.provision(withConfiguration: provisionerConfiguration, parameters: nil, retryCount: 3) { (connection, node, error) in
proxyConnection = connection.proxyConnection
proxyConnection.replaceErrorCallback(errorCallback)
}
5. Conclusion
To sum up, the above guidelines should help the Users to understand how to enable the new described features in their application. Certainly it can bring significant improvements to the performance of their applications and increase reliability as well.
In case of any problems or questions regarding this document you can create a support ticket at our web page or comment below.
Adding Customized Advertising Sets to Bluetooth Mesh Applications
Advertising Sets
Advertising Sets are defined in Section 4.4.2.10, Part B, Vol 6, Bluetooth Specification Version 5.2. With advertising sets supported, Bluetooth stack actually provides a way to interleave multiple advertising events. Each advertising set has its own parameters, payload, timing etc. and is independed to the other advertising sets. For example, if you want to send a connectable advertisement and a non-connectable beacon simultaneously, you don't necessarily need to send the connectable advertisement once then modify the content and parameters to send the non-connectable beacon repeatedly, this will easy to achieve by using 2 advertising sets.
Advertising Sets Used by Bluetooth Mesh Stack
When the Bluetooth stack initializes, user application needs to configure the number of the maximum advertising sets used by both the stack and application. Other than the regular BLE examples, which typically don't use any advertising set, the Bluetooth Mesh stack uses some advertising sets to send data. You can find below inline description of the advertising sets used by Bluetooth Mesh stack in the main.c file of all Bluetooth Mesh examples.
/// Bluetooth advertisement set configuration
///
/// At minimum the following is required:
/// * One advertisement set for Bluetooth LE stack (handle number 0)
/// * One advertisement set for Mesh data (handle number 1)
/// * One advertisement set for Mesh unprovisioned beacons (handle number 2)
/// * One advertisement set for Mesh unprovisioned URI (handle number 3)
/// * N advertisement sets for Mesh GATT service advertisements
/// (one for each network key, handle numbers 4 .. N+3)
///
#define MAX_ADVERTISERS (4 + MESH_CFG_MAX_NETKEYS)
Here is a more verbose explanation for each set:
Advertising Set 0 - Reserved for Application
This advertising set is reserved for regular BLE advertising. It's created when the stack initializes by default and ready to be used by the application. For example, you can call the API gecko_cmd_le_gap_start_advertising with handle 0 to start advertising with this advertising set. This is NOT used by the Bluetooth Mesh stack, but has to be counted into the maximum number of the advertising sets.
Advertising Set 1 - Bluetooth Mesh Data
This advertising set is used for Bluetooth Mesh data traffic, which is the traffic happens on the Advertising bearer (section 3.3.1 of Mesh Profile v1.0.1) and PB-ADV (section 5.2.1 of Mesh Profile v1.0.1) . The stack is in control of the advertising data and the advertising parameters for this set, and the user application MUST NOT override the parameters or use this set for any other purpose.
Advertising Set 2 - Bluetooth Mesh Unprovisioned Device Beacon Without URI
This advertising set is used for sending the Unprovisioned Device Beacon (section 3.9.2 of Mesh Profile v1.0.1) when devices are in unprovisioned state. The Bluetooth Mesh stack will construct the advertising payload according to the definition of the Unprovisioned Device beacon format. User application shall not modify the advertising payload to this advertising set. What the user application can control in this case is the cadence for sending the Unprovisioned Device beacon, call the API - gecko_cmd_le_gap_set_advertise_timing with handle 2 BEFORE starting the Unprovisioned Device beacon.
Advertising Set 3 - Bluetooth Mesh Unprovisioned Device Beacon With URI
This advertising set is also used for sending the Unprovisioned Device Beacon (section 3.9.2 of Mesh Profile v1.0.1) when devices are in unprovisioned state. The only difference is there are 4-byte of URI hash appended to the data payload. See below lines from the Mesh Profile.
Along with the Unprovisioned Device beacon, the device may also advertise a separate non-connectable advertising packet with a Uniform Resource Identifier (URI) data type (as defined in [7]) that points to outof-band (OOB) information such as a public key. To allow the association of the advertised URI with the Unprovisioned Device beacon, the beacon may contain an optional 4-octet URI Hash field.
The latest Bluetooth Mesh stack doesn't support sending Unprovisioned Device beacon with URI, so this is reserved for future use.
Advertising Set 4 to N - Bluetooth Mesh Proxy Service Advertising
The usage of this advertising set is device state dependent.
If a device is in unprovisioned state, this advertising set will be used to advertise the Mesh Provisioning Service (section 7.1 of Mesh Profile v1.0.1) if the application call gecko_cmd_mesh_node_start_unprov_beaconing with PB-GATT bit set in the bearer parameter.
If a device is in provisioned state and supports Proxy feature, it shall start advertising the Mesh Proxy Service (section 7.2 of Mesh Profile v1.0.1) if the given situations are met. Alternatively, user application can start the advertising munally whenever the device is expected to connect to a proxy client.
Because a provisioned device could belong to multiple subnets, it could advertise multiple Mesh Proxy Service advertisements simultaneously. The maximum network key number that the device supports decides the maximum number of subnets the device can be in, so N is calculated to be 4 + the maximum network key on the device.
Adding Customized Advertising Sets to Bluetooth Mesh Applications
This example shows how to add your custom BLE advertising into a Bluetooth Mesh project.
Step 1: Increase the MAX_ADVERTISERS macro by the number of your custom advertising sets.
The .bluetooth.max_advertisers parameter in the gecko_configuration_t structure decides the maximum number of the advertising sets in the application. In all examples of the Bluetooth Mesh SDK, this value is feed by MAX_ADVERTISERS macro. So, modify the MAX_ADVERTISERS macro like below to add your own advertising sets.
/* Number of custom Advertising Sets */
#define MY_ADVERTISERS 2
#define MAX_ADVERTISERS (4 + MESH_CFG_MAX_NETKEYS + MY_ADVERTISERS)
/*
* Advertising Set ID from the offset. E.g. to get the first custom advertising
* set ID, put n as 1 like this - MY_ADVERTISING_SET_ID(1)
*/
#define MY_ADVERTISING_SET_ID(n) (4 + MESH_CFG_MAX_NETKEYS + n)
Step 2: Configure the advertising sets if needed.
You can use the advertising configuration related APIs (gecko_cmd_le_gap_set_advertise_xxx) to configure the advertising sets specifically by the advertising set ID (handle), as well as the gecko_cmd_le_gap_bt5_set_adv_data to set the advertising payload. For more details about the advertising parameters and data payload format, you can check Bluetooth Advertising Data Basics. For constructing the advertising data in a much easier way, you can use the code example - Advertisement or Scan Response Constructor.
Step 3: Start the advertising sets
This is the final step to send your own advertisement, call gecko_cmd_le_gap_start_advertising with advertising set ID (handle) specified to start advertising the specific advertisement.
There is basically no difference compared to regular (non-mesh) BLE case. The key thing to take into account here is configuring the number of advertising sets and selecting the right advertising handle to use.
This self provisioning and configuration example provides a function to provision and configure the device itself. This example doesn't perform the provisioning procedure and instead writes provisioning data directly into the persistent storage and configures the models on the device.
The goal of this example is to provide the function for the users who want to run their devices directly in a Bluetooth Mesh network without using a provisioner. This example is mainly used for development and testing purposes and is not recommended to run on final products.
This article describes how to integrate the example into a Bluetooth Mesh project, how to configure the function and how the self provisioning and configuration work.
Project integration
This article assumes app.c is the file that will call the self provisioning function. In your project, you may make the function be called in some conditions, e.g. when a button is held down for seconds. The example uses the DCD configuration from your project so the auto-generated files dcd.c and mesh_app_memory_config.h should exist in your project folder.
The code example consists of two source files: selfprov.c and selfprov.h. Copy the two files to your Bluetooth Mesh project and make the following changes.
Add gecko_bgapi_class_mesh_test_init(); to the class initialization function gecko_bgapi_classes_init() in app.c.
Add #include "selfprov.h" in app.c.
Add the function call self_provisioning(); in app.c at a point after the node has been initialized. For example, in the event handler of the gecko_evt_mesh_node_initialized_id event.
The example performs self provisioning and configuration only when the network and application key counts are 0. You may need to call cmd_flash_ps_erase_all to delete all security keys and then reset the device.
Self provisioning configuration
The example doesn't declare any global variables for data to be changed at runtime. The provisioning and model configuration data are therefore defined at compilation time in selfprov.h and are used by the functions in selfprov.c to provision and configure the device.
The example gets the model IDs configured for the device from dcd.c which is generated from the Bluetooth Mesh Configurator. The example binds all of these model IDs to the application key. The example then recoginzes server and client models from these model IDs and applies server and client settings respectively. The server and client settings are publication parameters and subscription addresses. The same application key is used for all model configuration.
Unicast address
A unicast address is required to provision a device. The self provisioning function generates a unicast address by performing XOR operations on the device's Bluetooth address. Bit 0, 1, 2, and 3 are reserved for secondary element addresses and bit 14 is reserved for manual addresses. This gives 1,023 automatically allocated addresses in the range of 0x0010 and 0x3FF0 with the 4 LSbs and the 2 MSbs set to 0.
If the address 0x0000 or a duplicate address is generated, you need to allocate manually an address to the device and in this case the function doesn't run the automatic address allocation. The addresses you can allocate manually would be in the range of 0x4000 and 0x7FF0 with the 4 LSbs set to 0.
#define UNICAST_ADDRESS 0x0000
Set UNICAST_ADDRESS to 0x0000 to run the automatic unicast address allocation. Alternatively, you can set any value between 0x0001 and 0x7FFF inclusively to allocate a unicast address manually. It is recommended to separate manual and automatic address ranges and the definition UADDR_RSVD_BITS is usded for this purpose.
#define UADDR_ELEM_BITS 4
The number of the LSbs reserved for secondary element addresses. If the address 0x0010 is allocated to a node, the address of the primary element (element 0) is 0x0010 and the addresses of secondary elements are 0x0011 (element 1), 0x0012 (element 2) and so on, which are allocated by the Bluetooth Mesh stack. The default value 4 gives maximum 16 elements. Set UADDR_ELEM_BITS to a number N to allow the maximum (2 to the power of N) elements that any node can have.
#define UADDR_RSVD_BITS 1
The number of bits from bit 14 to LSb reserved for manual addresses in the range separate from the automatic address range. The default value 1 means you can set UNICAST_ADDRESS to any of the addresses with bit 14 set to 1, which are in the range of 0x4000 and 0x7FFF. You can set it to 0 if you want and you will need to manage the addresses that are unique among the automatically allocated addresses.
Security keys
The self provisioning function writes the security keys netkey, devkey and appkey directly into the persistent storage on the device. The key length is 128 bits, i.e. 16 bytes.
The security keys NETWORK_KEY and DEVICE_KEY are required to provision a device and the security key APPLICATION_KEY is required to configure the node. The self provisioning function uses the application key to bind all models configured on the device and to set publication parameters.
Server and client models
The self provisioning function reads model IDs from DCD and splits them into two groups: server and client. The function sets the server publication parameters and subscription addresses to all server models and the client publication parameters and subscription addresses to all client models.
The models Configuration Server, Configuration Client, Health Server, Health Client and Setup servers are excluded.
The self provisioning function determines whether a model ID is a server model or a client model by comparing it with PUB_SUB_SERVER_MODELS and PUB_SUB_CLIENT_MODELS. The function reads all model IDs from DCD and puts server model IDs to a server model buffer and client model IDs to a client model buffer, or drops the model IDs that don't exist in these definitions. You can remove any model ID from these definitions if you don't want the device running the model to send and receive messages.
#define MAX_PUB_SUB_MODELS 20
The size of the buffers used to store server and client model IDs. It is usually the maximum length of PUB_SUB_SERVER_MODELS and PUB_SUB_CLIENT_MODELS.
Publication address and subscription list
The server publication address and subscription list are set to all server models and the client publication address and subscription list are set to all client models. Therefore, messages sent from the nodes running a server model will go to the nodes running the corresponding client model, and vice versa.
To publish messages to a new group, you can add a new group address to the client subscription list and set the server publication address to the new group address, and vice versa. You can also configure the node not to send messages by setting the publication address to 0x0000, or not to receive messages by clearing the subscription list.
For the nodes running server models to send messages to the nodes running client models, set GRP_SVR_PUB_ADDRESS to an address in the list of GRP_CLI_SUB_ADDRESSES. For the nodes running client models to send messages to the nodes running server models, set GRP_CLI_PUB_ADDRESS to an address in the list of GRP_SVR_SUB_ADDRESSES.
On December 20, 2020, EN/IEC 60950-1 safety standard will be withdrawn and fully replaced by EN/IEC 62368-1, requiring manufacturers to comply with the new standard for the presumption of conformity. Furthermore, as of February 6, 2020, RF regulatory standard EN 300 328 V2.2.2 has replaced EN 300 328 V2.1.1 with a transition period ending on August 6, 2021. After the transitions, products on the market must comply with the updated standards.
Silicon Laboratories is committed to perform any required delta testing with the affected wireless modules (except for certain parts reaching EoL) according to the new standards and release the updated test reports and declarations of conformity (DoCs) before the end of the listed transition periods.
The parts planned to be tested are listed in the table below:
The Node Reset Procedure is the way to remove a node from a network, which is like the node leaves the network actively. It's different from blacklisting which is the way to move all un-blacklisted nodes to the new network, so the node is left passively. Below table gives a simple comparison between these 2 methods to remove node(s) from network.
Node Reset
Notes
Blacklisting
Notes
Node status after the procedure
Unprovisioned
Same as before
Stay provisioned
Network Status
Unchanged
Network key changed
Application key may change
Involved in the procedure
Yes
node should be present and function normally in the procedure
No
Node state doesn't matter
The node reset procedure includes below 2 messages:
Config Node Reset - sent by the provisioner to ask the node to remove itself from the network.
Config Node Reset Status - sent by the node to acknowledge the node has received the Config Node Reset message.
In general, how the node reset procedure looks like in the ideal situation is like figure 1 shows.
Figure 1
Given that the wireless communication can be affected by many environment factors, especially the packet collision, which results in certain packet cannot be received by the receiving device. Typically, the wireless protocols have a proper way to know the situation happens, then they can just retry sending the missing packets. However, for this procedure, because the node needs to remove itself from the network after sending the Config Node Reset Status message, it won't be able to communicate with the provisioner any more. Let's imagine what happens if either of those 2 packets is missing by the target device.
Figure 2 shows that if the node misses some of the Config Node Reset message.
Figure 2
From the figure you can see, the provisioner sends Config Node Reset then waits for the acknowledgement - the Config Node Reset Status message from the Node, whereas the node doesn't receive the Config Node Reset message successfully, which means the node will never send the acknowledgement. There is a predefined waiting time on the provisioner side, so the provisioner will get the timeout event after the predefined time, then it can retry sending the Config Node Reset message until the acknowledgement is received or it fails for a certain amount of times. In this case, only the user experience will be affected since the time for the procedure increases dramatically becauses of the timeouts.
Figure 3 shows that if the provisioner misses the Config Node Reset Status message.
Figure 3
From the figure you can see, the node receives the Config Node Reset message from the provisioner and acknowledges with the Config Node Reset Status message, then removes itself from the network. However, the message is missed by the provisioner, which means the real node status is uncertain to the provisioner since it doesn't know if the Config Node Reset message is received by the node or not. In this case, the situation is not recoverable, consider:
No matter how many times the provisioner retries sending the Config Node Reset message, the node will not be able receive anymore because it has already removed itself from the network.
The node will also never be able to send the Config Node Reset Status message, the reason is the same as above.
Actually, the figure 3 is still idealised. In practice, the provisioner won't know the status of the node before it successfully receives the Config Node Reset Status. So, this brings some problems:
It's not easy for the provisioner to decide when to stop retrying sending the Config Node Reset message. Apparently, it would be a deadloop for the provisioner to send Config Node Reset forever if the situation in figure 3 happens without specifying the times.
The real status of the node is unknown to the provisioner during this procedure, it could either be 1> the node doesn't receive any of the Config Node Reset messages, the node stay provisioned, or 2> the Config Node Reset Status missed by the provisioner. In both cases, there is no solid indication that the provisioner is OK to remove the node from device database. Below is a table to the cases mentioned above.
Node Removed from Device Database
Node Not Removed from Device Database
Node Reset
Normal
Abnormal 2
Node Not Reset
Abnormal 1
Need to Continue the Removal Procedure
Conclusion
All in all, the conclusion is The Node Reset Procedure is UNRELIABLE without any other means of determining the real status of the node.
Ideas
From the above description, the most important thing for this procedure to finish properly is that the provisioner receiving the Config Node Reset Status message successfully. So, to improve the performance, you could try to increase the network retransmission. This can be done temporarily before the node reset procedure, e.g. normally, the network retransmission count is disabled or configured to be a low value. When the provisioner wants to remove the node, it could firstly configure a high network retransmission to the node then start the node reset procedure. See figure 4.
Figure 4
But this is just a way to improve the performance, it doesn't make the procedure to be reliable. Application developers should take this into account if it's desired to make it reliable. For example, based on the assumption that the unprovisioned device will always send unprovisioned device beacon, the provisioner can scan for the unprovisioned device beacon to know if the device is already in unprovisioned state before removes the node from database.
KBA_BT_0515: Bluetooth Mesh Mobile - Import/Export Functionalities Concepts
1. Introduction
The Import and Export feature can be regarded as one of the most important ones in the Bluetooth Mesh Silicon Laboratories’ ADK. Introduced in the 2.2.0 release can allow the User to implement completely new approach to control the Mesh Network. One of the use cases examples we suggest, and which is enabled by this functionality, is active usage of multiple data bases or in other words multiple different Mesh networks in the same application. Currently as stated in the AN1200 document the library does not natively support it but it can be worked around by using the Import and Export. Surely there are many other scenarios to be invented by the Users, and knowing the importance of the topic, we have tried to sum up the key steps that need to be followed, in the Document below.
2. Export
First of all, it is necessary for the Developer to understand how and what information exactly need to be exported into an external file to successfully move the Mesh Network structure between the devices. The Silabs’ ADK does not specify what type of file it needs to be, it is up to Developer to choose a specific format for storing the data base. Our API only provides appropriate methods which can be used to extract the necessary information from the Mesh structure which main components are Network, Subnet, Group, Node, Element and Model. As a help for the Developers to get started, we have also prepared a sample implementation of the Export which you can use as a reference or a starting point for your own, in which we have decided to use a JSON string file as a container for our database.
Warning: Due to complexity of the dependencies between the different objects in the Mesh Structure we were not able to gather all the necessary API for export in this document. Below you will find just examples of the methods which can be used to extract the data. The rest of the necessary functions can be found in the class documentation which was attached to the BLE mesh package in the Simplicity Studio directory.
Also, we would highly recommend, after the successful export procedure, to keep the file protected by implementing an appropriate encryption method according to the Customer's requirements.
2.1 Network
Firstly, it would be necessary to get access to the Network type objects available in the data base. It would allow the developer to extract all the necessary information stored inside and will allow you to get the lists of existing Subnets, Provisioners and Scenes in the Mesh Network. Following that, it is going to be needed to extract the data stored in each of the objects of these three types and then the lower layer as well (SubnetSecurity, NetKey, AddressRange). The API samples were listed below for both platforms.
2.1.1. iOS
SBMBluetoothMesh:
networks – use SBMBluetoothMesh.networks
SBMNetwork:
version – use SBMNetwork.version
uuid – use SBMNetwork.uuid
name – use SBMNetwork.name
timestamp – use SBMNetwork.timestamp
subnets – use SBMNetwork.subnets
provisioners – use SBMNetwork.provisioners
scenes – use SBMNetwork.scenes
SBMSubnet
name – use SBMSubnet.name
netKey – use SBMSubnet.netKey
subnetSecurity – use SBMSubnet.subnetSecurity
groups – use SBMSubnet.groups
nodes – use SBMSubnet.nodes
SBMProvisioner
provisionerName – use SBMProvisioner.provisionerName
uuid – use SBMProvisioner.uuid
allocatedUnicastRange – use SBMProvisioner.allocatedUnicastRange
allocatedGroupRange – use SBMProvisioner.allocatedGroupRange
allocatedSceneRange – use SBMProvisioner.allocatedSceneRange
SBMScene
name – use SBMScene.name
number – use SBMScene.number
nodes – use SBMScene.nodes
2.1.2 Android
Bluetoothmesh:
networks – use BluetoothMesh.getNetworks()
Network:
version – use Network.getVersion()
uuid – use Network.getUuid()
name – use Network.getName()
timestamp – use Network.getTimestamp()
subnets – use Network.getSubnets()
provisioners – use Network.getProvisioners()
scenes – use Network.getScenes()
Subnet
name – use Subnet.getName()
netKey – use Subnet.getNetKey()
subnetSecurity – use Subnet.getSubnetSecurity()
groups – use Subnet.getGroups()
nodes – use Subnet.getNodes()
Provisioner
provisionerName – use Provisioner.getName()
uuid – use Provisioner.getUuid()
allocatedUnicastRange – use Provisioner.getAllocatedUnicastRange()
allocatedGroupRange – use Provisioner.getAllocatedGroupRange()
allocatedSceneRange – use Provisioner.getAllocatedSceneRange()
Scene
name – use Scene.getName()
number – use Scene.getNumber()
nodes – use Scene.getNodes()
2.2 Group
Having extracted a list of Group objects from each Subnet instance, you would need to access the data stored in those by using the following API samples.
2.2.1 iOS
SBMGroup:
name – use SBMGroup.name
address – use SBMGroup.address
virtualAddress – use SBMGroup.virtualAddress
parentGroup – use SBMGroup.parentGroup
appKey – use SBMGroup.appKey
subnet – use SBMGroup.subnet
2.2.2 Android
Group:
name – use Group.getName
address – use Group.getAddress
virtualAddress – use Group.getVirtualAddress
parentGroup – use Group.getParentGroup
appKey – use Group.getAppKey
subnet – use Group.getSubnet
2.3 Node
In the next step you would need to extract the data from the above Node class structure for each Node object in the data base.
2.3.1 iOS
SBMNode
uuid – use SBMNode.uuid
name – use SBMNode.name
primaryElementAddress – use SBMNode.primaryElementAddress
devKey – use SBMNode.devKey
deviceCompositionData – use SBMNode.deviceCompositionData
settings – use SBMNode.settings
security – use SBMNode.security
elements – use SBMNode.elements
subnets – use SBMNode.subnets
2.3.2 Android
Node
uuid – use Node.getUuid
name – use Node.getName
primaryElementAddress – use Node.getPrimaryElementAddress
devKey – use Node.getDevKey
deviceCompositionData – use Node.getDeviceCompositionData
settings – use Node.getSettings
security – use Node.getSecurity
elements – use Node.getElements
subnets – use Node.getSubnets
2.4 Element
Next major step would be to extract the Element type objects which were extracted in the previous part.
2.4.1 iOS
SBMElement
name – use SBMElement.name
address - use SBMElement.address
index - use SBMElement.index
location - use SBMElement.location
sigModels - use SBMElement.sigModels
vendorModels - use SBMElement.vendorModels
2.4.2 Android
Element
name – use Element.getName
address – use Element.getAddress
index – use Element.getIndex
location – use Element.getLocation
sigModels – use Element.getSigModels
vendorModels – use Element.getVendormodels
2.5 Model
Having extracted the lists of supported models you would need to also export the Model structures as well.
2.5.1 iOS
SBMModel
identifier – use SBMModel.identifier
settings – use SBMModel.modelSettings
bindedGroups - use SBMModel.bindedGroups
2.5.2 Android
Model
identifier – use Model.getId()
settings – use Model.getModelSettings()
bindedGroups - use Model.getBindedGroups()
3. Import
Having successfully extracted all the necessary structures of a Mesh Network, it is now time to cover the import procedure to transfer it i.e. into another mobile device. It is a more complex in comparison to the export and there are a few challenges the Developer need to think about to come up with a solution. The following description would require at least basic understanding of Bluetooth Mesh Network mechanisms and safety solutions to enable the Developer to come up with an own solution for the given use case. In our implementation or rather code example we have taken a few shortcuts as this was not prepared for any particular real-life solution but rather for testing and reference for the Customers.
In general, the process would contain from a few key points mentioned below:
Firstly, it is important to note that the existing data base in the receiver device needs to be emptied before starting the procedure, which means that to be sure it was correctly prepared we would recommend using the clearDatabase method from the BluetoothMesh/ SBMBluetoothMesh class.
Secondly, the developer needs to take care of creating all the Mesh structure elements and filling them with appropriate data from the source file. For this purpose, we have prepared an implementation of Importer classes which would allow you to use the API to create the objects with specific configurations.
Lastly, it is necessary to initialize the imported Network with the initializeNetwork method from the BluetoothMesh/SBMBluetoothMesh class. At this point it is necessary for the developer to implement a mechanism for handling the unicast addresses of the provisioners and maintaining both the correct sequence number and IV Index for the Mesh Network.
3.1 Importer class
The Importer/SBMImporter class on both platforms provides two methods createNetwork and performImport. The first one is used to create an object of a NetworkImport/SBMNetworkImport class which contains the API to create and fill all the preliminary MeshNetwork structures in the data base on the receiving device. However, the end responsibility of preparing implementation of creating an appropriate logic to make use of the available functions is on the developer’s side. (The methods were listed and briefly described in the Class Documentation available in the Simplicity Studio directory mentioned in section 2 Export.) Once you have prepared the structure, next step you would need to do is to call the second method from the Importer class which would be performImport. It would transfer all the ‘Import’ objects into the default data base classes and clear the previous instances.
To help you better understand the usage of the Importer we have prepared a code sample for both iOS and Android which shows the usage of these methods.
3.1.1 iOS
func import(from json: String) {
let decoder = JSONDecoder()
do {
let meshData = try decoder.decode(JsonMesh.self, from: (json.data(using: .utf8))!)
// clear database to ensure it's ready for import
SBMBluetoothMesh.sharedInstance().clearDatabase()
let importer = meshData.createImporter()
try importer.performImport()
let network = SBMBluetoothMesh.sharedInstance().networks()[0]
let address = 0
let ivi = 0
try SBMBluetoothMesh.sharedInstance().initializeNetwork(item, address: address, ivIndex: ivi)
} catch {
}
}
func createImporter() -> SBMImporter {
let importer = SBMImporter()
let networkImport = importer.createNetwork((uuid.data(using: .hexadecimal))!)
networkImport.name = name
for item in netKeys {
item.performImport(network: networkImport)
}
// AppKeys & Groups
for item in groups {
item.performImport(network: networkImport, appKeys: appKeys)
}
for item in provisioners {
item.performImport(network: networkImport)
}
for node in nodes {
node.performImport(network: networkImport)
}
return importer
}
3.1.2 Android
fun import() {
val bluetoothMesh = BluetoothMesh.getInstance()
val customAddress = 0
val customIvIndex = 0
val importer = createImporter()
bluetoothMesh.clearDatabase()
importer.performImport()
val network = bluetoothMesh.networks.first()
bluetoothMesh.initializeNetwork(network, customAddress, customIvIndex)
}
private fun createImporter(): Importer {
val importer = Importer() importer.createNetwork(Converter.stringToUuid(jsonMesh.meshUUID!!))
.apply { name = jsonMesh.meshName }
.also {
handleAppKeys()
handleSubnets(it)
handleNodes(it)
handleProvisioners(it)
handleScenes(it)
}
return importer
}
3.2 Network initialization
As it can be seen, next step after a successful data import would be the Network initialization which can be done using the initializeNetwork method from the BluetoothMesh/SBMBluetoothMesh class. (In the code examples attached at sections 3.1.1 and 3.1.2 it can be seen how the usage should look like.) At this point, it is important for the Developer to understand the meaning of the three arguments that this function should receive because wrong values of these parameters may have big influence on the ability to control the imported Network by the mobile device.
Network
First of the arguments is relatively easy to define because it is going be a Network/SBMNetwork type instance which was created by the Importer/SBMImporter.performImport call and can be obtained by using the bluetoothMesh.networks.first() on Android side or SBMBluetoothMesh.networks[0] on the iOS platform.
Warning: With the current version of the ADK library which is 2.3.0 it is always going to be the first element of the networks list because it does not support importing multiple Network instances.
Address
According to the Bluetooth Mesh specification, a provisioner device is still regarded as a Node but with capabilities to add new devices to the Network. This implies that it needs to have a unicast address defined to be identifiable in the structure and it should be unique for a mobile device across mesh. One of the reasons why it is so important is that the address is strictly tied with a certain value of Sequence Number (check out section 3.2.1) and in a case when these two would not match, the provisioner the provisioner device would not be able to control the Network.
IV Index
Last but not least important is for the Developer to set a correct IV Index value and because the updates intervals of this value may differ across different Mesh Networks we can not be sure if the value has not changed since the data base has been exported so hard coding the value in the source file would not be a good solution. Luckily, the IV Index can be retrieved from the Secure Network Beacon (for more information please check Bluetooth Mesh Profile Specification rev. 1.0.1 chapter 3.9.3) data so our recommendation would be to implement a mechanism shown in the AN1200: Bluetooth Mesh for iOS and Android ADK section 13.5 Retrieving the IV Index from the Secure Network Beacon (section number valid for a document rev. 1.3) before calling the initializeNetwork method.
The sequence number, a 24-bit value contained in the sequence number field of the Network PDU, is primarily designed to protect against replay attacks. Elements within the same node may or may not share the sequence number space with each other. Having a different sequence number in each new Network PDU for every message source (identified by the unicast address contained in the SRC field) is critical for the security of the mesh network.
With a 24-bit sequence number, an element can transmit 16,777,216 messages before repeating a nonce. If an element transmits a message on average once every five seconds (representing a fairly high frequency message for known use cases), the element can transmit for 2.6 years before the nonce repeats.
Each element shall use strictly increasing sequence numbers for the Network PDUs it generates. Before the sequence number approaches the maximum value (0xFFFFFF), the element shall update the IV Index using the IV Update procedure (see Section 3.10.5). This is done to ensure that the sequence number will never wrap around.
The IV Index is a 32-bit value that is a shared network resource (i.e., all nodes in a mesh network share the same value of the IV Index and use it for all subnets they belong to).
The IV Index starts at 0x00000000 and is incremented during the IV Update procedure as described in Section 3.10.5. The timing when the value is incremented does not have to be exact, since the least significant bit is communicated within every Network PDU. Since the IV Index value is a 32-bit value, a mesh network can function approximately 5 trillion years before the IV Index will wrap.
The IV Index is shared within a network via Secure Network beacons (see Section 3.9.3). IV updates received on a subnet are processed and propagated to that subnet. The propagation happens by the device transmitting Secure Network beacons with the updated IV Index for that particular subnet. If a device on a primary subnet receives an update on the primary subnet, it shall propagate the IV update to all other subnets. If a device on a primary subnet receives an IV update on any other subnet, the update shall be ignored.
If a node is absent from a mesh network for a period of time, it can scan for Secure Network beacons (see Section 3.10.1) or use the IV Index Recovery procedure (see Section 3.10.6), and therefore set the IV Index value autonomously.
4. Conclusion
As stated at the beginning, the above article shows just a concept of using the Import and Export functionalities available in our mobile library. The mentioned sample implementation will be presented in details with the KBA_BT_0516 which should be available soon on our community forum. In case of any questions regarding this document you can create a support ticket at our web page or comment below.
The Gecko SDK and hence Bluetooth SDK gets a regular update, usually on a monthly basis, in the form of major, minor and patch releases. These updates contain important bug fixes, new features, and sometimes they add support for freshly released hardware (new parts or new boards). This article discusses how to update an existing project, once a new release was downloaded to your computer.
Releases
When you download an SDK with a new major or minor version number (e.g. you update from v2.6.2 to v2.7.0) a new SDK folder will be created on your computer, and from that point you can choose which SDK to use when creating a new project. Your already existing projects won't be touched.
In contrast to this, when you download a patch release to your computer, it will automatically overwrite your existing SDK content. E.g. Gecko SDK v2.7.3 will overwrite Gecko SDK v2.7.2 when downloaded. Now, if you create a new project, it will be created using the new patch release. However, your already existing projects will still contain the files originated from the previous patch release! This is because when you create a project, the SDK files will be copied to your project during project creation, and an SDK update won't touch your already created projects. (This is to avoid automatically updating projects that were already tested with the earlier patch release.)
Updating Existing Projects
If you want to update an already existing project, there are to ways to go:
Creating a new SoC-Empty project with the new SDK, and merging all your changes that were done on the top of the SoC-Empty project generated with the previous SDK
Replacing all SDK files in your already existing project
In general, it is highly recommended to take the first path, as the project generator takes care of copying all the files and making all the configuration needed for the latest SDK version to work.
Updating with Freshly Created SoC-Empty Project
It is recommended to write Bluetooth application in a way, that the application files are completely separated from the SDK files. That's why the SoC-Empty example project contains app.c / app.h files, that implements the application and are independent from the underlying SDK version. (Of course more files can be added implementing application code.) In this case the best way to migrate to a new SDK version is:
Create a new SoC-Empty project with the new SDK version
Overwrite app.c/app.h with your application
Add your other application files (e.g. modules that handles peripherals and provide data for Bluetooth)
Copy the needed SDK dependencies into your project from the updated SDK folder (e.g. if you use LE timer in your project, you have to copy em_letimer.c / em_letimer.h into your project)
Import your GATT database with the GATT configurator. Find the import button on the right side, and import the gatt.xml file from your old project. Press Generate to generate the GATT database code in your project.
You may have applied changes on init_mcu.c, init_board.c, init_app.c in your already existing project. Instead of overwriting these files with the ones from your old project, rather merge in the changes you made. This is important, because these files are not SDK independent, and there may be important changes in them between two SDK versions. Important: do not press Generate in the GATT configurator after this point, as it may regenerate these files, and your changes can disappear!
Add your additional include directories (e.g. if you created a new folder for own header files, or you copied SDK files into a new folder) and libraries in the project settings. Important: do not press Generate in the GATT configurator after this point, as it may regenerate project settings, and your changes can disappear!
You are ready to build your project.
Updating SDK files in your already existing project
You may also take the other path, and update all SDK files in your project one-by-one. In this case you should
Update the /hardware, /platform and /protocol folders in your project. Since these folders in your project contain only a subset of the files existing in the /hardware, /platform, /protocol folders of the SDK (C:\SiliconLabs\SimplicityStudio\v4\developer\sdks\gecko_sdk_suite\vX.Y), you should copy the files one-by-one instead of copying the whole folders into your project!
Check at least main.c, init_mcu.c, init_board.c, init_app.c if they contain any important update since the last SDK version. Create a new SoC-Empty project for your part, and compare the new files with your existing project. If you see any changes that was not done by you, merge those changes in your project.
Some applications require security features beyond those provided by the Bluetooth specification. This article describes the steps necessary for a building a BLE project with mbedtls.
Mbedtls is a library of cryptographic functions, defined here https://tls.mbed.org/api/, which are used by the Silicon Laboratories Bluetooth Low Energy stack. Silicon Labs provides low level drivers for the cryptographic engines in it SoCs to allow mbedtls to run efficiently.
Any application that needs to use mbedtls must remove the prebuilt mbedtls library and build the mbedtls library from source to avoid conflicts. Mbedtls is a highly configurable library with features that can be enabled by defining preprocessor symbols to a configuration file. The basic setup is described below
Remove the prebuilt mbedtls.a library from your project as shown.
At a minimum, the following files must be added to the project. These are found in the SDK folder under util\third_party\mbedtls
Add the following definition to the preprocessor symbols
MBEDTLS_CONFIG_FILE="mbedtls_config.h"
Copy protocol\bluetooth\ble_stack\inc\soc\mbedtls_config.h from the SDK to the project's protocol\bluetooth\ble_stack\inc\soc folder. This ensures that the project enables all of the mbedtls features that the Bluetooth stack requires. Additional features can be enabled in this file but none of the existing features can be disabled.
Bluetooth 5 introduces several enhancements to advertising. This article discusses the concept of chained advertising.
Discussion
Chained advertising allows advertising packets to be linked or chained together to allow for larger advertisements, up to 1650 bytes, to be sent. A new packet type, AUX_CHAIN_IND, is used to transmit the individual portions of these advertisements. Chained advertising works together with extended advertising and periodic advertising. The following example allows a synchronizer, i.e. the receiver of a periodic advertisement, to synchronize to a chained periodic advertisement and begin receiving these advertisements.
Implementation
Advertiser
The maximum size of a BGAPI command is 255B, which does not allow to use one command to set 1650B of advertisement data. Therefore, version 2.12 of Silicon Labs Bluetooth SDK introduces a new API: gecko_cmd_system_data_buffer_write() to write up to 255 bytes of data to the system data buffer, in which the stacks assembles the full advertisement data. This API can be called multiple times when more than 255 bytes must be written to the buffer.
The sample code provided with this article implements a simple function, writeSystemDataBuffer(), to simplify writing up to 1650 bytes to the system data buffer. Once the desired advertising data has been written to the buffer the application starts advertising. The advertisement will include a service UUID, which the synchronizer will look for, and the sync info, on which the synchronizer can sync on. Next, the periodic advertisement is started. Finally, the data assembled in the system data buffer is transferred to the periodic advertisement by calling another new API: gecko_cmd_le_gap_set_long_advertising_data().
Scanner
The scanner, or synchronizer, begins by starting scanning for advertisements containing the ‘watchable’ service with the UUID f69dd7f9-340a-4693-9e46-c8630c898558. The first step is to request the extended scan response by calling gecko_cmd_le_gap_set_discovery_extended_scan_response(), this provides more information about the scanner than the basic scan response. Next, the scanner sets the discovery timing and type and starts discovery. Advertisements or scan responses are handled by gecko_evt_le_gap_extended_scan_response_id event handler. This event handler first filters out any packets which are not extended advertising packets. Next, the advertisement is searched for the service UUID mentioned above by calling findServiceInAdvertisement(). When an advertisement containing this UUID is found, the scanner syncs to this device by calling gecko_cmd_sync_open().
The sample code for the scanner/synchronizer includes event handlers for sync_open and sync_closed events. The sync_closed event is triggered when a sync timeout expires and is used to start scanning again. The gecko_evt_sync_opened_id event is purely informative and simply prints a message indicating that a sync has been opened. The gecko_evt_sync_data_id is triggered whenever sync data is received. This event handler handles three situations:
data received complete,
data received with more to follow and
data truncated.
The first situation occurs either when the advertisement fits in a single packet or when the last packet in a chain is received, in either case the data is saved. The second situation occurs when data is received, and more is expected. When this happens, event handler saves the data and begins reassembly the advertisement. If subsequent data is expected, but none is received, the status is set to data truncated. In this case, the sample application considers the data to be corrupt and discards it all by clearing it’s buffer.
Chained advertisements are buffered using the bluetooth_stack_heap found in main.c. The definition must be increased as shown below to provide sufficient space for the data.
The attached example requires two WSTK/radioboards.
Create a soc-empty project for your desired radio board.
Overwrite the app.c file in this project with app.c from the advertiser folder in the attached zip file.
Open main.c and modify the heap size uint8_t bluetooth_stack_heap[DEFAULT_BLUETOOTH_HEAP(MAX_CONNECTIONS)+1650];
Import gatt.xml from the advertiser folder using the ‘Import GATT’ icon in the GATT Configurator. When finished the result should look like this
Click generate.
Build and download to the first kit.
Create another soc-empty for the second kit.
Overwrite app.c in this project with app.c from the scanner folder in the attached zip file.
Open main.c and modify the heap size uint8_t bluetooth_stack_heap[DEFAULT_BLUETOOTH_HEAP(MAX_CONNECTIONS)+1650];
Open app.h and change the value of DEBUG_LEVEL from 0 to 1 to enable debug printing.
Build and download to the second board.
Open a terminal program, such as the SimplicityStudio serial console, to view the output from the device. The result should look similar to the followingShortly after starting up, the scanner discovers an advertiser that has come into range and synchronizes with it. Each gecko_evt_sync_data_id comes with a maximum of 250 bytes. The entire advertising packet contains 1650 bytes so we see the final event contains 150 bytes and displays a message indicating that the sync is complete. In the next chained advertisement, one of the advertising packet PDUs is not received, so the data is discarded. After one more successful chained advertisement, the sync is closed due to a timeout
Conclusion
Chained advertising provides a way of distributing larger amounts of data to multiple synchronizers without the need for connections. The focus of this article is chained advertising, for more information on periodic advertising in general please see our periodic advertising knowledgebase article
The sequence number, a 24-bit value contained in the sequence number field of the Network PDU, is primarily designed to protect against replay attacks. Elements within the same node may or may not share the sequence number space with each other. Having a different sequence number in each new Network PDU for every message source (identified by the unicast address contained in the SRC field) is critical for the security of the mesh network.
With a 24-bit sequence number, an element can transmit 16,777,216 messages before repeating a nonce. If an element transmits a message on average once every five seconds (representing a fairly high frequency message for known use cases), the element can transmit for 2.6 years before the nonce repeats.
Each element shall use strictly increasing sequence numbers for the Network PDUs it generates. Before the sequence number approaches the maximum value (0xFFFFFF), the element shall update the IV Index using the IV Update procedure (see Section 3.10.5). This is done to ensure that the sequence number will never wrap around.
Sequence number Storing Strategy
Sequence number should be non-volatile, software stacks should make sure that every time the device sends a valid packet, it should never use the sequence numbers which had been already used before, so it would be a good way to store it in the flash. However, writing flash once per each sequence number increment is probably too often so that the flash may easily wear out before the life time of the real product. To balance the impact, the stack will only write the sequence number to flash at a fixed interval when the sequence number increases by pstore_write_interval_elem_seq times, which is adjustable and located in the dcd.c file in your project. Given that there is a chance that the device may loss power unexpectedly before the interval, which means the real sequence number has not been written to flash, next time when the device boots, it will use the old value in the flash. To avoid the node uses any old sequence number, the node will always increase pstore_write_interval_elem_seq after reset. Besides, the stack will detect if there is valid sequence number increasing between the 2 times of reset, if no, the stack won't increase the sequence number. For more information, you can refer to the example in Figure 1.
NOTE: This is not standard but Silicon Labs' current solution and it may change in the future.
IV Index
The IV Index is a 32-bit value that is a shared network resource (i.e., all nodes in a mesh network share the same value of the IV Index and use it for all subnets they belong to).
The IV Index starts at 0x00000000 and is incremented during the IV Update procedure as described in Section 3.10.5. The timing when the value is incremented does not have to be exact, since the least significant bit is communicated within every Network PDU. Since the IV Index value is a 32-bit value, a mesh network can function approximately 5 trillion years before the IV Index will wrap.
The IV Index is shared within a network via Secure Network beacons (see Section 3.9.3). IV updates received on a subnet are processed and propagated to that subnet. The propagation happens by the device transmitting Secure Network beacons with the updated IV Index for that particular subnet. If a device on a primary subnet receives an update on the primary subnet, it shall propagate the IV update to all other subnets. If a device on a primary subnet receives an IV update on any other subnet, the update shall be ignored.
If a node is absent from a mesh network for a period of time, it can scan for Secure Network beacons (see Section 3.10.1) or use the IV Index Recovery procedure (see Section 3.10.6), and therefore set the IV Index value autonomously.
SDK – Bluetooth Mesh SDK 1.5.0 GA or newer, the latest version are always recommended.
Hardware – At least 2 Bluetooth Mesh compatible boards - EFR32xG12 or EFR32xG13 (x= M, B) based, SLWRB4104A and SLWRB4103A are recommended.
Provisioner - Bluetooth Mesh app on smartphones, or the Host Provisioner.
Tools – J-Link RTT viewer or serial terminal for print, if using serial terminal, the parameters are as below:
Baud rate: 115200
Data bits: 8
Stop bit: 1
Flow control: False
IV Update & Recovery Introduction
IV Update & Recovery Procedure
IV Update Procedure:
The sequence number is 24-bit length, as the example provided above, with 5 seconds cadence, the sequence number will repeat after 2.6 years. To avoid this, the node could start the IV update procedure to update the network to a new IV index so that the sequence number could be reset to 0. The IV update procedure can be initiated by any node in the primary subnet. Table 1 shows the summary of IV update procedure.
IV Index
IV Update Flag
IV Update Procedure State
IV Index Accepted
IV Index used when transmitting
n
0
Normal
n-1, n
n
m (m=n+1)
1
In Progress
m-1, m
m-1
m
0
Normal
m-1, m
m
Table 1: IV Update procedure summary
IV Recovery Procedure:
A node shall support the IV index recovery procedure because a node that is away from the network for a long time may miss IV Update procedures, in which case it can no longer communicate with the other nodes. In order to recover the IV Index, the node must listen for a Secure Network beacon, which contains the Network ID and the current IV Index.
IV Update & Recovery Limitations
There are some limitations on initiating IV update and recovery procedure, mentioned in chapters 3.10.5 and 3.10.6 of Mesh Profile Specification v1.0.1. Generally, as below:
If a node in Normal Operation receives a Secure Network beacon with an IV index less than the last known IV Index or greater than the last known IV Index + 42, the Secure Network beacon shall be ignored. Note: This above requirement allows a node to be away from the network for 48 weeks. A node that is away from a network for longer than 48 weeks must be reprovisioned.
A node shall not start an IV Update procedure more often when once every 192 hours.
The transition from Normal Operation state to IV Update in Progress state must occur at least 96 hours before the sequence numbers are exhausted.
After at least 96 hours and before 144 hours of operating in IV Update in Progress state, the node shall transition back to the IV Normal Operation state and not change the IV Index. At the point of transition, the node shall reset the sequence number to 0x000000.
The node shall not execute more than one IV Index Recovery within a period of 192 hours.
IV Test Mode
Because the limitations mentioned above, it's not easy to test the IV update & recovery procedure. So the IV test mode removes the 96 hours limit. All other behavior of the devices remains unchanged.
Secure Network Beacon
The secure network beacon must be enabled to do the IV update & recovery since it's the carrier of the information that a node is updating the IV index.
NOTE: the Bluetooth Mesh app may not support to configure the secure network beacon state, so you may need to enable it locally with the mesh test class commands. If using the Host Provisioner, then it's not a problem since it supports that.
Running The Example
The example contains two projects - iv_update and iv_recovery, they needs to work together to show how the IV update & recovery procedure works, as well as showing the sequence number storing strategy. Let's call the node flashed with iv_update firmware node U, and the node flashed with iv_recovery firmware node R.
BGAPI Commands & Events
Below is a list of BGAPI commands and events related to the IV update & recovery procedure, all of which are demonstrated in the example.
Commands:
gecko_cmd_mesh_node_request_ivupdate(...) - this command is used to initiate an IV update procedure.
gecko_cmd_mesh_node_set_ivrecovery_mode(...) - this command is used for enabling/disabling the IV recovery mode, this can typically be called when the stack reports it's found that the IV of the network is different than the IV of node itself.
gecko_cmd_mesh_test_set_iv_index(...) - this command is used to set the IV index of the node itself.
gecko_cmd_mesh_test_set_ivupdate_state(...) - this command is used to forcedly set the iv update procedure state
Events:
gecko_evt_mesh_node_changed_ivupdate_state_id - This event is generated whenever the node IV update state changes.
gecko_evt_mesh_node_ivrecovery_needed_id - this event is generated whenever the stack consider the found network IV index is too far to catch up automatically, so that the application will decide if to catch up or not.
Import The Projects
Download the attachment and extract it, create a soc-btmesh-switch example project and a soc-btmesh-light example and specify the names, e.g. iv_update and iv_recovery.
Replace the main.c file of the iv_update project with the main.c in the ${extract_folder}/iv_update folder.
Replace the app.c file of the iv_recovery project with the app.c in the ${extract_folder}/iv_recovery folder.
The example uses the Logging System, if you want to use printf instead, you can comment out the #define USE_LOG_MODULE in app.c.
Build both projects and flash them to 2 boards respectively.
Use Bluetooth Mesh app on smartphones or any other kinds of provisioner to provision the 2 boards to the same network and configure them properly.
Behaviors of The Example
As you can see from the last section that the examples are based on the light and switch examples, so they still keep the basic functionalities and behaviors as the original example. What is modified is listed below:
On the Node U side - iv_update project:
Very long press on PB0 - It will start the IV update procedure by increasing the IV index by MIN(TEST_IV_HOP, MAX_IV_HOP - 1) + 1 to demonstrate the IV index hop if the node is not in IV update state. Otherwise, it will terminate the IV update procedure if it's in IV update procedure.
Very long press on PB1 - It will start the IV update procedure by increasing the IV index by 1 to demonstrate the typical IV update procedure if the node is not in IV update state. Otherwise, it will terminate the IV update procedure if it's in IV update procedure.
Whenever the node sends a packet, it will print the current and remaining sequence number.
On the Node R side - iv_recovery project:
Press on PB0 - It will disable the IV recovery mode.
Press on PB1 - It will enable the IV recovery mode.
Test The Sequence Number Increasing
Every time the node U boots and if the node is provisioned, it will print the current and remaining sequence number. Every time any button is pressed to send a packet, the current and remaining sequence number will be printed. You can try to send some packets then reset the device to see what happens. How about if not send packets but reset the node directly? See the result in Figure 1, the pstore_write_interval_elem_seq here is 0x10000.
Figure 1. Sequence Number Increasing
System boots, node Sequence number is 0x30000.
Short press the PB0 once, the sequence number increments to 0x30001.
The same as step 2. After that, reset the device.
System boots, node sequence number is 0x40000. After that, directly reset the device without letting it send any packet.
System boots, node sequence number is still 0x40000.
Test IV Update & Recovery
Figure 2 shows the procedure of IV update and IV recovery, there are 2 nodes in the same network, as you can see from figure 1, on the left side, it's the print of the node which initiates IV update procedure, this is node U, on the right side, it's the print of the node which catches up the IV update, this is node R. There are 4 times of the IV update & recovery procedure, describing below:
From the print of node R you can see the IV recovery mode is disabled after reset. Both node U and R have IV index 158. Node U initiates the IV update from 158 to 159, which is the value of the current IV index of node R plus 1, at the same time, the IV update flag in the secure network beacon is set. So it catches up the IV update procedure automatically without application involved.
Manually set the IV index to 189, then starts IV update procedure. Because the current IV index of node R is 159, the IV index sent from node U is 190 which is not equal to 159 + 1, so the node R generates the event gecko_evt_mesh_node_ivrecovery_needed_id to let the application to decide if to catch up the IV update and start the IV recovery procedure. As you can see the IV recovery mode is enabled after it gets the event, so the node catches up to 190.
The IV index of node U is 156 and the flag in secure network beacon is not set, which means it's not in IV update procedure. The IV index of node R is 155, it generates the event gecko_evt_mesh_node_ivrecovery_needed_id to let the application to decide if to catch up the IV update and start the IV recovery procedure. The application didn't do it in this case, so the IV index didn't change after reset after a while.
The situation is the same as step 3, the only difference is the application enabled the IV recovery mode, so the node catches up the IV index to 156.
Bluetooth Knowledge Base
KBA_BT_0504: Bluetooth Mesh Mobile - Reduction of GATT Connections for Provisioning with Configuration - Implementation
1. Introduction
In the version 2.3.2 of our Bluetooth Mesh Mobile ADK we have introduced a new feature which allows the User to reduce the amount of separate GATT connections necessary for provisioning of the Node with configuration. Enabling it should not only improve the performance of the operation but also increase reliability and success rates during those procedures. That's because both the provisioning process and the initial proxy session with configuration of the Node is going to take place under a single connection.
The main aim of this article is to give you a simple instruction on how to implement all the necessary changes into the application which are required to reduce number of GATT connections needed.
2. Android
2.1 BluetoothConnectableDevice modifications
First of all, for the new solution to work it is necessary to make the following changes to the BluetoothConnectableDevice class.
Warning: The following modifications have been already applied in the Bluetooth Mesh by Silicon Labs demo application released with ADK 2.3.2 and the full class implementation can be found in the attachment to this article.
2.2 Provision with configuration under one connection
Having successfully incorporated the code attached above, the Developer may proceed to make changes that will make the provisioning and configuration to happen at the same GATT connection. It would require a change in the execution order which is presented below.
2.2.1 Execution modification
The User of the ADK needs to make sure that he/she creates a ProvisionerConfiguration object, sets the isUsingOneGattConnection property to true and then adds that object as an argument for the provision method.
Note: It is also possible to add other initial configuration to that object such as setting the Node as Proxy or Relay.
3. iOS
On the iOS the situation looks very similar to the Android. The appropriate steps have been covered below
3.1 SBMConnectableDevice modifications
Firstly, it is necessary to make modifications to class implementing SBMConnectableDevice protocol by implementation for new method and calling SBMConnectableDeviceDelegate.didModifyServices(, for:) method of delegate object.
Warning: Those changes have been already applied in the Bluetooth Mesh by Silicon Labs demo application released with ADK 2.3.2 and the full class implementation can be found in the attachment to this article.
SBMConnectableDevice:
SBMConnectableDeviceDelegate:
3.2 Provision with configuration under one connection
Once the Developer has successfully incorporated all the above changes, he or she can proceed to modify the execution sequence which is required to enable the usage of One Gatt connection.
3.2.1 Execution modification
The User of the ADK needs to make sure that he/she creates a ProvisionerConfiguration object, sets the useOneGattConnection property to true and then adds that object as an argument for the provision method.
Note: It is also possible to add other initial configuration to that object such as setting the Node as Proxy or Relay.
4. Keeping connection after the provisioning
Apart from the feature described above, in the 2.3.2 version of the ADK we have also introduced a possibility of keeping the Proxy connection after the successful provisioning. Enabling that might also lead to improvements in performance and reliability of the application.
The following points describe the necessary actions which need to be implemented in the application for each platform.
4.1 Android
4.1.1 Execution modification
Firstly, it is necessary to set the keepingProxyConnection to true in the ProvisionerConfiguration object and add it as an argument for the provision method.
Note: It is also possible to add other initial configuration to that object such as setting the Node as Proxy or Relay.
4.1.2 Obtaining active Proxy Connection object
When the provisioning session finishes, it is going to be necessary to obtain the still active ProxyConnection to use it for other operations depending on the Developer requirements. It can be done by implementing a following solution into the provisioning callback.
It is important to highlight the importance of replacing the error callback for handling unexpected connection issues such as sudden disconnects. Please make sure you carefully analyse the following code example.
4.2 iOS
4.2.1 Execution modification
It is important to notice that if one wishes to close proxy connection after configuration, init method with keepProxyConnection set to false needs to be explicitly used.
4.2.2 Obtaining active Proxy Connection object
When the provisioning session finishes, it is going to be necessary to obtain the still active ProxyConnection to use it for other operations depending on the Developer requirements. It can be done by implementing a following solution into the provisioning callback.
It is important to highlight the importance of replacing the error callback for handling unexpected connection issues such as sudden disconnects. Please make sure you carefully analyse the following code example.
5. Conclusion
To sum up, the above guidelines should help the Users to understand how to enable the new described features in their application. Certainly it can bring significant improvements to the performance of their applications and increase reliability as well.
In case of any problems or questions regarding this document you can create a support ticket at our web page or comment below.
KBA_BT_0503: Bluetooth Mesh Advertising Sets
This article describes:
Advertising Sets
Advertising Sets are defined in Section 4.4.2.10, Part B, Vol 6, Bluetooth Specification Version 5.2. With advertising sets supported, Bluetooth stack actually provides a way to interleave multiple advertising events. Each advertising set has its own parameters, payload, timing etc. and is independed to the other advertising sets. For example, if you want to send a connectable advertisement and a non-connectable beacon simultaneously, you don't necessarily need to send the connectable advertisement once then modify the content and parameters to send the non-connectable beacon repeatedly, this will easy to achieve by using 2 advertising sets.
Advertising Sets Used by Bluetooth Mesh Stack
When the Bluetooth stack initializes, user application needs to configure the number of the maximum advertising sets used by both the stack and application. Other than the regular BLE examples, which typically don't use any advertising set, the Bluetooth Mesh stack uses some advertising sets to send data. You can find below inline description of the advertising sets used by Bluetooth Mesh stack in the main.c file of all Bluetooth Mesh examples.
Here is a more verbose explanation for each set:
Advertising Set 0 - Reserved for Application
This advertising set is reserved for regular BLE advertising. It's created when the stack initializes by default and ready to be used by the application. For example, you can call the API gecko_cmd_le_gap_start_advertising with handle 0 to start advertising with this advertising set. This is NOT used by the Bluetooth Mesh stack, but has to be counted into the maximum number of the advertising sets.
Advertising Set 1 - Bluetooth Mesh Data
This advertising set is used for Bluetooth Mesh data traffic, which is the traffic happens on the Advertising bearer (section 3.3.1 of Mesh Profile v1.0.1) and PB-ADV (section 5.2.1 of Mesh Profile v1.0.1) . The stack is in control of the advertising data and the advertising parameters for this set, and the user application MUST NOT override the parameters or use this set for any other purpose.
Advertising Set 2 - Bluetooth Mesh Unprovisioned Device Beacon Without URI
This advertising set is used for sending the Unprovisioned Device Beacon (section 3.9.2 of Mesh Profile v1.0.1) when devices are in unprovisioned state. The Bluetooth Mesh stack will construct the advertising payload according to the definition of the Unprovisioned Device beacon format. User application shall not modify the advertising payload to this advertising set. What the user application can control in this case is the cadence for sending the Unprovisioned Device beacon, call the API - gecko_cmd_le_gap_set_advertise_timing with handle 2 BEFORE starting the Unprovisioned Device beacon.
Advertising Set 3 - Bluetooth Mesh Unprovisioned Device Beacon With URI
This advertising set is also used for sending the Unprovisioned Device Beacon (section 3.9.2 of Mesh Profile v1.0.1) when devices are in unprovisioned state. The only difference is there are 4-byte of URI hash appended to the data payload. See below lines from the Mesh Profile.
The latest Bluetooth Mesh stack doesn't support sending Unprovisioned Device beacon with URI, so this is reserved for future use.
Advertising Set 4 to N - Bluetooth Mesh Proxy Service Advertising
The usage of this advertising set is device state dependent.
If a device is in unprovisioned state, this advertising set will be used to advertise the Mesh Provisioning Service (section 7.1 of Mesh Profile v1.0.1) if the application call gecko_cmd_mesh_node_start_unprov_beaconing with PB-GATT bit set in the bearer parameter.
If a device is in provisioned state and supports Proxy feature, it shall start advertising the Mesh Proxy Service (section 7.2 of Mesh Profile v1.0.1) if the given situations are met. Alternatively, user application can start the advertising munally whenever the device is expected to connect to a proxy client.
Because a provisioned device could belong to multiple subnets, it could advertise multiple Mesh Proxy Service advertisements simultaneously. The maximum network key number that the device supports decides the maximum number of subnets the device can be in, so N is calculated to be 4 + the maximum network key on the device.
Adding Customized Advertising Sets to Bluetooth Mesh Applications
This example shows how to add your custom BLE advertising into a Bluetooth Mesh project.
Step 1: Increase the MAX_ADVERTISERS macro by the number of your custom advertising sets.
The .bluetooth.max_advertisers parameter in the gecko_configuration_t structure decides the maximum number of the advertising sets in the application. In all examples of the Bluetooth Mesh SDK, this value is feed by MAX_ADVERTISERS macro. So, modify the MAX_ADVERTISERS macro like below to add your own advertising sets.
Step 2: Configure the advertising sets if needed.
You can use the advertising configuration related APIs (gecko_cmd_le_gap_set_advertise_xxx) to configure the advertising sets specifically by the advertising set ID (handle), as well as the gecko_cmd_le_gap_bt5_set_adv_data to set the advertising payload. For more details about the advertising parameters and data payload format, you can check Bluetooth Advertising Data Basics. For constructing the advertising data in a much easier way, you can use the code example - Advertisement or Scan Response Constructor.
Step 3: Start the advertising sets
This is the final step to send your own advertisement, call gecko_cmd_le_gap_start_advertising with advertising set ID (handle) specified to start advertising the specific advertisement.
There is basically no difference compared to regular (non-mesh) BLE case. The key thing to take into account here is configuring the number of advertising sets and selecting the right advertising handle to use.
KBA_BT_0518: Self provisioning and configuration example
Introduction
This self provisioning and configuration example provides a function to provision and configure the device itself. This example doesn't perform the provisioning procedure and instead writes provisioning data directly into the persistent storage and configures the models on the device.
The goal of this example is to provide the function for the users who want to run their devices directly in a Bluetooth Mesh network without using a provisioner. This example is mainly used for development and testing purposes and is not recommended to run on final products.
This article describes how to integrate the example into a Bluetooth Mesh project, how to configure the function and how the self provisioning and configuration work.
Project integration
This article assumes app.c is the file that will call the self provisioning function. In your project, you may make the function be called in some conditions, e.g. when a button is held down for seconds. The example uses the DCD configuration from your project so the auto-generated files
dcd.c
andmesh_app_memory_config.h
should exist in your project folder.The code example consists of two source files: selfprov.c and selfprov.h. Copy the two files to your Bluetooth Mesh project and make the following changes.
Add
gecko_bgapi_class_mesh_test_init();
to the class initialization functiongecko_bgapi_classes_init()
in app.c.Add
#include "selfprov.h"
in app.c.Add the function call
self_provisioning();
in app.c at a point after the node has been initialized. For example, in the event handler of thegecko_evt_mesh_node_initialized_id
event.The example performs self provisioning and configuration only when the network and application key counts are 0. You may need to call
cmd_flash_ps_erase_all
to delete all security keys and then reset the device.Self provisioning configuration
The example doesn't declare any global variables for data to be changed at runtime. The provisioning and model configuration data are therefore defined at compilation time in selfprov.h and are used by the functions in selfprov.c to provision and configure the device.
The example gets the model IDs configured for the device from dcd.c which is generated from the Bluetooth Mesh Configurator. The example binds all of these model IDs to the application key. The example then recoginzes server and client models from these model IDs and applies server and client settings respectively. The server and client settings are publication parameters and subscription addresses. The same application key is used for all model configuration.
Unicast address
A unicast address is required to provision a device. The self provisioning function generates a unicast address by performing XOR operations on the device's Bluetooth address. Bit 0, 1, 2, and 3 are reserved for secondary element addresses and bit 14 is reserved for manual addresses. This gives 1,023 automatically allocated addresses in the range of 0x0010 and 0x3FF0 with the 4 LSbs and the 2 MSbs set to 0.
If the address 0x0000 or a duplicate address is generated, you need to allocate manually an address to the device and in this case the function doesn't run the automatic address allocation. The addresses you can allocate manually would be in the range of 0x4000 and 0x7FF0 with the 4 LSbs set to 0.
Set
UNICAST_ADDRESS
to 0x0000 to run the automatic unicast address allocation. Alternatively, you can set any value between 0x0001 and 0x7FFF inclusively to allocate a unicast address manually. It is recommended to separate manual and automatic address ranges and the definitionUADDR_RSVD_BITS
is usded for this purpose.The number of the LSbs reserved for secondary element addresses. If the address 0x0010 is allocated to a node, the address of the primary element (element 0) is 0x0010 and the addresses of secondary elements are 0x0011 (element 1), 0x0012 (element 2) and so on, which are allocated by the Bluetooth Mesh stack. The default value 4 gives maximum 16 elements. Set
UADDR_ELEM_BITS
to a number N to allow the maximum (2 to the power of N) elements that any node can have.The number of bits from bit 14 to LSb reserved for manual addresses in the range separate from the automatic address range. The default value 1 means you can set
UNICAST_ADDRESS
to any of the addresses with bit 14 set to 1, which are in the range of 0x4000 and 0x7FFF. You can set it to 0 if you want and you will need to manage the addresses that are unique among the automatically allocated addresses.Security keys
The self provisioning function writes the security keys
netkey
,devkey
andappkey
directly into the persistent storage on the device. The key length is 128 bits, i.e. 16 bytes.The security keys
NETWORK_KEY
andDEVICE_KEY
are required to provision a device and the security keyAPPLICATION_KEY
is required to configure the node. The self provisioning function uses the application key to bind all models configured on the device and to set publication parameters.Server and client models
The self provisioning function reads model IDs from DCD and splits them into two groups: server and client. The function sets the server publication parameters and subscription addresses to all server models and the client publication parameters and subscription addresses to all client models.
The models Configuration Server, Configuration Client, Health Server, Health Client and Setup servers are excluded.
The self provisioning function determines whether a model ID is a server model or a client model by comparing it with
PUB_SUB_SERVER_MODELS
andPUB_SUB_CLIENT_MODELS
. The function reads all model IDs from DCD and puts server model IDs to a server model buffer and client model IDs to a client model buffer, or drops the model IDs that don't exist in these definitions. You can remove any model ID from these definitions if you don't want the device running the model to send and receive messages.The size of the buffers used to store server and client model IDs. It is usually the maximum length of
PUB_SUB_SERVER_MODELS
andPUB_SUB_CLIENT_MODELS
.Publication address and subscription list
The server publication address and subscription list are set to all server models and the client publication address and subscription list are set to all client models. Therefore, messages sent from the nodes running a server model will go to the nodes running the corresponding client model, and vice versa.
To publish messages to a new group, you can add a new group address to the client subscription list and set the server publication address to the new group address, and vice versa. You can also configure the node not to send messages by setting the publication address to 0x0000, or not to receive messages by clearing the subscription list.
For the nodes running server models to send messages to the nodes running client models, set
GRP_SVR_PUB_ADDRESS
to an address in the list ofGRP_CLI_SUB_ADDRESSES
. For the nodes running client models to send messages to the nodes running server models, setGRP_CLI_PUB_ADDRESS
to an address in the list ofGRP_SVR_SUB_ADDRESSES
.Publication parameters
The server publication parameters are set to all server models and the client publication parameters are set to all client models on the node.
Module EN 300 328 V2.2.2 and EN/IEC 62368-1 DoC Availability
On December 20, 2020, EN/IEC 60950-1 safety standard will be withdrawn and fully replaced by EN/IEC 62368-1, requiring manufacturers to comply with the new standard for the presumption of conformity. Furthermore, as of February 6, 2020, RF regulatory standard EN 300 328 V2.2.2 has replaced EN 300 328 V2.1.1 with a transition period ending on August 6, 2021. After the transitions, products on the market must comply with the updated standards.
Silicon Laboratories is committed to perform any required delta testing with the affected wireless modules (except for certain parts reaching EoL) according to the new standards and release the updated test reports and declarations of conformity (DoCs) before the end of the listed transition periods.
The parts planned to be tested are listed in the table below:
KBA_BT_0517: Bluetooth Mesh Node Reset Procedure
The Node Reset Procedure is the way to remove a node from a network, which is like the node leaves the network actively. It's different from blacklisting which is the way to move all un-blacklisted nodes to the new network, so the node is left passively. Below table gives a simple comparison between these 2 methods to remove node(s) from network.
The node reset procedure includes below 2 messages:
In general, how the node reset procedure looks like in the ideal situation is like figure 1 shows.
Figure 1
Given that the wireless communication can be affected by many environment factors, especially the packet collision, which results in certain packet cannot be received by the receiving device. Typically, the wireless protocols have a proper way to know the situation happens, then they can just retry sending the missing packets. However, for this procedure, because the node needs to remove itself from the network after sending the Config Node Reset Status message, it won't be able to communicate with the provisioner any more. Let's imagine what happens if either of those 2 packets is missing by the target device.
Figure 2 shows that if the node misses some of the Config Node Reset message.
Figure 2
From the figure you can see, the provisioner sends Config Node Reset then waits for the acknowledgement - the Config Node Reset Status message from the Node, whereas the node doesn't receive the Config Node Reset message successfully, which means the node will never send the acknowledgement. There is a predefined waiting time on the provisioner side, so the provisioner will get the timeout event after the predefined time, then it can retry sending the Config Node Reset message until the acknowledgement is received or it fails for a certain amount of times. In this case, only the user experience will be affected since the time for the procedure increases dramatically becauses of the timeouts.
Figure 3 shows that if the provisioner misses the Config Node Reset Status message.
Figure 3
From the figure you can see, the node receives the Config Node Reset message from the provisioner and acknowledges with the Config Node Reset Status message, then removes itself from the network. However, the message is missed by the provisioner, which means the real node status is uncertain to the provisioner since it doesn't know if the Config Node Reset message is received by the node or not. In this case, the situation is not recoverable, consider:
Actually, the figure 3 is still idealised. In practice, the provisioner won't know the status of the node before it successfully receives the Config Node Reset Status. So, this brings some problems:
Conclusion
All in all, the conclusion is The Node Reset Procedure is UNRELIABLE without any other means of determining the real status of the node.
Ideas
From the above description, the most important thing for this procedure to finish properly is that the provisioner receiving the Config Node Reset Status message successfully. So, to improve the performance, you could try to increase the network retransmission. This can be done temporarily before the node reset procedure, e.g. normally, the network retransmission count is disabled or configured to be a low value. When the provisioner wants to remove the node, it could firstly configure a high network retransmission to the node then start the node reset procedure. See figure 4.
Figure 4
But this is just a way to improve the performance, it doesn't make the procedure to be reliable. Application developers should take this into account if it's desired to make it reliable. For example, based on the assumption that the unprovisioned device will always send unprovisioned device beacon, the provisioner can scan for the unprovisioned device beacon to know if the device is already in unprovisioned state before removes the node from database.
KBA_BT_0515: Bluetooth Mesh Mobile - Import/Export Functionalities Concepts
KBA_BT_0515: Bluetooth Mesh Mobile - Import/Export Functionalities Concepts
1. Introduction
The Import and Export feature can be regarded as one of the most important ones in the Bluetooth Mesh Silicon Laboratories’ ADK. Introduced in the 2.2.0 release can allow the User to implement completely new approach to control the Mesh Network. One of the use cases examples we suggest, and which is enabled by this functionality, is active usage of multiple data bases or in other words multiple different Mesh networks in the same application. Currently as stated in the AN1200 document the library does not natively support it but it can be worked around by using the Import and Export. Surely there are many other scenarios to be invented by the Users, and knowing the importance of the topic, we have tried to sum up the key steps that need to be followed, in the Document below.
2. Export
First of all, it is necessary for the Developer to understand how and what information exactly need to be exported into an external file to successfully move the Mesh Network structure between the devices. The Silabs’ ADK does not specify what type of file it needs to be, it is up to Developer to choose a specific format for storing the data base. Our API only provides appropriate methods which can be used to extract the necessary information from the Mesh structure which main components are Network, Subnet, Group, Node, Element and Model. As a help for the Developers to get started, we have also prepared a sample implementation of the Export which you can use as a reference or a starting point for your own, in which we have decided to use a JSON string file as a container for our database.
Warning: Due to complexity of the dependencies between the different objects in the Mesh Structure we were not able to gather all the necessary API for export in this document. Below you will find just examples of the methods which can be used to extract the data. The rest of the necessary functions can be found in the class documentation which was attached to the BLE mesh package in the Simplicity Studio directory.
Also, we would highly recommend, after the successful export procedure, to keep the file protected by implementing an appropriate encryption method according to the Customer's requirements.
2.1 Network
Firstly, it would be necessary to get access to the Network type objects available in the data base. It would allow the developer to extract all the necessary information stored inside and will allow you to get the lists of existing Subnets, Provisioners and Scenes in the Mesh Network. Following that, it is going to be needed to extract the data stored in each of the objects of these three types and then the lower layer as well (SubnetSecurity, NetKey, AddressRange). The API samples were listed below for both platforms.
2.1.1. iOS
2.1.2 Android
2.2 Group
Having extracted a list of Group objects from each Subnet instance, you would need to access the data stored in those by using the following API samples.
2.2.1 iOS
2.2.2 Android
2.3 Node
In the next step you would need to extract the data from the above Node class structure for each Node object in the data base.
2.3.1 iOS
2.3.2 Android
2.4 Element
Next major step would be to extract the Element type objects which were extracted in the previous part.
2.4.1 iOS
2.4.2 Android
2.5 Model
Having extracted the lists of supported models you would need to also export the Model structures as well.
2.5.1 iOS
2.5.2 Android
3. Import
Having successfully extracted all the necessary structures of a Mesh Network, it is now time to cover the import procedure to transfer it i.e. into another mobile device. It is a more complex in comparison to the export and there are a few challenges the Developer need to think about to come up with a solution. The following description would require at least basic understanding of Bluetooth Mesh Network mechanisms and safety solutions to enable the Developer to come up with an own solution for the given use case. In our implementation or rather code example we have taken a few shortcuts as this was not prepared for any particular real-life solution but rather for testing and reference for the Customers.
In general, the process would contain from a few key points mentioned below:
3.1 Importer class
The Importer/SBMImporter class on both platforms provides two methods createNetwork and performImport. The first one is used to create an object of a NetworkImport/SBMNetworkImport class which contains the API to create and fill all the preliminary MeshNetwork structures in the data base on the receiving device. However, the end responsibility of preparing implementation of creating an appropriate logic to make use of the available functions is on the developer’s side. (The methods were listed and briefly described in the Class Documentation available in the Simplicity Studio directory mentioned in section 2 Export.) Once you have prepared the structure, next step you would need to do is to call the second method from the Importer class which would be performImport. It would transfer all the ‘Import’ objects into the default data base classes and clear the previous instances.
To help you better understand the usage of the Importer we have prepared a code sample for both iOS and Android which shows the usage of these methods.
3.1.1 iOS
3.1.2 Android
3.2 Network initialization
As it can be seen, next step after a successful data import would be the Network initialization which can be done using the initializeNetwork method from the BluetoothMesh/SBMBluetoothMesh class. (In the code examples attached at sections 3.1.1 and 3.1.2 it can be seen how the usage should look like.) At this point, it is important for the Developer to understand the meaning of the three arguments that this function should receive because wrong values of these parameters may have big influence on the ability to control the imported Network by the mobile device.
First of the arguments is relatively easy to define because it is going be a Network/SBMNetwork type instance which was created by the Importer/SBMImporter.performImport call and can be obtained by using the bluetoothMesh.networks.first() on Android side or SBMBluetoothMesh.networks[0] on the iOS platform.
Warning: With the current version of the ADK library which is 2.3.0 it is always going to be the first element of the networks list because it does not support importing multiple Network instances.
Address
According to the Bluetooth Mesh specification, a provisioner device is still regarded as a Node but with capabilities to add new devices to the Network. This implies that it needs to have a unicast address defined to be identifiable in the structure and it should be unique for a mobile device across mesh. One of the reasons why it is so important is that the address is strictly tied with a certain value of Sequence Number (check out section 3.2.1) and in a case when these two would not match, the provisioner the provisioner device would not be able to control the Network.
IV Index
Last but not least important is for the Developer to set a correct IV Index value and because the updates intervals of this value may differ across different Mesh Networks we can not be sure if the value has not changed since the data base has been exported so hard coding the value in the source file would not be a good solution. Luckily, the IV Index can be retrieved from the Secure Network Beacon (for more information please check Bluetooth Mesh Profile Specification rev. 1.0.1 chapter 3.9.3) data so our recommendation would be to implement a mechanism shown in the AN1200: Bluetooth Mesh for iOS and Android ADK section 13.5 Retrieving the IV Index from the Secure Network Beacon (section number valid for a document rev. 1.3) before calling the initializeNetwork method.
3.2.1 Sequence number
Definition taken from Bluetooth Mesh Profile Specification rev. 1.0.1 chapter 3.8.3.
3.2.2 IV Index
Definition taken from Bluetooth Mesh Profile Specification rev. 1.0.1 chapter 3.8.4.
4. Conclusion
As stated at the beginning, the above article shows just a concept of using the Import and Export functionalities available in our mobile library. The mentioned sample implementation will be presented in details with the KBA_BT_0516 which should be available soon on our community forum. In case of any questions regarding this document you can create a support ticket at our web page or comment below.
KBA_BT_1406: Migrating Bluetooth Projects between SDK Releases
Introduction
The Gecko SDK and hence Bluetooth SDK gets a regular update, usually on a monthly basis, in the form of major, minor and patch releases. These updates contain important bug fixes, new features, and sometimes they add support for freshly released hardware (new parts or new boards). This article discusses how to update an existing project, once a new release was downloaded to your computer.
Releases
When you download an SDK with a new major or minor version number (e.g. you update from v2.6.2 to v2.7.0) a new SDK folder will be created on your computer, and from that point you can choose which SDK to use when creating a new project. Your already existing projects won't be touched.
In contrast to this, when you download a patch release to your computer, it will automatically overwrite your existing SDK content. E.g. Gecko SDK v2.7.3 will overwrite Gecko SDK v2.7.2 when downloaded. Now, if you create a new project, it will be created using the new patch release. However, your already existing projects will still contain the files originated from the previous patch release! This is because when you create a project, the SDK files will be copied to your project during project creation, and an SDK update won't touch your already created projects. (This is to avoid automatically updating projects that were already tested with the earlier patch release.)
Updating Existing Projects
If you want to update an already existing project, there are to ways to go:
Creating a new SoC-Empty project with the new SDK, and merging all your changes that were done on the top of the SoC-Empty project generated with the previous SDK
Replacing all SDK files in your already existing project
In general, it is highly recommended to take the first path, as the project generator takes care of copying all the files and making all the configuration needed for the latest SDK version to work.
Updating with Freshly Created SoC-Empty Project
It is recommended to write Bluetooth application in a way, that the application files are completely separated from the SDK files. That's why the SoC-Empty example project contains app.c / app.h files, that implements the application and are independent from the underlying SDK version. (Of course more files can be added implementing application code.) In this case the best way to migrate to a new SDK version is:
Create a new SoC-Empty project with the new SDK version
Overwrite app.c/app.h with your application
Add your other application files (e.g. modules that handles peripherals and provide data for Bluetooth)
Copy the needed SDK dependencies into your project from the updated SDK folder (e.g. if you use LE timer in your project, you have to copy em_letimer.c / em_letimer.h into your project)
Import your GATT database with the GATT configurator. Find the import button on the right side, and import the gatt.xml file from your old project. Press Generate to generate the GATT database code in your project.
You may have applied changes on init_mcu.c, init_board.c, init_app.c in your already existing project. Instead of overwriting these files with the ones from your old project, rather merge in the changes you made. This is important, because these files are not SDK independent, and there may be important changes in them between two SDK versions. Important: do not press Generate in the GATT configurator after this point, as it may regenerate these files, and your changes can disappear!
Add your additional include directories (e.g. if you created a new folder for own header files, or you copied SDK files into a new folder) and libraries in the project settings. Important: do not press Generate in the GATT configurator after this point, as it may regenerate project settings, and your changes can disappear!
You are ready to build your project.
Updating SDK files in your already existing project
You may also take the other path, and update all SDK files in your project one-by-one. In this case you should
Update the /hardware, /platform and /protocol folders in your project. Since these folders in your project contain only a subset of the files existing in the /hardware, /platform, /protocol folders of the SDK (C:\SiliconLabs\SimplicityStudio\v4\developer\sdks\gecko_sdk_suite\vX.Y), you should copy the files one-by-one instead of copying the whole folders into your project!
Check at least main.c, init_mcu.c, init_board.c, init_app.c if they contain any important update since the last SDK version. Create a new SoC-Empty project for your part, and compare the new files with your existing project. If you see any changes that was not done by you, merge those changes in your project.
KBA_BT_0921: Using Mbedtls with BLE
Some applications require security features beyond those provided by the Bluetooth specification. This article describes the steps necessary for a building a BLE project with mbedtls.
Mbedtls is a library of cryptographic functions, defined here https://tls.mbed.org/api/, which are used by the Silicon Laboratories Bluetooth Low Energy stack. Silicon Labs provides low level drivers for the cryptographic engines in it SoCs to allow mbedtls to run efficiently.
Any application that needs to use mbedtls must remove the prebuilt mbedtls library and build the mbedtls library from source to avoid conflicts. Mbedtls is a highly configurable library with features that can be enabled by defining preprocessor symbols to a configuration file. The basic setup is described below
Remove the prebuilt mbedtls.a library from your project as shown.
At a minimum, the following files must be added to the project. These are found in the SDK folder under util\third_party\mbedtls
Add the following to your project's include paths
util/third_party/mbedtls/include util/third_party/mbedtls/include/mbedtls util/third_party/mbedtls/sl_crypto/include util/silicon_labs/silabs_core/memory_manager
Add the following definition to the preprocessor symbols
MBEDTLS_CONFIG_FILE="mbedtls_config.h"
Copy protocol\bluetooth\ble_stack\inc\soc\mbedtls_config.h from the SDK to the project's protocol\bluetooth\ble_stack\inc\soc folder. This ensures that the project enables all of the mbedtls features that the Bluetooth stack requires. Additional features can be enabled in this file but none of the existing features can be disabled.
Add the following to your application code
#if !defined(MBEDTLS_CONFIG_FILE) #include "mbedtls/config.h" #else #include MBEDTLS_CONFIG_FILE #endif
Now you can begin using mbedtls in your application code.
KBA_BT_0208: Chained Advertisements
Introduction
Bluetooth 5 introduces several enhancements to advertising. This article discusses the concept of chained advertising.
Discussion
Chained advertising allows advertising packets to be linked or chained together to allow for larger advertisements, up to 1650 bytes, to be sent. A new packet type, AUX_CHAIN_IND, is used to transmit the individual portions of these advertisements. Chained advertising works together with extended advertising and periodic advertising. The following example allows a synchronizer, i.e. the receiver of a periodic advertisement, to synchronize to a chained periodic advertisement and begin receiving these advertisements.
Implementation
Advertiser
The maximum size of a BGAPI command is 255B, which does not allow to use one command to set 1650B of advertisement data. Therefore, version 2.12 of Silicon Labs Bluetooth SDK introduces a new API: gecko_cmd_system_data_buffer_write() to write up to 255 bytes of data to the system data buffer, in which the stacks assembles the full advertisement data. This API can be called multiple times when more than 255 bytes must be written to the buffer.
The sample code provided with this article implements a simple function, writeSystemDataBuffer(), to simplify writing up to 1650 bytes to the system data buffer. Once the desired advertising data has been written to the buffer the application starts advertising. The advertisement will include a service UUID, which the synchronizer will look for, and the sync info, on which the synchronizer can sync on. Next, the periodic advertisement is started. Finally, the data assembled in the system data buffer is transferred to the periodic advertisement by calling another new API: gecko_cmd_le_gap_set_long_advertising_data().
Scanner
The scanner, or synchronizer, begins by starting scanning for advertisements containing the ‘watchable’ service with the UUID f69dd7f9-340a-4693-9e46-c8630c898558. The first step is to request the extended scan response by calling gecko_cmd_le_gap_set_discovery_extended_scan_response(), this provides more information about the scanner than the basic scan response. Next, the scanner sets the discovery timing and type and starts discovery. Advertisements or scan responses are handled by gecko_evt_le_gap_extended_scan_response_id event handler. This event handler first filters out any packets which are not extended advertising packets. Next, the advertisement is searched for the service UUID mentioned above by calling findServiceInAdvertisement(). When an advertisement containing this UUID is found, the scanner syncs to this device by calling gecko_cmd_sync_open().
The sample code for the scanner/synchronizer includes event handlers for sync_open and sync_closed events. The sync_closed event is triggered when a sync timeout expires and is used to start scanning again. The gecko_evt_sync_opened_id event is purely informative and simply prints a message indicating that a sync has been opened. The gecko_evt_sync_data_id is triggered whenever sync data is received. This event handler handles three situations:
data received complete,
data received with more to follow and
data truncated.
The first situation occurs either when the advertisement fits in a single packet or when the last packet in a chain is received, in either case the data is saved. The second situation occurs when data is received, and more is expected. When this happens, event handler saves the data and begins reassembly the advertisement. If subsequent data is expected, but none is received, the status is set to data truncated. In this case, the sample application considers the data to be corrupt and discards it all by clearing it’s buffer.
Chained advertisements are buffered using the bluetooth_stack_heap found in main.c. The definition must be increased as shown below to provide sufficient space for the data.
uint8_t bluetooth_stack_heap[DEFAULT_BLUETOOTH_HEAP(MAX_CONNECTIONS)+1650];
Running the Example
The attached example requires two WSTK/radioboards.
Create a soc-empty project for your desired radio board.
Overwrite the app.c file in this project with app.c from the advertiser folder in the attached zip file.
Open main.c and modify the heap size
uint8_t bluetooth_stack_heap[DEFAULT_BLUETOOTH_HEAP(MAX_CONNECTIONS)+1650];
Import gatt.xml from the advertiser folder using the ‘Import GATT’ icon in the GATT Configurator. When finished the result should look like this
Click generate.
Build and download to the first kit.
Create another soc-empty for the second kit.
Overwrite app.c in this project with app.c from the scanner folder in the attached zip file.
Open main.c and modify the heap size
uint8_t bluetooth_stack_heap[DEFAULT_BLUETOOTH_HEAP(MAX_CONNECTIONS)+1650];
Open app.h and change the value of DEBUG_LEVEL from 0 to 1 to enable debug printing.
Build and download to the second board.
Open a terminal program, such as the SimplicityStudio serial console, to view the output from the device. The result should look similar to the followingShortly after starting up, the scanner discovers an advertiser that has come into range and synchronizes with it. Each gecko_evt_sync_data_id comes with a maximum of 250 bytes. The entire advertising packet contains 1650 bytes so we see the final event contains 150 bytes and displays a message indicating that the sync is complete. In the next chained advertisement, one of the advertising packet PDUs is not received, so the data is discarded. After one more successful chained advertisement, the sync is closed due to a timeout
Conclusion
Chained advertising provides a way of distributing larger amounts of data to multiple synchronizers without the need for connections. The focus of this article is chained advertising, for more information on periodic advertising in general please see our periodic advertising knowledgebase article
KBA_BT_0513: IV Update & Recovery Procedure and Sequence Number Storing Strategy
IV Index & Sequence Number
Below is the definition of Sequence number and IV index from chapters 3.8.3 and 3.8.4 of Mesh Profile Specification v1.0.1.
Sequence Number
Sequence number Storing Strategy
Sequence number should be non-volatile, software stacks should make sure that every time the device sends a valid packet, it should never use the sequence numbers which had been already used before, so it would be a good way to store it in the flash. However, writing flash once per each sequence number increment is probably too often so that the flash may easily wear out before the life time of the real product. To balance the impact, the stack will only write the sequence number to flash at a fixed interval when the sequence number increases by pstore_write_interval_elem_seq times, which is adjustable and located in the dcd.c file in your project. Given that there is a chance that the device may loss power unexpectedly before the interval, which means the real sequence number has not been written to flash, next time when the device boots, it will use the old value in the flash. To avoid the node uses any old sequence number, the node will always increase pstore_write_interval_elem_seq after reset. Besides, the stack will detect if there is valid sequence number increasing between the 2 times of reset, if no, the stack won't increase the sequence number. For more information, you can refer to the example in Figure 1.
NOTE: This is not standard but Silicon Labs' current solution and it may change in the future.
IV Index
Environments
IV Update & Recovery Introduction
IV Update & Recovery Procedure
IV Update Procedure:
The sequence number is 24-bit length, as the example provided above, with 5 seconds cadence, the sequence number will repeat after 2.6 years. To avoid this, the node could start the IV update procedure to update the network to a new IV index so that the sequence number could be reset to 0. The IV update procedure can be initiated by any node in the primary subnet. Table 1 shows the summary of IV update procedure.
Table 1: IV Update procedure summary
IV Recovery Procedure:
A node shall support the IV index recovery procedure because a node that is away from the network for a long time may miss IV Update procedures, in which case it can no longer communicate with the other nodes. In order to recover the IV Index, the node must listen for a Secure Network beacon, which contains the Network ID and the current IV Index.
IV Update & Recovery Limitations
There are some limitations on initiating IV update and recovery procedure, mentioned in chapters 3.10.5 and 3.10.6 of Mesh Profile Specification v1.0.1. Generally, as below:
IV Test Mode
Because the limitations mentioned above, it's not easy to test the IV update & recovery procedure. So the IV test mode removes the 96 hours limit. All other behavior of the devices remains unchanged.
Secure Network Beacon
The secure network beacon must be enabled to do the IV update & recovery since it's the carrier of the information that a node is updating the IV index.
NOTE: the Bluetooth Mesh app may not support to configure the secure network beacon state, so you may need to enable it locally with the mesh test class commands. If using the Host Provisioner, then it's not a problem since it supports that.
Running The Example
The example contains two projects - iv_update and iv_recovery, they needs to work together to show how the IV update & recovery procedure works, as well as showing the sequence number storing strategy. Let's call the node flashed with iv_update firmware node U, and the node flashed with iv_recovery firmware node R.
BGAPI Commands & Events
Below is a list of BGAPI commands and events related to the IV update & recovery procedure, all of which are demonstrated in the example.
Commands:
Events:
Import The Projects
Behaviors of The Example
As you can see from the last section that the examples are based on the light and switch examples, so they still keep the basic functionalities and behaviors as the original example. What is modified is listed below:
On the Node U side - iv_update project:
On the Node R side - iv_recovery project:
Test The Sequence Number Increasing
Every time the node U boots and if the node is provisioned, it will print the current and remaining sequence number. Every time any button is pressed to send a packet, the current and remaining sequence number will be printed. You can try to send some packets then reset the device to see what happens. How about if not send packets but reset the node directly? See the result in Figure 1, the pstore_write_interval_elem_seq here is 0x10000.
Figure 1. Sequence Number Increasing
Test IV Update & Recovery
Figure 2 shows the procedure of IV update and IV recovery, there are 2 nodes in the same network, as you can see from figure 1, on the left side, it's the print of the node which initiates IV update procedure, this is node U, on the right side, it's the print of the node which catches up the IV update, this is node R. There are 4 times of the IV update & recovery procedure, describing below:
Figure 2. IV Update & Recovery Procedure