This example shows how to generate and decode Bluetooth® Low Energy (BLE) link layer packets using the Communications Toolbox™ Library for the Bluetooth® Protocol.
The Bluetooth Core Specification [ 1 ] includes a Low Energy version for low-rate wireless personal area networks, that is referred to as Bluetooth Low Energy (BLE) or Bluetooth Smart. The BLE stack consists of: Generic Attribute Profile (GATT), Attribute Protocol (ATT), Security Manager Protocol (SMP), Logical Link Control and Adaptation Protocol (L2CAP), link layer (LL) and physical layer. BLE was added to the standard for low energy devices generating small amounts of data, such as notification alerts used in such applications as home automation, health-care, fitness, and Internet of Things (IoT).
Bluetooth core specification [ 1 ] defines two kinds of PHYs for BLE. Each PHY has its own packet format.
(i) Uncoded PHYs (1 Mbps and 2 Mbps)
(ii) Coded PHYs (125 Kbps and 500 Kbps)
Coded PHYs use Forward Error Correction (FEC) encoding (with coding scheme S = 8 or S = 2) for the packets. The figures show the uncoded and coded PHY packet formats.
Format of LE Air Interface Packet for Uncoded PHY
Format of LE Air Interface Packet for Coded PHY
The Communications Toolbox™ Library for the Bluetooth Protocol generates LL packets that consist of Protocol Data Unit (PDU) and the Cyclic Redundancy Check (CRC) shown in the PHY packet.
BLE classifies 40 RF channels into three advertising channels (Channel indices: 37, 38, 39) and thirty-seven data channels (Channel indices: 0 to 36). BLE link layer defines two categories of PDUs, advertising channel PDUs and data channel PDUs. There are different PDU types within these two categories of PDUs. The access address field in the air interface packet format differentiates between a data channel PDU and an advertising channel PDU. Each category of PDU has its own format.
The advertising channel PDUs (see Section 2.3, Part-B, Vol-6 in [ 1 ]) are used before a LL connection is created. These PDUs are transmitted only on the advertising channels and used in establishing the LL connection. The advertising channel PDU has a 16-bit header and a variable size payload.
The advertising channel PDU has the following packet format:
This example illustrates generation and decoding of advertising indication PDU. For a list of other advertising channel PDUs supported, see the PDUType property.
Advertising indication: The advertising indication PDU is used when a device wants to advertise itself. This PDU contains the advertising data related to the application profile of the device.
% Check if the 'Communications Toolbox Library for the Bluetooth Protocol' % support package is installed or not. commSupportPackageCheck('BLUETOOTH');
You can use the bleLLAdvertisingChannelPDU
function to generate an advertising channel PDU. This function accepts a configuration object bleLLAdvertisingChannelPDUConfig
. This object configures the fields required for generating an advertising channel PDU.
Advertising Indication Generation
To generate an 'Advertising indication' PDU, create a bleLLAdvertisingChannelPDUConfig
object with PDUType
set to 'Advertising indication'
.
cfgLLAdv = bleLLAdvertisingChannelPDUConfig('PDUType', ... 'Advertising indication');
Configure the fields:
% Advertiser address cfgLLAdv.AdvertiserAddress = '012345ABCDEF'; % Advertising data cfgLLAdv.AdvertisingData = '0201060D09426174746572792056312E30'
cfgLLAdv = bleLLAdvertisingChannelPDUConfig with properties: PDUType: 'Advertising indication' ChannelSelection: 'Algorithm1' AdvertiserAddressType: 'Random' AdvertiserAddress: '012345ABCDEF' AdvertisingData: [17x2 char]
Generate an 'Advertising indication' PDU.
llAdvPDU = bleLLAdvertisingChannelPDU(cfgLLAdv);
You can use the bleLLAdvertisingChannelPDUDecode
function to decode an advertising channel PDU. This function outputs the following information:
status
: An enumeration of type blePacketDecodeStatus, which indicates whether the LL decoding was successful.
cfgLLAdv
: A LL advertising channel PDU configuration object of type bleLLAdvertisingChannelPDUConfig
, which contains the decoded LL properties.
Provide the advertising channel PDU and an optional name-value pair specifying the format of the input data PDU to the bleLLAdvertisingChannelPDUDecode function. Default input format is 'bits'.
Decoding Advertising Indication
[llAdvDecodeStatus, cfgLLAdv] = bleLLAdvertisingChannelPDUDecode(llAdvPDU); % Observe the outputs % Decoding is successful if strcmp(llAdvDecodeStatus, 'Success') fprintf('Link layer decoding status is: %s\n\n', llAdvDecodeStatus); fprintf('Received Advertising channel PDU configuration is:\n'); cfgLLAdv % Decoding failed else fprintf('Link layer decoding status is: %s\n', llAdvDecodeStatus); end
Link layer decoding status is: Success Received Advertising channel PDU configuration is: cfgLLAdv = bleLLAdvertisingChannelPDUConfig with properties: PDUType: 'Advertising indication' ChannelSelection: 'Algorithm1' AdvertiserAddressType: 'Random' AdvertiserAddress: '012345ABCDEF' AdvertisingData: [17x2 char]
The data channel PDUs (see Section 2.4, Part-B, Vol-6 in [ 1 ]) are used after a LL connection is created. The data channel PDUs consist of two sub-categories: LL data PDUs and LL control PDUs. The LL control PDUs are used for managing the LL connection and the LL data PDUs are used to carry the upper-layer data. The data channel PDU has a 16-bit header and a variable size payload.
The data channel PDUs have the following packet format:
This example illustrates generation and decoding of the following PDUs. For a list of other control PDU types and data PDU types supported see Opcode and LLID properties respectively.
Channel map indication: This LL control PDU is used to update the channel map at the peer device. This PDU contains the updated channel map indicating good and bad channels.
Data (start fragment/complete): This LL data PDU is used to carry L2CAP data to the peer device.
You can use the bleLLDataChannelPDU
function to generate a data channel PDU. This function accepts a configuration object bleLLDataChannelPDUConfig
, which configures the fields required for generating a data channel PDU. The bleLLControlPDUConfig
is a sub-configuration object within bleLLDataChannelPDUConfig
, control PDU payload fields are populated using the settings of this configuration object.
Data channel PDUs use the CRC initialization value obtained in the 'Connection indication' packet. The CRC initialization value used in the generation and decoding of packets.
% CRC initialization value crcInit = 'ED321C';
LL Data PDU Generation
To generate a data PDU, create a bleLLDataChannelPDUConfig
object with LLID
set to 'Data (start fragment/complete)'
.
cfgLLData = bleLLDataChannelPDUConfig('LLID', ... 'Data (start fragment/complete)');
Configure the fields:
% CRC initialization value cfgLLData.CRCInitialization = crcInit; % Sequence number cfgLLData.SequenceNumber = 0; % Next expected sequence number cfgLLData.NESN = 1
cfgLLData = bleLLDataChannelPDUConfig with properties: LLID: 'Data (start fragment/complete)' NESN: 1 SequenceNumber: 0 MoreData: 0 CRCInitialization: 'ED321C'
A data PDU is used to transmit a payload from upper-layer. A 18-byte payload is used in this example.
% Payload payload = '0E00050014010A001F004000170017000000';
Generate a data PDU using payload and configuration.
llDataPDU = bleLLDataChannelPDU(cfgLLData, payload);
LL Control PDU Generation
To generate a control PDU, create a bleLLDataChannelPDUConfig
object with LLID
set to 'Control'
.
cfgLLData = bleLLDataChannelPDUConfig('LLID', 'Control');
Configure the fields:
% CRC initialization value
cfgLLData.CRCInitialization = crcInit
cfgLLData = bleLLDataChannelPDUConfig with properties: LLID: 'Control' NESN: 0 SequenceNumber: 0 MoreData: 0 CRCInitialization: 'ED321C' ControlConfig: [1x1 bleLLControlPDUConfig]
You can configure the contents of an LL control PDU using bleLLControlPDUConfig
.
Create a control PDU configuration object with Opcode
set to 'Channel map indication'
.
cfgControl = bleLLControlPDUConfig('Opcode', 'Channel map indication');
Configure the fields:
% Used channels cfgControl.UsedChannels = [9, 10, 12, 24, 28, 32]; % Connection event instant cfgControl.Instant = 245
cfgControl = bleLLControlPDUConfig with properties: Opcode: 'Channel map indication' Instant: 245 UsedChannels: [9 10 12 24 28 32]
Assign the updated control PDU configuration object to the ControlConfig
property in the data channel PDU configuration object.
% Update the data channel PDU configuration
cfgLLData.ControlConfig = cfgControl;
Generate a control PDU with the updated configuration.
llControlPDU = bleLLDataChannelPDU(cfgLLData);
You can use the bleLLDataChannelPDUDecode
function to decode a data channel PDU. This function outputs the following information:
status
: An enumeration of type blePacketDecodeStatus, which indicates whether the LL decoding was successful.
cfgLLData
: An LL data channel PDU configuration object of type bleLLDataChannelPDUConfig
, which contains the decoded LL properties.
payload
: An n-by-2 character array representing the upper-layer payload carried by LL data PDUs.
Provide the data channel PDU, CRC initialization value and an optional name-value pair specifying the format of the input data PDU to the bleLLDataChannelPDUDecode
function. Default input format is 'bits'.
Decoding LL Data PDU
[llDataDecodeStatus, cfgLLData, payload] = ... bleLLDataChannelPDUDecode(llDataPDU, crcInit); % Observe the outputs % Decoding is successful if strcmp(llDataDecodeStatus, 'Success') fprintf('Link layer decoding status is: %s\n\n', llDataDecodeStatus); fprintf('Received Data channel PDU configuration is:\n'); cfgLLData fprintf('Size of the received upper-layer payload is: %d\n', ... numel(payload)/2); % Decoding failed else fprintf('Link layer decoding status is: %s\n', llDataDecodeStatus); end
Link layer decoding status is: Success Received Data channel PDU configuration is: cfgLLData = bleLLDataChannelPDUConfig with properties: LLID: 'Data (start fragment/complete)' NESN: 1 SequenceNumber: 0 MoreData: 0 CRCInitialization: '012345' Size of the received upper-layer payload is: 18
Decoding LL Control PDU
[llControlDecodeStatus, cfgLLData] = ... bleLLDataChannelPDUDecode(llControlPDU, crcInit); % Observe the outputs % Decoding is successful if strcmp(llControlDecodeStatus, 'Success') fprintf('Link layer decoding status is: %s\n\n', llControlDecodeStatus); fprintf('Received Data channel PDU configuration is:\n'); cfgLLData fprintf('Received control PDU configuration is:\n'); cfgControl = cfgLLData.ControlConfig % Decoding failed else fprintf('Link layer decoding status is: %s\n', llControlDecodeStatus); end
Link layer decoding status is: Success Received Data channel PDU configuration is: cfgLLData = bleLLDataChannelPDUConfig with properties: LLID: 'Control' NESN: 0 SequenceNumber: 0 MoreData: 0 CRCInitialization: '012345' ControlConfig: [1x1 bleLLControlPDUConfig] Received control PDU configuration is: cfgControl = bleLLControlPDUConfig with properties: Opcode: 'Channel map indication' Instant: 245 UsedChannels: [9 10 12 24 28 32]
This example uses blePCAPWriter
object to export the generated PDUs to a file with .pcap extension or .pcapng extension. To analyze and visualize this file, use a third part packet analyzer such as Wireshark.
Prepend access address
The PCAP format expects access address to be prepended to the LL packet. The helper function helperBLEPrependAccessAddress prepends access address to the generated LL packet.
% Advertising channel PDUs use the default access address advAccessAddress = '8E89BED6'; % Data channel PDUs use the access address obtained from 'Connection % indication' packet. A random access address is used for this example connAccessAddress = 'E213BC42'; % Prepend access address llPkts{1} = helperBLEPrependAccessAddress(llAdvPDU, advAccessAddress); llPkts{2} = helperBLEPrependAccessAddress(llDataPDU, connAccessAddress); llPkts{3} = helperBLEPrependAccessAddress(llControlPDU, connAccessAddress);
Export to a PCAP file
Create an object of type blePCAPWriter
and specify the packet capture file name.
% Create the BLE PCAP Writer file object pcapObj = blePCAPWriter("FileName", "bleLLPackets");
Use the write
function to write all the BLE LL PDUs to a PCAP file. The constant timestamp
specifies the capture time of a PDU. In this example, the capture time is same for all the PDUs.
timestamp = 124800; % timestamp (in microseconds) % Write all the LL PDUs to the PCAP file for idx = 1:numel(llPkts) write(pcapObj, llPkts{idx}, timestamp, 'PacketFormat', 'bits'); end % Clear the object clear pcapObj;
You can open the PCAP file containing the generated LL packets in a packet analyzer. The packets decoded by the packet analyzer match the standard compliant LL packets generated by the Communications Toolbox™ Library for the Bluetooth Protocol. The captured analysis of the packets is shown below.
Advertising indication
LL data PDU (carrying L2CAP payload)
LL control PDU (channel map indication)
This example demonstrated generation and decoding of LL packets specified in the Bluetooth standard [ 1 ]. You can use a packet analyzer to view the generated LL packets.
The example uses these feature:
bleLLAdvertisingChannelPDU
: Generate LL advertising channel PDU
bleLLAdvertisingChannelPDUDecode
: Decode LL advertising channel PDU
bleLLAdvertisingChannelPDUConfig
: Create a configuration object for generation and decoding of LL advertising channel PDU
bleLLDataChannelPDU
: Generate LL data channel PDU
bleLLDataChannelPDUDecode
: Decode LL data channel PDU
bleLLDataChannelPDUConfig
: Create a configuration object for generation and decoding of LL data channel PDU
bleLLControlPDUConfig
: Create a sub-configuration object used in generation and decoding of data channel PDU
blePCAPWriter
: Create BLE PCAP or PCAPNG file writer object
This example uses this helper:
helperBLEPrependAccessAddress: Prepends the link layer PDU with the access address
Bluetooth® Technology Website. "Bluetooth Technology Website | The Official Website of Bluetooth Technology." Accessed July 8, 2020. https://www.bluetooth.com/.
"Development/LibpcapFileFormat - The Wireshark Wiki." Accessed July 8, 2020. https://wiki.wireshark.org/Development/LibpcapFileFormat.
Group, The Tcpdump. "Tcpdump/Libpcap Public Repository." Accessed July 8, 2020. https://www.tcpdump.org.