Introduction

This workshop is a detailed description of how to use the advertising and
scanning features of the TI BLE5-Stack. All tasks in this lab session are
targeted to be completed within a 2-4 hour time frame. You should have an
intermediate level of knowledge of the C programming language as well as
experience with embedded software development to be able to complete the tasks.

The first section describes the GAP layer of the Bluetooth low energy protocol,
and the subsequent tasks will explore the advertising and scanning and how to
make some small changes to the BLE application.

The hardware kits supporting the TI BLE5-Stack are the CC26x2R1 and the CC1352.
For the tasks in this module, a pair of evaluation kits (CC26x2R1 LaunchPads or
CC1352 Launchpads) running TI applications (simple_central and
simple_peripheral) is required.

Hardware

Recommended reading

The GAP chapter of the BLE5-Stack
User's Guide can also provide further insight into the topics discussed in
this Simplelink Academy lab.

Getting started – Desktop

Install the Software

Run the SimpleLink SDK installer. This gives you the SDK with TI-RTOS included
at the default location C:\ti\simplelink_ccxxx2_sdk_1_60_00_xx.

Modify/Load the Software

Load Board #1 with simple_central project that supports the scanning
procedure. The simple_central project is found in the ble5stack examples folder,
e.g. <SIMPLELINK_CC26X2R1_SDK_INSTALL_DIR>\examples\rtos\CC26X2R1_LAUNCHXL\ble5stack\simple_central\tirtos

Load Board #2 with simple_peripheral project that supports the advertising
procedure. The simple_peripheral project is found in the ble5stack examples
folder, e.g. <SIMPLELINK_CC26X2R1_SDK_INSTALL_DIR>\examples\rtos\CC26X2R1_LAUNCHXL\ble5stack\simple_peripheral\tirtos

Note: Be sure to build both the stack and app projects.

The following tasks will show how to modify the above projects to showcase
scanning and advertising features in the respective projects. The user will have
to modify these existing projects in the SimpleLink SDK to experiment
with the tasks.

Background

GAP

The Generic Access Profile (GAP) layer is a top layer in the host protocol stack that
defines how BLE devices behave in standby and connecting states. The purpose of
GAP is to ensure interoperability with other Bluetooth devices. GAP also
describes discovery, link establishment and security procedures. The GAP APIs
can be called from the application layer.

A device that accepts the establishment of an LE physical link using the connection establishment procedure.

CENTRAL

A device that supports that initiates the establishment of a physical connection.

The GAP layer API gives very fine-grained control of the device behavior. To
help using GAP, the BLE5-Stack contains four modules with higher lever APIs the
application can use:

GAP Advertiser

The GAP Advertiser module lets you create advertisement sets. The application
can then enable and disable the sets. This way, the application can quickly
change the advertisement parameters and advertisement data. For example, an
application can create an advertisement set for legacy advertising and one for
long range advertising.

GAP Scanner

GAP Initiator

The initiator module is used to initiate the connection to a peripheral device.
Unlike the GAP Advertiser and GAP Scanner modules, GAP Initiator doesn’t have
any callback function to call or to be called. Only a device initiated with the
GAP Central Role can become an initiator.

GAPBondMgr

The GAP Bond Manager is a configurable module that offloads most of the security
mechanisms from the application.

In this Simplelink Academy lab, we will elaborate on the the gap_advertiser
and the gap_scanner modules.

Quiz

Which GAP Roles are connectionless (do not support the connected state)? Choose
the correct answer(s).

BroadcasterCentralObserverPeripheral

Advertising

Advertising Basics

Bluetooth devices can send advertising packets (PDUs) to
broadcast data, or to allow other Bluetooth devices to find them and connect to
them.

Bluetooth low energy uses 40 different RF channels. Three of these channels
are called primary advertising channels, and are used for communication outside
of connections. This includes:

advertisements

scan requests

scan responses

connection requests.

The remaining 37 channels are primarily used for data exchanges within BLE
connections. In the following figure, this is illustrated. The primary
advertising channels are placed to avoid the Wi-Fi channels since Wi-Fi
transmissions cause noise on the BLE channels.

