Dynamic Advertising Data¶
We just explored how we can create the advertised BD name at runtime. Advertising data can contain multiple segments of various other data types, and some of those can carry dynamic application data - meaning data that changes over time. The dynamic data could be sensor data or other data that it makes sense to advertise. The advantage of advertising sensor data is that we can transmit the data without the requirement to enter into a BLE connection. By advertising our data, we can make it available to an infinite number of central devices, such as smartphones, simultaneously.
Typically, dynamic advertising data is provided in one of the following advertising data types:
GAP_AD_TYPE_SERVICE_16_BIT_DATA
, 16bit UUID service data which is used when the data is associated with a Bluetooth® SIG adopted profileGAP_AD_TYPE_SERVICE_128_BIT_DATA
, 128bit UUDI service data which is used for custom service data and is available without restrictionsGAP_AD_TYPE_MANU_SPECIFIC_DATA
, Manufacturer specific data which requires a 16bit Company identifier registered with the Bluetooth® SIG
我们将使用128位UUI unrestricetedD service advertising data type in the following. The methods demonstrated will work equally well with any of the other types as long as you adhere to their specific restrictions.
The 128bit UUID service data segment consists of 4 parts:
The one octet length of the segment excluding the length field itself
The advertising data type,
GAP_AD_TYPE_SERVICE_128_BIT_DATA
The 128bit (16 octets) universally unique identifier or UUID
The value of the data that we want to advertise.
In the previous part of the tutorial, we demonstrated how to set the BD name at runtime. In order to simplify this part of the tutorial, we will revert back to default advertising, and let the SDK construct the full advertising package.
Inuser_callback_config.h, change the following declaration (highlighted portion)
staticconst结构体default_app_operationsuser_default_app_operations={.default_operation_adv=user_advertise_operation,};
to this:
staticconst结构体default_app_operationsuser_default_app_operations={.user_operation_adv=default_advertise_operation,};
Note
我们恢复到默认的广告后,BD name will also revert back to the “smiley with shades” emoji.
We will, as mentioned previously, use theGAP_AD_TYPE_SERVICE_128_BIT_DATA
to advertise dynamic data. Our data will be a simple counter of one octet that we will increment using a timer. We will just randomly generate a UUID for the data. We can now calculate the length field as follows:
1 octet data type (
GAP_AD_TYPE_SERVICE_128_BIT_DATA
is defined ingap.has 0x21)16 octets UUID (We will use 0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11)
1 byte of data (We will start with a value of 0x00)
The length field must therefore be 18 octets or 0x12 for those of us who are addicted to hexadecimal notation.
Formatted as a string, the data will look like this:
\x12\x21\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x00
Inuser_config.h, insert this string into the
USER_ADVERTISE_DATA
definition:
#define USER_ADVERTISE_DATA "\x18\x21\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x00"
We will need to keep our counter value retained during sleep. Inuser_empty_periphral_template.c, right below the include statements, add the following:
uint8_tmy_counter__SECTION_ZERO("retention_mem_area0")=0;// @RETENTION MEMORY
We will have to initialize our counter. To do this we will re-route the.app_on_init
callback to user space.
Inuser_callback_config, change the callback from
default_app_on_init
touser_app_on_init
:
staticconst结构体arch_main_loop_callbacksuser_app_main_loop_callbacks={.app_on_init=user_app_on_init,~
Now, add a prototype to this function at the bottom ofuser_peripheral_template.h:
voiduser_app_on_init(void);
This gives us a function that we can use for initialization of our global variable as well as starting our data update timer. At the bottom ofuser_peripheral_template.c, add the following code:
voiduser_app_on_init(){mycounter=0;app_easy_timer(100,update_adv_data)// One second one-shot timer// After we have initialized our variable, we call the default handlerdefault_app_on_init();}
We can then implement our timer handler just above this function:
voidupdate_adv_data(){my_counter++;// Copy the counter value into the advertising data (ignore the scan response data)uint8_tadv_data[USER_ADVERTISE_DATA_LEN];memcpy(&adv_data,USER_ADVERTISE_DATA_LEN,USER_ADVERTISE_DATA_LEN);// Load the counter value into the last octet of the advertising dataadv_data[USER_ADVERTISE_LEN-1]=my_counter;// Update the advertising dataapp_easy_gap_update_adv_data(adv_data,USER_ADVERTISE_DATA_LEN,NULL,NULL);// Restart the timerapp_easy_timer(100,update_adv_data)// One second one-shot timer}