The goal of this article is to explain the basics on how BLE advertising packets are formatted. The idea is not to cover every little detail related to advertising but to give a brief introduction that will allow you to quickly learn how to “decode” the content of an advertising packet.
When a BLE device is advertising it will periodically transmit packets contains information such as: Preamble, Access Address, CRC, Bluetooth address of the sender, etc… The interesting part from application developer perspective is often the advertising payload that is 0-31 bytes long. Other fields in the advertising packets are automatically filled by the Bluetooth stack but the advertising payload is something that is under the control of the application (either indirectly or directly, as explained later).
In this article, the term advertising data refers to the 0..31 byte long payload that is available for application use. (In Bluetooth Core specification this field is referred to as AdvData).
Advertising data consists of one or more Advertising Data (AD) elements. Each element is formatted as follows:
The possible AD type values are listed in the Bluetooth SIG website, see following link:
Some of the most commonly used data types are:
0x01 = flags
0x03 = Complete List of 16-bit Service Class UUIDs
0x09 = Complete Local Name
0x08 = Shortened Local Name
The advertising data format is probably easiest to learn by looking at some real-world examples.
The first example shows how to decode the advertisement data sent by the Thermometer example (taken from SDK v2.1.1). The payload consists of 28 bytes that are seemingly random but it is actually quite simple to decode in to advertising elements as shown below.
In the example shown above, the raw payload is split into three AD elements. The first byte is always the length indicator which makes it easy to find the AD element boundaries.
The first elements is flags. The payload is just one byte long and thus there are up to 8 flags that can be set. In this example, two flags are set (bit positions 1 and 2) and the meaning is:
Bit 1 : “LE General Discoverable Mode”
Bit 2: “BR/EDR Not Supported.”
The second element includes list of adopted services (16-bit UUID). In this case, only one service (Health Thermometer, UUID 0x1809) is advertised. Note the reversed byte order (multibyte values in BLE packets are in little-endian order). A complete list of the adopted service UUID values can be found at:
The third element contains the device name Thermometer Example. This is the name that is displayed if you for example try to scan the device with your smartphone.
The second example is taken from the SPP-over-BLE example that is described in this article:
In this second example, the advertising payload is maximum length i.e. 31 bytes. It is dissected into individual AD elements same way as in the first example.
The first element is the flags byte which has same value as in first example.
The second element has AD Type set to 0x07 which means Complete List of 128-bit Service Class UUID. In this case, the device is advertising the 128-bit UUID that has been allocated for the custom SPP-over-BLE service. This value is defined in gatt.xml file of the example project (linked above). Again, note that the byte order is reversed if you compare the advertising payload and the gatt.xml content.
The third element is the device name. The actual device name defined in the project is "BGM111 SPP server". However, there is not enough space in the advertising payload to fit the complete name. For this reason, the name is truncated. The AD Type 0x08 is used to indicate that this is a shortened name. Only 8 first characters of the name can be fitted in the advertising data to meet the 31-byte size limit.
There are two possible ways to set the advertising data content using Silicon Labs Bluetooth SDK.
Option 1) is the simplest one. The stack will automatically fill the advertising data content based on what services have been defined in the GATT database of the application. It is possible to select which services are included in the advertising packets. All services are not automatically advertised, this is configurable using the advertise parameter. For more details, refer to document UG118: Blue Gecko Bluetooth® Profile Toolkit Developer's Guide.
The logic how the advertising data is automatically filled is described in BGAPI reference manual (command cmd_le_gap_set_mode description). For details, see Bluetooth Smart Software API Reference Manual (Rev 1.9) -> Section 220.127.116.11 cmd_le_gap_set_mode.
Option 2) is more flexible because it allows the application to have full control over data that is included in the advertising payload. This is especially useful if the application needs to advertise some manufacturer specific data. (There is a dedicated AD Type 0xFF reserverd for proprietary data).
Note that even when using custom data the AD elements must be formatted according to the Bluetooth specification. Using custom advertising data is beyond the scope of this article, it will be discussed in a separate article later.
This article is intended to be used as a quick introduction to BLE advertising, without digging too deep into the details. Below are some pointers for more detailed information on the topic:
List of adopted services:
BGAPI reference manual (*
UG118: Blue Gecko Bluetooth® Profile Toolkit Developer's Guide (*
Bluetooth Core Specification:
This is the golden reference but not that easy to digest…
*) it's recommended to refer to the copy that is included in the SDK that you are using, to make sure the doc version matches the SDK you are using. The documents are accessible form the Simplicity Studio main page (launcher view). Alternatively, you can check the doc folder within the SDK installation tree, for example:
Nice intro to advertising Jaakko Looking forward to the following more detailed articles and how the nuances are supported in the SiLabs devices.
I often see devices that somehow manage to embed both a fairly long name and 128bit UUIDs, thus going past the 31 bytes limit of advertisement packets. Is there a trick they use for doing this? Such as picking different contents for each advertisement, or another mechanism?
For instance, a device I work with uses a 17 byte UUID packet + 16 byte 0x09 'complete name + header...
Right now I am trying to achieve the same on a BGM-111 device powered by bgscript, any advice on how to do this?
@elafargue you can put additional data in scan responses. The advertising payload is 31 bytes and the scan response is another 31 bytes.
You can initialize the advertising and scan response data explicitly using the cmd_le_gap_set_adv_data API command. The parameter scan_rsp selects which data set you are updating. See BGAPI reference manual for more info.
Alternatively, you can just let the stack fill the adv data and scan responses. The logic how this works is explained in the BGAPI ref.manual, see command cmd_le_gap_set_mode.
EDIT: active and passive scanning concepts are explained in following document:
Thanks for your reply! I did exactly this and it works great, getting a full name + proper UUID in the advertising + scan response packets now, so that we can use filtering on service when scanning for the devices, makes it a lot simpler for users.
Will there be an article on using custom advertising data? I need to put in some extra data in manufaturer specific data to be able to separate devices from each other as or complete device names does not fit in the advertising packet.
Custom advertising data is covered in following KB article:
Thank you for the useful information provided. Now I would like to ask a question.
Imagin there is a BLE raw PDU as shown in the following:
and after decomposition of this PDU, we will have :
I am confusing about the Data field, is there any method to decode this data value?
Can we encrypt the BLE advertising data using the AES CCM algorithm ?