On advertisement channels, both advertisement, scan request and connection
request packets are sent. So if there is too much noise on the advertisement
channel, the devices will be unable to establish a connection. This is why the
advertisement channels are placed the farthest away from the Wi-Fi channels.
In addition, they are placed far away from each other.

With Bluetooth 5, new advertisement types are added that expand the
possibilities of sending data in advertisement packets. The new advertisement
packet types are listed in the Advertising Packets section. Bluetooth 5
opens for advertising on the 37 data channels. When advertisements are sent on
the data channels, they are called secondary advertising channels.

Quiz

Which of the following PDUs can not be sent on a primary advertisement channel?

A data packetAn advertisement packetA connection request packet

Advertising Parameters

The following table summarizes the parameters that can be configured for
advertising.

Advertising Parameter

Description

Range

Advertising Interval

Time between the start of two consecutive advertising events

20ms to 10.24s

Advertising Types

Different PDUs are sent for different types of advertising

See table under Advertising Packets

Advertising Channels

Legacy advertising packets are sent on three channels

Different combinations of channels 37, 38 and 39.

The advertising channels for legacy advertising are channel 37 (2402 MHz),
channel 38 (2426 MHz), and channel 39 (2480 MHz). The device can advertise on
one, two or three of these. The following diagram shows an advertising event
when advertising on all three channels.

Note that the same data (ADV_IND) is sent on all three channels. Since the
packet is quite small (remember that the advertisement data is no more than 31
bytes), it takes less than 10 ms to send it. The device can be modified to
advertise only on selected channels. Advertising on fewer channels will save
power, however using more channels will increase the likelihood of a peer device
receiving the packet. The user can configure the advertising interval based on
the application use case. For example, if a door lock is advertising at a slower
interval, it will take longer for the peer device to connect to the door lock
which would adversely affect user experience.

Quiz

Which advertising interval would be better suited for a door lock application
powered by battery?

10 s 1 s7.5 ms

Which advertising interval would be better suited for a temperature sensor application
powered by battery?

10 s1 s 7.5 ms

Advertising Packets

The advertising data consists up to 31 bytes of user configurable data. An additional
31 bytes can be sent as a scan response to a scan request. There are eight
different types of advertising packets, listed in the table below. The last four
(in bold type) have been added with Bluetooth 5. They are called extended
advertisement PDUs. The packets that start with ADV_ are transmitted on the
primary advertising channels. The packets that start with AUX_ are
transmitted on the secondary advertisement channels.

Advertising PDU

Description

Max adv data len

Allow scan req

Allow connect

ADV_IND

Used to send connectable undirected advertisement

31 bytes

Yes

Yes

ADV_DIRECT_IND

Used to send connectable directed advertisement

N/A

No

Yes

ADV_SCAN_IND

Used to send scannable undirected advertisement

31 bytes

Yes

No

ADV_NONCONN_IND

Used to send non-connectable undirected advertisement

31 bytes

No

No

ADV_EXT_IND

Used to indicate that an advertisement will be sent on a secondary advertisement channel.

No adv data allowed.

No

No

AUX_ADV_IND

Used to send connectable directed advertisement on a secondary advertisement channel.

254 bytes

Yes

Yes

AUX_SYNC_IND

Used for periodic advertisements on secondary advertisement channels.

254 bytes

No

No

AUX_CHAIN_IND

Used to chain advertisement packets, allowing the advertisement data to extend beyond one packet.

For example, if you want to advertise on LE Coded PHY (long range), the device
would use the ADV_EXT_IND to advertise on the primary advertising channels.
The ADV_EXT_IND contain a pointer to a AUX_ADV_IND that would be transmitted
on a secondary advertisement channel.

An other example: If the device wants to send a lot of advertisement data, it
can advertise with ADV_EXT_IND as usual. The ADV_EXT_IND would contain a
pointer to a AUX_ADV_IND. If there is a lot of adv data to send, the
AUX_ADV_IND could be sent on the LE 2M PHY for speed. The AUX_ADV_IND can
contain a pointer to a AUX_CHAIN_IND which contains the remaining adv data. In
this case, you are not allowed to advertise in connectable or scannable mode.

