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 profile

  • GAP_AD_TYPE_SERVICE_128_BIT_DATA, 128bit UUDI service data which is used for custom service data and is available without restrictions

  • GAP_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_DATAto 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_DATAis 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 theUSER_ADVERTISE_DATAdefinition:

#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_initcallback to user space.

  • Inuser_callback_config, change the callback fromdefault_app_on_inittouser_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}