3. Changing Advertising Parameters

This section describes how to change the advertising parameters on a DA14585/86 or DA14531 device. It covers all the key elements related to advertising, specifically dealing with Advertising Data and Advertising Intervals, as well as the Advertising Channel Map and Advertising Mode.

3.1. Changing the Advertising Data

_images/Picture4.jpg

Figure 8 Default Advertising Data

  1. In user_config.h, change the contents of the existing USER_ADVERTISE_DATA macro to the desired Advertising Data.

    Figure 9 shows how to change the Advertising Data. Since the advertising string should have a specific format, you could use the ADV_TYPE_MANUFACTURER_SPECIFIC_DATA macro to add any custom data you wish into the advertising packets, as further explained in step 2.

_images/Picture5.jpg

Figure 9 Changing the Manufacturer Specific Data

The following sample code demonstrates setting some custom Advertising Data. It sets the full device name to THIS-IS-DIALOG.

Code snippet:

  /// Advertising data
#define USER_ADVERTISE_DATA      "\x11"\
                                  ADV_TYPE_MANUFACTURER_SPECIFIC_DATA\
                                  ADV_DIALOG_MANUFACTURER_CODE\
                                  "THIS-IS-DIALOG"

2. Commonly, the Advertising Data includes some manufacturer specific data. These data are fully customizable in the header file user_barebone.h, as illustrated below:

Code snippet:

/* Manufacturer specific data constants */
#define APP_AD_MSD_COMPANY_ID               (0xFEDE)
#define APP_AD_MSD_COMPANY_ID_LEN           (2)
#define APP_AD_MSD_DATA_LEN                 (sizeof(uint16_t))

We can change the company data to FEDE as shown in Figure 10 (screenshot from a BLE Scanner).

Code snippet:

/* Manufacturer specific data constants */
#define APP_AD_MSD_COMPANY_ID               (0xFEDE)
_images/Picture6.jpg

Figure 10 Manufacturer Specific Data Constants

When the device is ready to start advertising, it calls mnf_data_init() in user_app_init(). This function sets some standard parameters so that the device will publicly broadcast its Advertising Data. The data to be advertised are copied from the struct mnf_specific_data_ad_structure. Finally, the device is asked to start advertising based on this configuration.

Code snippet:

void user_app_init(void)
{
    app_param_update_request_timer_used = EASY_TIMER_INVALID_TIMER;

    // Initialize Manufacturer Specific Data
    mnf_data_init();

    // Initialize Advertising and Scan Response Data
    memcpy(stored_adv_data, USER_ADVERTISE_DATA, USER_ADVERTISE_DATA_LEN);
    stored_adv_data_len = USER_ADVERTISE_DATA_LEN;
    memcpy(stored_scan_rsp_data, USER_ADVERTISE_SCAN_RESPONSE_DATA, USER_ADVERTISE_SCAN_RESPONSE_DATA_LEN);
    stored_scan_rsp_data_len = USER_ADVERTISE_SCAN_RESPONSE_DATA_LEN;

    default_app_on_init();
}

Code snippet:

/**
 ****************************************************************************************
 * @brief Initialize Manufacturer Specific Data
 * @return void
 ****************************************************************************************
 */
static void mnf_data_init()
{
    mnf_data.ad_structure_size = sizeof(struct mnf_specific_data_ad_structure ) - sizeof(uint8_t);
                                                // minus the size of the ad_structure_size field
    mnf_data.ad_structure_type = GAP_AD_TYPE_MANU_SPECIFIC_DATA;
    mnf_data.company_id[0] = APP_AD_MSD_COMPANY_ID & 0xFF; // LSB
    mnf_data.company_id[1] = (APP_AD_MSD_COMPANY_ID >> 8 )& 0xFF; // MSB
    mnf_data.proprietary_data[0] = 0;
    mnf_data.proprietary_data[1] = 0;
}

Note

When the device is ready for advertising, we may want it to call a custom function to handle the Advertising Data. The barebone example periodically updates the Advertising Data and it demonstrates how the advertising contents can be handled using a user-defined function. In this case, we have to modify the appropriate callback function in user_callback_config.h, as in the code example below which uses the function user_app_adv_start.

user_app_adv_start() is a user defined function in the user application layer and does the following:

  • Starts an application timer with timeout APP_ADV_DATA_UPDATE_TO.

  • Updates the Manufacturer Data included in the Advertising Data, see Changing the Advertising Data.

  • Starts the Advertising.

