KB: Advertising RSL10 as an Accessory to iOS

[RSL10 - Knowledge Base]

By design, there are specific advertising guidelines that you are required to follow to avoid being filtered by an iOS device. This is intended partially as a security measure within the Apple ecosystem, but also to set a standard regarding the information that a Peripheral device must provide to the Central. We will discuss the two mandatory advertising configurations required to appear on the default iOS Bluetooth Scanner below.

Advertising Packet & Scan Response

Per Apple’s Guidelines, advertising packets and scan response packets sent out by Peripheral Accessories are required to include several parameter values shared between the two, as well as the corresponding flags indicating that these parameters are present. A list of the parameters and values that are required is shown below:

  • Flags
  • Accessory Primary Service UUID
  • Transmit Power
  • Device Complete/Shortened Local Name

Our Bluetooth Low Energy stack and abstraction code offers a straightforward method of preparing these advertising and scan response packets, so that they can easily be included within the Advertising command itself. A snippet of code that outlines the process of creating these packets for the Heart Rate Profile Service is provided below:

    /* Union passed to the Stack when issuing a GAPM_START_ADVERTISE_CMD */
    union gapm_adv_info app_adv_info;

    uint8_t hrp_uuid[2]  = { 0x0D, 0x18 }; /* 16-bit HRP Service UUID*/

    /* Set advertising data as service UUID */
    app_adv_info.host.adv_data_len = 0;
    GAPM_AddAdvData(GAP_AD_TYPE_SERVICE_16_BIT_DATA, hrp_uuid,
                    sizeof(hrp_uuid), app_adv_info.host.adv_data,

    uint8_t tx_power[1] = { 0 }; /* Transmission Power of the Peripheral Device*/
    uint8_t dev_name[20]   = "PeripheralHeartRate"; /* Complete Local Device Name */

    /* Set scan response data as TX Power and Complete Device Name */
    app_adv_info.host.scan_rsp_data_len = 0;
					sizeof(tx_power), app_adv_info.host.scan_rsp_data,
                    sizeof(dev_name)-1, app_adv_info.host.scan_rsp_data,

Private Resolvable Address (PRA)

To enhance the security of the Apple Environment further, your Peripheral Accessory is required to make use of a Private Resolvable Address type. This type of address reduces the probability that your device can be tracked via its Advertising address, by requiring new random addresses to be generated and set on a certain time interval. This address type is also Resolvable, which means it can exchange security keys with a Central and save the information for later connectivity, removing the need to share keys again and allowing the Central iOS to immediately resolve the Accessories’ true address in the future. More information about PRA and other Address Types is available in the CEVA RW-BLE-GAP-IS_2mbps document, found in our RSL10 Documentation Package.

Below is another code snippet, which outlines the specific parameter and value changes required within the structures passed into the stack, resulting in:

  • Properly initializing the address type within the device configurations
  • Properly pack the advertising command with the address type
  • Assign the app_adv_info.host.adv_data and app_adv_info.host.scan_rsp_data data, packed in the code above, to be sent out during advertising operations
/* Structure passed to the Stack on BLE Device Configuration */
struct gapm_set_dev_config_cmd devConfigCmd =
    .renew_dur = 150, /* Renewal Duration in Seconds */
    .addr_type = GAPM_CFG_ADDR_HOST_PRIVACY, /* Private Resolvable  Address Type */

/* Structure passed to the Stack on BLE Advertising Start*/
struct gapm_start_advertise_cmd advertiseCmd =
    .op = {
         /* Address Type of this device is Private Resolvable */
        .addr_src = GAPM_GEN_RSLV_ADDR, 
    .info.host = {
        /* Advertising data as set above */
        .adv_data = app_adv_info.host.adv_data, 
        /* Advertising data length as set above */
        .adv_data_len = app_adv_info.host.adv_data_len, 
        /* Scan response data as set above */
        .scan_rsp_data = app_adv_info.host.scan_rsp_data, 
        /* Scan response data length as set above */
        .scan_rsp_data_len = app_adv_info.host.scan_rsp_data_len,