The above table shows that the legacy advertising modes use the 31 payload bytes
for advertisement data except directed advertising, which uses the 6-byte
device address of the initiating device as adv data. Directed advertisements
have an intended receiving device (scanner), while undirected advertisements do
not have a specific intended receiver. In addition, all the legacy advertising
types enable sending a scan response, except for the directed and
non-connectable advertising.

It may be worth noting that for directed advertising, the advertisement duration
can not be higher than 1.28 seconds.

Bluetooth 5 Advertisement PDUs

The rules for directed/undirected, scannable/non-scannable and
connectable/non-connectable are a bit more complex for the extended advertising
PDUs. The extended advertising PDUs contain an additional header where this
information is stored.

The Common Extended Advertising Payload Format is given below. No fields of the
extended header are mandatory.

Scannable and Connectable

The extended advertisement PDUs can not be both scannable and connectable.
They can be either scannable or connectable (or neither). This is indicated
in the AdvMode field of the packet.

Scannable ADV_EXT_IND and AUX_ADV_IND can not contain any advertising data
(just the header).

PHYs

ADV_EXT_IND can be sent on the LE 1M PHY, or a LE Coded PHY. The other extended
advertising PDUs can be sent on any PHY.

Quiz

Which type of legacy advertising does not receive (RX) any packets (is transmit (TX)
only)? Choose the correct answer(s).

ADV_INDADV_DIRECT_IND ADV_SCAN_IND ADV_NONCONN_IND

What information can the Common Extended Advertising Payload Format extended
header contain? Choose the correct answer(s).

Whether the packet is scannable and connectable. Tx power of the advertisement packet The advertisement data The target device (in case of directed advertisements)

AUX_SYNC_IND is not supported in the Simplelink CC2640R2 SDK 1.50, and will
not be further explored in this Simplelink Academy lab.

The following tasks will demonstrate advertising using the simple_peripheral
project.

Advertising Task 1 – Change Advertising Parameters

In some cases we want to save power. One way to do this is by increasing the
advertisement interval (advertise less frequently), and just advertise on one
channel. In this task, we will configure the device to advertise on one channel
every 500 ms using the simple_peripheral project. The default values of the
advertising parameters for simple_peripheral are shown below:

In simple_peripheral, the device is initialized before the advertisements are
configured. The advertisement configuration is done in
SimplePeripheral_processGapMessage, GAP_DEVICE_INIT_DONE_EVENT, look for the
following code:

As you can see, the advertisement parameters are loaded from
GAPADV_PARAMS_LEGACY_SCANN_CONN (shown above). Then the advertisement set is
created. The advertisement data and scan response data are loaded to the
advertisement set. The event mask is set and lastly the advertisement set is
enabled.

The default value of the advertising channel map is set to GAP_ADV_CHAN_ALL;
advertise on all three channels. We will make a new GapAdv_params_t variable
to hold our parameters:

Advertisement interval: 500 ms

Only advertise on channel 37

Initialize the new GapAdv_params_t variable before you set the values that are
different from GAPADV_PARAMS_LEGACY_SCANN_CONN. You can find all necessary bit
flags in gap_advertiser.h. E.g. the list of available defines for the channel
map is given in the GapAdv_advChannels_t struct. Note that the advertisement
interval is given in units of 0.625 ms, so you will have to calculate the
correct value for this parameter.

Advertising is started when GapAdv_enable() is called. You can see the
corresponding advertising event in gap_advertising.h.

Advertising Event Mask

Description

GAP Event

GAP_ADV_EVT_MASK_SCAN_REQ_NOTI

Sent when a scan request is received.

GAP_EVT_SCAN_REQ_RECEIVED

GAP_ADV_EVT_MASK_SET_TERMINATED

Sent when an advertisement set is terminated due to a connection establishment.

GAP_EVT_ADV_SET_TERMINATED

GAP_ADV_EVT_MASK_START_AFTER_ENABLE

Sent on the first advertisement after a GapAdv_enable().

GAP_EVT_ADV_START_AFTER_ENABLE