Code snippet:

// Default Handler Operations
static const struct default_app_operations user_default_app_operations = {
    .default_operation_adv = user_app_adv_start,
};

See also

The DA14585/586 and DA14531 devices may receive Scan Requests from the Central device in order to transmit additional user data by means of a Scan Response. The Scan Response usually has more data than the advertising packets and can vary in length from 8 to 39 bytes, because the Advertising Data is typically chosen to be very short to minimize power consumption. For more information, we recommend reading about Scan Response packets in the SIG core specification.

3.2. Changing the Advertising Interval

The Advertising Interval is the period between two consecutive advertisements of a Bluetooth Low Energy peripheral.

This interval can be customized in the file user_config.h. The default value is set to 687.5ms.

Code snippet:

static const struct advertise_configuration user_adv_conf = {

    .addr_src = APP_CFG_ADDR_SRC(USER_CFG_ADDRESS_MODE),

    /// Minimum interval for advertising
    .intv_min = MS_TO_BLESLOTS(687.5),                    // 687.5 ms

    /// Maximum interval for advertising
    .intv_max = MS_TO_BLESLOTS(687.5),                    // 687.5 ms
   ....

The following example changes the update timer to 1500ms.

Code snippet:

/// Minimum interval for advertising
.intv_min = MS_TO_BLESLOTS(1500),                    // 1500 ms

/// Maximum interval for advertising
.intv_max = MS_TO_BLESLOTS(1500),                    // 1500 ms

Note

From the Bluetooth Specification (Vol 6, Part B, section 4.4.2.2.1 Advertising Interval) The advInterval shall be an integer multiple of 0.625ms in the range of 20ms to 10.24s.

3.3. Changing the Advertising Channel Map

The band defined in the Bluetooth Core Specification consists of 37 data communication channels and three advertising channels for Device Discovery. The latter are allocated in non-consecutive parts of the spectrum to prevent interference from concurrent activities in the ISM Band. Specifically, a Bluetooth Low Energy device can advertise on channels 37, 38, and 39 which correspond to frequencies of 2.402 MHz, 2.2426 MHz, and 2.480 MHz respectively. SmartBond™ devices advertise successively on all enabled channels.

By default, all channels are enabled with the assignement .channel_map = ADV_ALL_CHNLS_EN. To force the Bluetooth Low Energy device to use only one channel, for example channel 37, use the assignment .channel_map = ADV_CHNL_37_EN.

Code snippet:

static const struct advertise_configuration user_adv_conf = {
   .....

    /**
     *  Advertising channels map:
     * - ADV_CHNL_37_EN:   Advertising channel map for channel 37.
     * - ADV_CHNL_38_EN:   Advertising channel map for channel 38.
     * - ADV_CHNL_39_EN:   Advertising channel map for channel 39.
     * - ADV_ALL_CHNLS_EN: Advertising channel map for channel 37, 38, and 39.
     */
    .channel_map = ADV_CHNL_37_EN,
Table 4 Advertising Channels

Enumeration Name

Value

Description

ADV_CHNL_37_EN

0x01

Select channel 37 for advertising

ADV_CHNL_38_EN

0x02

Select channel 38 for advertising

ADV_CHNL_39_EN

0x04

Select channel 39 for advertising

ADV_ALL_CHNLS_EN

0x07

Select all channels (37, 38, and 39) for advertising

3.4. Changing the Advertising Mode

The Advertising Mode is customizable by calling one of these API functions in sdk/app_modules/src/app_common/app.c:

  • void app_easy_gap_undirected_advertise_start()

  • void app_easy_gap_directed_advertise_start(uint8_t ldc_enable)

  • void app_easy_gap_non_connectable_advertise_start(void)

To start advertising, use the GAPM_START_ADVERTISE_CMD definition and send it to the GAP manager layer (GAPM). A message is allocated using the KE_MSG_ALLOC macro.

/**
 ****************************************************************************************
 * @brief Create a start advertise message.
 * @return The pointer to the created message.
 ****************************************************************************************
 */
__INLINE struct gapm_start_advertise_cmd* app_advertise_start_msg_create(void)
{
    struct gapm_start_advertise_cmd* cmd = KE_MSG_ALLOC(GAPM_START_ADVERTISE_CMD,
                                                        TASK_GAPM,
                                                        TASK_APP,
                                                        gapm_start_advertise_cmd);

    return cmd;
}

To start an undirected GAPM_ADV_UNDIRECT advertising operation, fill the message with the necessary data: cmd = app_easy_gap_undirected_advertise_start_create_msg();

void app_easy_gap_undirected_advertise_start(void)
{
    struct gapm_start_advertise_cmd* cmd;
    cmd = app_easy_gap_undirected_advertise_start_create_msg();

    // Send the message
    app_advertise_start_msg_send(cmd);
    adv_cmd = NULL ;

    // We are now connectable
    ke_state_set(TASK_APP, APP_CONNECTABLE);
}


/**
 ****************************************************************************************
 * @brief Create advertising message for connectable undirected event (ADV_IND).
 * @return gapm_start_advertise_cmd Pointer to the advertising message
 ****************************************************************************************
 */
static struct gapm_start_advertise_cmd* app_easy_gap_undirected_advertise_start_create_msg(void)
{
        .....
        struct gapm_start_advertise_cmd *cmd;
        cmd = app_advertise_start_msg_create();
        adv_cmd = cmd;

        cmd->op.code = GAPM_ADV_UNDIRECT;
        cmd->op.addr_src = user_adv_conf.addr_src;
        cmd->intv_min = user_adv_conf.intv_min;
        cmd->intv_max = user_adv_conf.intv_max;
        .....
}

Then send it to the GAPM task, from the user_barebone.c. The application layer is informed by calling the app_easy_gap_undirected_advertise_start() in user_app_adv_start. The other advertising modes are described in Table 5.

Table 5 Advertising Modes

Enumeration Name

Description

GAPM_ADV_NON_CONN

The Bluetooth Low Energy device advertises without permitting a connection to another central device.

GAPM_ADV_UNDIRECT

The Bluetooth Low Energy device advertises towards all devices regardless of their BD address

GAPM_ADV_DIRECT

The Bluetooth Low Energy device advertises towards a device with a specific BD address.

GAPM_ADV_DIRECT_LDC

The Bluetooth Low Energy device advertises towards a device with a specific BD address using Low Duty Cycle.

3.5. Changing the Advertising Data On the Fly

The barebone example updates the Advertising Data, and more specifically the Manufacturer Specific Data, while the device is operating. The function that updates the Manufacturer Specific Data can be seen below:

/**
 ****************************************************************************************
 * @brief Update Manufacturer Specific Data
 * @return void
 ****************************************************************************************
 */
static void mnf_data_update()
{
   uint16_t data;

   data = mnf_data.proprietary_data[0] | (mnf_data.proprietary_data[1] << 8);
   data += 1;
   mnf_data.proprietary_data[0] = data & 0xFF;
   mnf_data.proprietary_data[1] = (data >> 8) & 0xFF;

   if (data == 0xFFFF) {
      mnf_data.proprietary_data[0] = 0;
      mnf_data.proprietary_data[1] = 0;
   }
}

This function is called each time a periodic timer fires. This function reads and increments the value of counter, wrapping when the counter reaches the value 0xFFFF. The update takes place in the adv_data_update_timer_cb() callback function.

/**
****************************************************************************************
* @brief Advertisement data update timer callback function.
* @return void
****************************************************************************************
*/
static void adv_data_update_timer_cb()
{
   // If mnd_data_index has MSB set, manufacturer data is stored in scan response
   uint8_t *mnf_data_storage = (mnf_data_index & 0x80) ? stored_scan_rsp_data : stored_adv_data;

   // Update manufacturer data
   mnf_data_update();

   // Update the selected fields of the advertising data (manufacturer data)
   memcpy(mnf_data_storage + (mnf_data_index & 0x7F), &mnf_data, sizeof(struct mnf_specific_data_ad_structure));

   // Update advertising data on the fly
   app_easy_gap_update_adv_data(stored_adv_data, stored_adv_data_len, stored_scan_rsp_data, stored_scan_rsp_data_len);

   // Restart timer for the next advertising update
   app_adv_data_update_timer_used = app_easy_timer(APP_ADV_DATA_UPDATE_TO, adv_data_update_timer_cb);
}

When we have updated the data, we have to call the app_easy_gap_update_adv_data() function. This code informs the BLE layer that there are updated advertising data and queues the update at the next available opportunity.