Exercise 2

Dynamically changing the advertising data

In this exercise, we will build on top of the previous exercise to focus on advertising parameters, Manufacturer Specific Data, and updating the advertising data dynamically.

We will still broadcast non-connectable advertising in this exercise. However, as opposed to the previous exercise, we will not use a predefined macro to manage the advertising parameters and fine-control the advertising interval.

We will also learn how to dynamically change the content of advertising data. We will create custom advertising data that represents how many times Button 1 is pressed on the board and we will include it in the advertising packet.

Exercise steps

In the GitHub repository for this course, go to the base code for this exercise, found in lesson2/blefund_less2_exer2.

1. Create the variable adv_param of type bt_le_adv_param.

This variable type can control many aspects of advertising. Let’s see how we can use it to control the advertising interval.

To create the variable, we will be using the helper maco BT_LE_ADV_PARAM(), which has the following signature

BT_LE_ADV_PARAM() helper macro
  • Advertising options: Specific macros to configure the advertising options. For example, choosing which channel (37, 38, 39) to advertise on. There are 19 options available, found here.
  • Minimum advertising interval: (N * 0.625 milliseconds): Less than or equal to the maximum advertising interval. The allowable range for N is 32 to 16384, which translates to 20 ms to 10.24 seconds. The API has predefined values to use for advertising intervals.
  • Maximum advertising interval: (N * 0.625 milliseconds): Larger than or equal to the minimum advertising interval. The allowable range for N is 32 to 16384, which translates to 20 ms to 10.24 seconds. The API has predefined values to use for advertising intervals.
  • Peer address: Included if directed advertising is used. Otherwise, set to NULL.

Add the following lines in main.c

static struct bt_le_adv_param *adv_param =
	BT_LE_ADV_PARAM(BT_LE_ADV_OPT_NONE,
	800,
	801,
	NULL);

The above code will set the advertising interval to about 500 ms (500 ms/0.625 ms =800 (N)). As we discussed before, there will be a random delay added to avoid packet collisions.

2. Declare the Manufacturer Specific Data

Manufacturer Specific Data is used to create and include custom data in Bluetooth LE advertising. The data to be included can be in any format suitable for your use case/application. 

2.1 Declare the Company identifier (Company ID)

The first two bytes in the Manufacturer Specific Data are the company identifier as registered in Bluetooth SIG in the Assigned Numbers Document. For educational/testing purposes, we will use Nordic Semiconductor Company Identifier.

Add the following line in main.c

#define COMPANY_ID_CODE            0x0059

Note:  Bluetooth LE products are not allowed to broadcast a custom company ID without being a Bluetooth SIG member. When you are ready to release your product, you would have to apply for a Bluetooth SIG membership to get your own unique Company ID.

2.2 Declare the structure for your custom data

In this exercise, we will keep it simple and declare our custom data as unsigned short(2 bytes). The data will represent how many times Button 1 is pressed. Therefore we will create a structure adv_mfg_data_type that has two members. The first is, of course, the Company ID and the second is number_press which represents how many times button 1 is pressed on the board.

Add the following struct definition to main.c

typedef struct adv_mfg_data {
	uint16_t company_code;	    /* Company Identifier Code. */
	uint16_t number_press;      /* Number of times Button 1 is pressed*/
} adv_mfg_data_type;

2.3 Define and initialize a variable of type adv_mfg_data_type that we created in the previous step.

static adv_mfg_data_type adv_mfg_data = {COMPANY_ID_CODE,0x00};

We are all set with the Manufacturer Specific Data declaration. In the next step, we will add a button press callback function that updates the number_press and update the advertising data through the function bt_le_adv_update_data().

3. Include the Manufacturer Specific Data in the advertising packet.

Add the following line inside the definition of the advertising packet ad .

4. Initialize the Buttons library and set a callback function.

4.1 We will use the DK Buttons and LEDs library to setup an interrupt (call back function) to be called every time Button 1 is pressed.

