Bluetooth OTA updates using customized advertising data

by <a href=""><font color="#000000"><font size="2">Legend Employee</font></font> </a> JaakkoV on ‎08-25-2017 03:04 AM



When a device is booted into OTA DFU mode, the default advertising data that is used by the BLE stack is very minimal. Below is an example that was created by booting the soc-smartPhone example (from SDK 2.4.2) into OTA mode:



// raw advertising data


 The advertising packet includes only two elements: 

  • flags (value 0x06) 
  • complete local name ("OTA")


For details on how to decode the advertising packet content, see following article:


To implement a robust OTA update procedure you may want to use some customized advertising data format, for example:

* include a unique device name in the OTA advertising packets

* indicate the current SDK/stack version in the advertising packets


These customizations are left for the application designer to decide. Silicon labs Bluetooth stacks includes a few simple yet powerful options to customize the advertising packets used in OTA mode. These options are explained below.


Setting the device name in OTA


The simplest option is to configure the device name that is inserted into OTA advertising packets. There are two ways to do this.


1) Setting the OTA name in the initial stack configuration


The Bluetooth stack is initialized by calling gecko_init() which takes a set of configurations as a parameter. The following code snippet from soc-smartPhone example shows how the name is set.




This method is really simple to use. However, it is somewhat limited because the name needs to be static and known when the stack is initialized.


If you for example need to use a unique device name that is specified by the OTA update client (the smartphone that performs OTA), then this option is not feasible.


2) Setting the OTA name at runtime


An alternative method for setting the OTA device name is using the BGAPI command cmd_system_set_device_name



// setting OTA name at runtime
gecko_cmd_system_set_device_name(0, 3, "OTA");

The code snippet shown above has the same effect as specifying a static name "OTA" in the gecko_configuration_t struct. However, this method makes it possible to use a dynamic name that is generated at runtime, while the Bluetooth stack is running. The device name to be used during OTA may be for example negotiated between the OTA client and the OTA target device over a Bluetooth connection.



Setting the OTA advertising packet content manually


It is also possible to define the whole content of the OTA advertising packets from the application. This feature is enabled starting from SDK 2.4.2. 


This method can be used if for example you want to include the OTA service UUID in the advertising packets that are sent during OTA mode. There are basically no limitations on what advertising data can be used, as long as it conforms to the Bluetooth specification.


Custom OTA advertising data can be set using the BGAPI call gecko_cmd_le_gap_set_adv_data. In normal operation (no OTA), this API call is used to define custom advertising data or scan response content. It can be also used to set the OTA time advertising data by setting the first parameter scan_rsp to value 2. For more details, refer to BGAPI reference manual.


The following code snippet shows how to set custom advertising packet that is used during OTA mode. In this example, we are using a simple packet format that includes one manufacturer specific AD element. The custom AD element is used to expose the Bluetooth address of the device.



typedef struct
	/* first AD element : Flags*/
	uint8 len_flags;
	uint8 type_flags;
	uint8 val_flags;

	/* for the second element, let's use a custom AD element */
	uint8 len_manuf;
	uint8 type_manuf;
	uint8 company_LO;
	uint8 company_HI;

	uint8 bt_address[6]; /* show BT address in the advertising data */

} tsCustomAdv;

void configure_OTA_adv()
	struct gecko_msg_system_get_bt_address_rsp_t* pAddr;
	tsCustomAdv sData;

	/* fill the first element (flags) */
	sData.len_flags = 0x02;
	sData.type_flags = 0x01;
	sData.val_flags = 0x06;

	/* fill the second AD element (custom) */
	sData.len_manuf = 1+2+6; /* length, including: type + companyID + BT address */
	sData.type_manuf = 0xFF;
	sData.company_LO = 0xFF;
	sData.company_HI = 0x02;  /*  silabs id 0x02FF */

	/* check our own BT address and add it to the advertising data */
	pAddr = gecko_cmd_system_get_bt_address();
	memcpy(sData.bt_address, pAddr->address.addr, 6);

	/* first parameter scan_rsp = 2 means we configure the OTA advertising data */
	gecko_cmd_le_gap_set_adv_data(2, sizeof(tsCustomAdv), (uint8*)&sData);




The struct tsCustomAdv is used to define our custom advertising data packet content. It is formatted according to the Bluetooth specification. There are two AD elements, each element beginning with a length indicator byte followed by the AD type indicator.


Function configure_OTA_adv() fills the advertising data content and then tells the stack to use this data during OTA mode. Most of the advertising data content in this example is static, except for the Bluetooth device address that is queried from the stack.


This code can be called for example from the system_boot event handler.


Following log from a test run shows how the advertising data is formatted in normal mode and after rebooting into OTA mode. This test was done by inserting the above code snippet into the soc-smartPhone example.



# advertising packets in normal mode
[1] 00:0b:57:15:88:3b RSSI:-47 Name:BG34875 020106050309180218080942473334383735
# connect to the device and enter OTA mode
[1] 00:0b:57:15:88:3b RSSI:-47 Name:Unknown 02010609FFFF023B8815570B00
[1] 00:0b:57:15:88:3b RSSI:-46 Name:Unknown 02010609FFFF023B8815570B00


As shown in the above example, the advertising data in OTA mode follows our custom format. In this case, the BT device address is 00:0B:57:15:88:3B and thus the advertising payload becomes: 


 (note the byte order in the BT addrress is least significant byte first)


The OTA advertising data set as shown above is stored permanently in Persistent Storage. Therefore the data will remain even if you remove or disable the call to configure_OTA_adv()  in the application code. To remove the custom advertising data it must be wiped from the persistent storage. One way to do this is to set a custom OTA advertising data with length of zero bytes as follows:



// remove previously configured OTA advertising content:
uint8 dummy;
gecko_cmd_le_gap_set_adv_data(2, 0, &dummy);





by <a href=""><font color="#000000"><font size="2">Genius</font></font> </a> PascalJedi
on ‎08-30-2017 12:32 AM

First, thank you guys for quickly adding this capability to the stack.  It really will help a lot of developers making OTA systems. 


Second, obiligatory snarky programmer comment: 


* first parameter scan_rsp = 2 means we configure the OTA advertising data */

2 ??


Typedef Enumerations anyone?  





by <a href=""><font color="#000000"><font size="2">Legend Employee</font></font> </a> JaakkoV
on ‎08-30-2017 12:52 AM

>> Typedef Enumerations anyone?  


Typedef enums are so overrated... 



Robot wink