GAP_ADV_EVT_MASK_START

Sent at the beginning of each advertisement.

GAP_EVT_ADV_START

GAP_ADV_EVT_MASK_END_AFTER_DISABLE

Sent after advertising stops due to a GapAdv_disable().

GAP_EVT_ADV_END_AFTER_DISABLE

GAP_ADV_EVT_MASK_ALL

Mask to enable/disable all advertising events.

N/A

Advertising Task 2 – Change Advertising Interval at Runtime

In this task we will advertise as previously, but when the device is discovered
it will change the advertising interval to advertise more frequently. Imagine a
BLE beacon that transmits data to passing phones. If no phones are around there
is no reason to advertise often, since every advertisement consumes power. When
the beacon receives a scan request it knows that someone is
around and it makes sense to advertise more frequently. In the previous task we
changed the advertising interval to 500 ms. We will keep this, but when the
device is discovered for the first time it will start advertising with 100 ms
interval.

In order to see if Simple Peripheral has received any scan requests, we have to
add GAP_ADV_EVT_MASK_SCAN_REQ_NOTI to the GapAdv event mask. Replace the
existing call to GapAdv_setEventMask() with the following:

Whenever a scan request is received, an event will be sent to the GapAdv
callback function (SimplePeripheral_advCallback()), which in turn will post it
to the SimplePeripheral_processAdvEvent() function. We can use this event to
set the advertisement interval, using the GapAdv_setParam() API. However,
before the GapAdv_setParam() is used, advertising has to be disabled.

The scan request event is received in SimplePeripheral_processAdvEvent(), as
GAP_EVT_SCAN_REQ_RECEIVED.

Inside this event we need to disable advertising (because GapAdv_setParam()
can not be used while advertising is enabled.)

The event is posted every time the device receives a scan request. However we
only want to update the advertisement interval once, so check whether this one
is already updated.

Advertising Task 3 – Change the Advertisement Data

In this task, we will change the advertisement data. The advertisement data is
stored in the advertData variable:

// Advertisement datastaticuint8_t advertData[] =
{
0x02, // length of this data
GAP_ADTYPE_FLAGS,
DEFAULT_DISCOVERABLE_MODE | GAP_ADTYPE_FLAGS_BREDR_NOT_SUPPORTED,
// service UUID, to notify central devices what services are included// in this peripheral0x03, // length of this data
GAP_ADTYPE_16BIT_MORE, // some of the UUID's, but not all
LO_UINT16(SIMPLEPROFILE_SERV_UUID),
HI_UINT16(SIMPLEPROFILE_SERV_UUID)
};

simple_peripheral.c – Advertisement data variable.

As you can see, the structure of the advertisement data is always as following:

Length of the following data

GAP AD type

Data.

For example the default advertisement data:

Length

GAP_ADTYPE

Explanation

Data

0x02

GAP_ADTYPE_FLAGS

Describes the advertisement mode: Limited, General etc.

DEFAULT_DISCOVERABLE_MODE GAP_ADTYPE_FLAGS_BREDR_NOT_SUPPORTED

0x03

GAP_ADTYPE_16BIT_MORE

This flag contains some of the 16bit Service UUIDs of the device; more UUIDs are available.

There are several ways to change the advertisement data. You can read about
them in the The GAP chapter of the BLE5-Stack
User's Guide.

Here, we will change the advertisement data when advertising is first enabled.
This is shown in the flow diagram below:

When advertising is enabled, the application receives an event from GAP
Advertiser, GAP_EVT_ADV_START_AFTER_ENABLE. This event is processes in
SimplePeripheral_processAdvEvent(). We will update the advertisement data with
the Update Advertising/Scan Response Data that is Used for Multiple
Advertising Handles method described in
The GAP chapter of the BLE5-Stack
User's Guide:

GapAdv_prepareLoadByBuffer() disables advertising for all advertisement sets
who uses the advertData buffer.

GapAdv_loadByBuffer() loads the advData to the relevant advertisement sets
and re-enables advertising.