Add the init_button() function definition in main.c .

static int init_button(void)
{
	int err;

	err = dk_buttons_init(button_changed);
	if (err) {
		printk("Cannot init buttons (err: %d)n", err);
	}

	return err;
}

It calls the dk_buttons_init() function to initialize your board’s buttons and assign the button_changed() , which will be defined in step 5, as a call back function every time a button is pressed.

4.2 Call init_button() in main()

Add the following line in main()

	err = init_button();
	if (err) {
		printk("Button init failed (err %d)n", err);
		return;
	}

5. Add the definition of the callback function and update the advertising data dynamically.

We will update the advertising data dynamically from inside the button_changed() callback function. We will use the function bt_le_adv_update_data().

bt_le_adv_update_data() API Function

The bt_le_adv_update_data() is very similar to the bt_le_adv_start() that we covered in the previous exercise, except it does not take Advertising Parameters options. It relies on the advertising parameters set before in bt_le_adv_start().

Add the definition of the button callback function.

static void button_changed(uint32_t button_state, uint32_t has_changed)
{
	if (has_changed & button_state & USER_BUTTON) {
	adv_mfg_data.number_press += 1;
	bt_le_adv_update_data(ad, ARRAY_SIZE(ad),
			      sd, ARRAY_SIZE(sd));
	}
}

In the callback function, we will do the following:

  • Check which button was pressed: if (has_changed & button_state & USER_BUTTON)
  • Update the count of the number of presses: adv_mfg_data.number_press += 1;
  • Update the advertising data dynamically bt_le_adv_update_data(ad, ARRAY_SIZE(ad),sd, ARRAY_SIZE(sd));

6. Build and flash the application on your board.

You should notice that LED1 on your board is blinking now. Indicating that your board is advertising.

7. Open nRF Connect for Mobile on your smartphone.

Android

In the SCANNER tab, press on the SCAN button to begin scanning

Android

Notice how the connection interval has changed from the previous exercise which was between 100-150 ms associated with the BT_LE_ADV_NCONN macro to around 500ms.

8. Tap on Nordic_Beacon to view the advertising data.

You should notice now that the Manufactured data is included in the advertising With the company ID of Nordic Semiconductor.

9. Tap on the Manufacturer data to change how the data is displayed and select Unsigned Int16

The data will be shown as Unsigned Int 16:

10. Press Button 1 on your board

You should observe that the count increments by one every time the button is pressed. You need to be in scanning mode on your phone to see the change. Press SCAN at the top right corner in nRF Connect for Mobile to see the updated data.

By default, the scanning period on nRF Connect for Mobile is set to 45 seconds. You can change the scanning period by going to Settings->Scanner->Scanning Period.

iOS

In the Scanner tab, select the play icon to begin scanning

iOS

Notice how the connection interval has changed from the previous exercise which was between 100-150 ms associated with the BT_LE_ADV_NCONN macro to around 500ms.

8. Use the filter to only see the Nordic_Beacon device

In the Scanner tab, select the filter and type Nordic_Beacon in the Name field.

Now you should only see the Nordic_Beacon device in the Scanner tab.

Notice the Manufacturer Specific data is 0000.

9. Press Button 1 on your board.

This will increment the Manufacturer Specific data by 1.

10. Start scanning for devices

To be able to see this change, you need to start scanning again on your phone. You can do this by sliding down in the Scanner window, to see the following window

Now you will notice that the data has increased by 1.

Bluetooth LE uses little endianness to represent the data in GAP and GATT layers, which is why it increments from 0x00 00 to 0x01 00, etc.

Make sure to turn off the filter before proceeding to the next exercise.

Register an account
Already have an account? Log in
(All fields are required unless specified optional)

  • 8 or more characters
  • Upper and lower case letters
  • At least one number or special character

Forgot your password?
Enter the email associated with your account, and we will send you a link to reset your password.