Bluetooth OTA Updates Using Customized Advertising Data

Introduction

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
02010604094F5441

The advertising packet includes only two elements:

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

Bluetooth advertising data basics

To implement a robust OTA update procedure, use a customized advertising data format, for example:

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.

Usage: 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.

ota_name_config.png

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

To use a unique device name that is specified by the OTA update client (the smartphone that performs OTA), 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 structure. 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 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 le_gap_bt5_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, see BGAPI reference manual.

The following code snippet shows how to set custom advertising packet that is used during OTA mode. In this example, a simple packet format is used 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;  /*  Silicon Labs 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_bg5_set_adv_data(2, sizeof(tsCustomAdv), (uint8*)&sData);

    return;
}

The structure tsCustomAdv defines 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.

The 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:

02010609FFFF023B8815570B00

(Note the byte order in the BT address is the least significant byte first)

OTA advertising data set as shown above is stored permanently in Persistent Storage. Therefore, 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);