By using the GAP_ADTYPE_MANUFACTURER_SPECIFIC data type, we can put whatever
we want in the advertisement data. (In this case it's 0xAA and 0xBB but you can change
it to something else if you want.)

Limited Advertising

Limited advertising can be used to conserve power by advertising for a limited
amount of time. General advertisers will continue advertising indefinitely,
while limited advertisers advertise for a given amount of times, e.g. 30
seconds, then stop. This is usually enough time for any devices trying to scan
and/or connect to the device to discover it. You can also set a number of
advertisement events. In this case, the device will advertise until the number
of advertisement events is reached (or until something else disables
advertising).

To use limited advertising in simple_peripheral.c, call GapAdv_enable() with
the following parameters:

// To advertise for a limited amount of time, use the option GAP_ADV_ENABLE_OPTIONS_USE_DURATION
GapAdv_enableOptions_t myOption = GAP_ADV_ENABLE_OPTIONS_USE_DURATION;
// The time to advertise before stopping is given in units of 10 ms. The range is 10 ms - 655 540 ms
uint16 advDuration = 3000; //Advertise for 30 s (30 000 / 10 ms = 3000 )
GapAdv_enable(advHandleLegacy, myOption, advDuration);

Limited advertising in time

To limit the number of advertisement events, call GapAdv_enable() with the
following parameters:

// To advertise for a limited amount of advertisement events, use the option GAP_ADV_ENABLE_OPTIONS_USE_MAX_EVENTS
GapAdv_enableOptions_t myOption = GAP_ADV_ENABLE_OPTIONS_USE_MAX_EVENTS;
// The maximum number of advertisements to send before stopping has the range 1-256
uint16 advDuration = 60;
GapAdv_enable(advHandleLegacy, myOption, advDuration);

Limited advertising in time

In addition, the flag in the advertisement data should be changed to
GAP_ADTYPE_FLAGS_LIMITED. You can do this directly in the advertisement data
buffer, or you can use the provided define:

// General discoverable mode: advertise indefinitely// Limited discoverable mode advertises for a limited time or number of adv events#define DEFAULT_DISCOVERABLE_MODE GAP_ADTYPE_FLAGS_LIMITED

Configuring limited advertising flag

Limited advertising can be used to classify/filter devices. For example, devices
that are scanning in limited discovery mode can only receive advertisement
data from limited advertising devices. See the Bluetooth core specification for more
information on the limited discovery procedure.

If you haven't loaded the simple_peripheral project into your device yet - do
it now! Build the stack library project first, then build and flash the app
project.

Scanning

Scanning Basics

When not connected, Bluetooth low energy devices can either advertise their
presence by transmitting advertisement packets or scan for nearby devices that
are advertising. The process of scanning for devices is called device
discovery. There are two types of scanning; active and passive. The difference
is that an active scanner can send a scan request to request additional
information from the advertiser, while a passive scanner can only receive data
from advertising device. Note that the terms discovery and scanning may be
used interchangeably. The figure below shows the sequence where the scanner
sends a scan request to an advertiser during an advertising event.

When it comes to the timing of a scan, there are a few parameters you need to
get familiar with. Each of these parameters has a range dictated by the
Bluetooth core specification. The Time Inter Frame Space (T_IFS) is the time
interval between two consecutive packets on the same channel index and is set
to 150us by the BLE specification.

Scan Parameter

Description

Range

Scan Interval

The interval between the start of two consecutive scan windows

10ms to 10.24s

Scan Window

The duration in which the Link Layer scans on one channel

10ms to 10.24s

Scan Duration

The duration in which the device stays in the scanning state

10ms to infinity

The following diagram visually shows the scanning parameters:

Note that the order of the scanning channels are not configurable. The device
will scan on channel 37 (2402 MHz), then channel 38 (2426 MHz), and then channel
39 (2480 MHz) respectively and in that order on every scanning interval for the
length of time defined by the scanning window.

Quiz

Which type of scanning does not transmit (TX) any packets, only receives (RX)
advertisement packets? Choose the correct answer(s).

active scanning passive scanning

After receiving which type of advertisement can an active scanner send a scan
request? Choose the correct answer(s).

Scanning Packets

