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.
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
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);
CThe 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
CNote: 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;
C2.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};
CWe 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
.
BT_DATA(BT_DATA_MANUFACTURER_DATA,(unsigned char *)&adv_mfg_data, sizeof(adv_mfg_data)),
C4. 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;
}
CIt 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 -1;
}
C5. 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()
.
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));
}
}
CIn the callback function, we will do the following:
if (has_changed & button_state & USER_BUTTON)
e
count of the number of presses: adv_mfg_data.number_press += 1;
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.
In the SCANNER tab, press on the SCAN button to begin scanning
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 Manufacturer 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 or Manufacturer data (Bluetooth Core 4.1).
Data shown as Manufacturer data (Bluetooth Core 4.1)
Changing data to Unsigned int 16
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.
In the Scanner tab, select the play icon to begin scanning
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.