Scannable advertisement packets on secondary advertising channels can also
incite a scan request and scan response. These are called AUX_SCAN_REQ and
AUX_SCAN_RSP. All scanning related packets are summarized in the following
table:

Scan requests and scan responses are always sent on the same channel and PHY as
the advertising packet that prompted them.

Quiz

Which of the scan PDUs can be sent on the LE 2M PHY?

SCAN_REQSCAN_RSPAUX_SCAN_REQ AUX_SCAN_RSP

Scanning Task 1 – Change Scanning Parameters

In this task, we will scan continuously with the following scan parameters:

Scan interval: 150 milliseconds(ms)

Scan window: 150 milliseconds(ms)

Scan duration: 5 seconds(s)

Scan type: Passive

Scan PHY: LE 1M PHY (Legacy scanning)

These parameters are set three different ways:

First we will set the parameters that are PHY-specific

Then we will set the PHY-agnostic parameters

Lastly we will give the scan duration as part of the GapScan_enable() command.

Scroll down to SimpleCentral_processGapMsg() :: GAP_DEVICE_INIT_DONE_EVENT and
change the parameters to match the specifications given above. The PHY-specific
parameters must be set for PHY we're going to scan on (in this case the LE 1M
PHY) and can be set with GapScan_setPhyParams(). The following parameters are
PHY-specific:

The above parameters are used to set up how the device will behave during the
discovery process.

In gap_scanner.h you can find a full description on all parameters that can be configured for the GAP Scanner module.

Two Kinds of Discovery

Note that this discovery procedure to discover nearby devices is not to be
confused with the characteristic discovery procedure which is can be called
after a connection is established.

If you haven't loaded the simple_central project into your device yet –
now is the time! Build the stack library project first, then build and flash the
app project.

Scanning Task 2 – Print Scanning Results

Every time the device receives an advertisement or scan response packet, the
application receives a GAP_EVT_ADV_REPORT event from the GAP layer. This event
is caught in SimpleCentral_scanCb(), then sent
it to SimpleCentral_processAppMsg().

The device info is encapsulated in the GapScan_Evt_AdvRpt_t structure:

Re-build and flash the project. You may notice that you only receive
advertisement packets and no scan response packets. Why?

Scanning Task 3 – Scan Indefinitely

When the application needs to scan for nearby devices at all times, i.e. always
be in the scanning state, set DEFAULT_SCAN_DURATION to 0. This will set the
device in continuous scanning. Alternatively, we can set the device to scan
continuously for a while, then take a break periodically. We will do this by
setting the scan duration and scan period as follows:

Scan duration: 1 s

Scan period: 5 s

This will make the device scan for 1 second, then pause for 4 seconds, before
scanning for 1 second etc.

Note that even in indefinite scanning, the number of scanned results will still
be limited by DEFAULT_MAX_SCAN_RES. In this case, DEFAULT_MAX_SCAN_RES is
set to 0. When zero, this parameter is ignored.

Note

Regardless of the number of devices the scanner has discovered, the application will return "0 Devices Found" when discovery is ended.

Filter Duplicate Advertisers

For some applications, processing multiple advertisements by the same peer
device can be useful. E.g. when collecting information from a beacon that
updates its advertisement data frequently. By default, the scanning device will
filter advertising data. To turn off the filter for duplicate advertisers, use
the following API:

In order to see all the received packets as a log, disable the ANSI interface
for the UART driver. Do this by opening the Project -> Properties -> Build ->
ARM Compiler -> Predefined Symbols and set BOARD_DISPLAY_USE_UART_ANSI=0.

Miscellaneous Guidelines

Choosing advertising interval: Fast or slow?

The advertising interval should be set based on use case. Both fast and slow
advertising have pros and cons:

Optimizing Scanning: How to get data fast?

In a time-constrained application, when the user needs to receive the data as
fast as possible, make sure that the scan window is more than the advertising
interval + 10ms to guarantee discovery. (The 10 ms extra account for the 0 ms to
10 ms of pseudo-random delay in between each advertising event, assuming no
interference.) Following this rule will increase the chance of receiving the
advertising packet on the first scan.