Modeling of Bluetooth LE Devices with Heart Rate Profile
This example shows you how to model Bluetooth® low energy (LE) devices with the Heart Rate Profile (HRP).
Using this example, you can:
Create and configure a Bluetooth LE HRP client-server scenario with a smartphone as the client and a wrist band with a heart rate sensor as the server.
Configure the client to perform service and characteristic discovery.
Configure the client to enable receiving notifications for a characteristic from the server.
Export the generated protocol data units (PDUs) to a file with
.pcap
extension.Visualize the generated PDUs by using a third party packet analyzer such as Wireshark [ 4 ].
Background
The Bluetooth core specification [ 2 ] includes a Low Energy version for low-rate wireless personal area networks, that is referred to as Bluetooth Low Energy (Bluetooth LE) or Bluetooth Smart. The Bluetooth LE 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 (PHY). Bluetooth LE 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).
Attribute Protocol
The ATT is built on top of the L2CAP layer of Bluetooth LE. ATT defines a set of Protocol Data Units (PDUs) that are used for data exchange in GATT-based profiles.
Generic Attribute Profile
The GATT is a service framework built using ATT. GATT handles the generation of requests or responses based on application data from the higher layers or ATT PDU received from the lower layer. It stores the information in the form of services, characteristics, and characteristic descriptors. It uses a client-server architecture.
GATT Terminology:
Service: A service is a collection of data and associated behaviors to accomplish a particular function or feature. Example: A heart rate service that allows measurement of a heart rate.
Characteristic: A characteristic is a value used in a service along with its permissions. Example: A heart rate measurement characteristic contains information about the measured heart rate value.
Characteristic descriptor: Descriptors of the characteristic behavior. Example: A Client Characteristic Configuration Descriptor (CCCD), describes whether or not the server has to notify the client in a response containing the characteristic value.
GATT-Client: Initiates commands and requests to the server, and receives responses, indications and notifications sent by the server.
GATT-Server: Accepts incoming commands and requests from a client, and sends responses, indications, and notifications to the client.
Heart Rate Profile
Heart Rate Profile (HRP) [ 3 ] is a GATT-based low energy profile defined by the Bluetooth Special Interest Group (SIG). The HRP defines the communication between a GATT-server of a heart rate sensor device, such as a wrist band, and a GATT-client, such as a smart phone or tablet. The HRP is widely used in fitness applications to collect heart rate measurements.
Bluetooth LE HRP Client-Server Scenario
In this scenario, the GATT-server is a wrist band with a heart rate sensor and the GATT-client is a smart phone.
% Create objects for GATT-server and GATT-client devices
gattServer = helperBLEGATTServer;
gattClient = helperBLEGATTClient;
Initially, the HRP client discovers the services, characteristics, characteristic descriptors defined at the server. After discovery, the client subscribes for heart rate measurement notifications.
Service Discovery
Clients perform a service discovery operation to get information about the available services. In service discovery, the client invokes 'Discover all primary services'
by sending a Read by group type request ATT PDU. The server responds with the available services and their associated handles by sending a 'Read by group type response' ATT PDU. A handle is a unique identifier of an attribute that are dynamically assigned by the server.
Client request for services at Server
The generateATTPDU object function generates an ATT PDU corresponding to the given sub-procedure as specified in the Bluetooth core specification.
% Preallocate a variable to store the generated link layer packets pcapPackets = cell(1, 9); count = 1; % Configure a GATT client to discover services available at the server gattClient.SubProcedure = 'Discover all primary services'; serviceDiscReqPDU = generateATTPDU(gattClient); % Transmit the application data (|serviceDiscReqPDU|) to the server through % PHY [bleWaveform, pcapPackets{count}] = helperBLETransmitData(serviceDiscReqPDU); count = count+1;
Receive Client request at Server
The server receives a Read by group type request from the client and sends the list of available services in a Read by group type response ATT PDU.
The receiveData
object function of the helperBLEGATTServer
helper object decodes the incoming PDU as a GATT-server and returns the corresponding ATT PDU configuration object and the appropriate response PDU.
% Decode the received Bluetooth LE waveform and retrieve the application % data receivedPDU = helperBLEDecodeData(bleWaveform); % Decode the received ATT PDU and generate response PDU, if applicable [attServerRespPDU, serviceDiscReqCfg, gattServer] = receiveData(gattServer, receivedPDU); fprintf("Received service discovery request at the server:\n")
Received service discovery request at the server:
serviceDiscReqCfg
serviceDiscReqCfg = bleATTPDUConfig with properties: Opcode: 'Read by group type request' StartHandle: '0001' EndHandle: 'FFFF' AttributeType: '2800'
% Transmit the application response data (|attServerRespPDU|) to the client % through PHY [bleWaveform, pcapPackets{count}] = helperBLETransmitData(attServerRespPDU); count = count+1;
Receive Server response at Client
The receiveData object function decodes the incoming PDU as a GATT-client and returns the corresponding ATT PDU configuration object and the appropriate response PDU, if applicable.
% Decode the received Bluetooth LE waveform and retrieve the application % data receivedPDU = helperBLEDecodeData(bleWaveform); % Decode received ATT PDU and generate response PDU, if applicable [~, serviceDiscRespCfg] = receiveData(gattClient, receivedPDU); gattClient.StartHandle = serviceDiscRespCfg.StartHandle; gattClient.EndHandle = serviceDiscRespCfg.EndHandle; % Expected response from the server: |'Read by group type response'| or % |'Error response'| if strcmp(serviceDiscRespCfg.Opcode, 'Error response') fprintf("Received error response at the client:\n") serviceDiscRespCfg serviceDiscRespMsg = ['Error response(''' serviceDiscRespCfg.ErrorMessage ''')']; else fprintf("Received service discovery response at the client:\n") serviceDiscRespCfg service = helperBluetoothID.getBluetoothName(serviceDiscRespCfg.AttributeValue); serviceDiscRespMsg = ['Service discovery response(''' service ''')']; end
Received service discovery response at the client:
serviceDiscRespCfg = bleATTPDUConfig with properties: Opcode: 'Read by group type response' StartHandle: '0001' EndHandle: '0006' AttributeValue: [2x2 char]
Characteristics Discovery
A service consists of multiple characteristics. For each service, there are information elements exchanged between a client and server. Each information element may contain descriptors of its behavior. A characteristic contains a value and its associated descriptors. After discovering the service, clients perform characteristics discovery to learn about the characteristics defined in the service. In characteristic discovery, the client invokes 'Discover all characteristics of service'
by sending 'Read by type request' ATT PDU. The server responds with the available characteristics and their associated handles by sending a 'Read by type response' ATT PDU.
Client request for characteristics at Server
% Configure a GATT client to discover all the available characteristics at % the server gattClient.SubProcedure = 'Discover all characteristics of service'; chrsticDiscReqPDU = generateATTPDU(gattClient); % Transmit the application data (|chrsticDiscReqPDU|) to the server through % PHY [bleWaveform, pcapPackets{count}] = helperBLETransmitData(chrsticDiscReqPDU); count = count+1;
Receive Client request at Server
Decodes the received request and return the list of available characteristics in a Read by type response ATT PDU.
% Decode the received Bluetooth LE waveform and retrieve the application % data receivedPDU = helperBLEDecodeData(bleWaveform); % Decode received ATT PDU and generate response PDU, if applicable [chrsticDiscRespPDU, chrsticDiscReqCfg, gattServer] = receiveData(gattServer, receivedPDU); fprintf("Received characteristic discovery request at the server:\n")
Received characteristic discovery request at the server:
chrsticDiscReqCfg
chrsticDiscReqCfg = bleATTPDUConfig with properties: Opcode: 'Read by type request' StartHandle: '0001' EndHandle: '0006' AttributeType: '2803'
% Transmit the application response data (|chrsticDiscRespPDU|) to the % client through PHY [bleWaveform, pcapPackets{count}] = helperBLETransmitData(chrsticDiscRespPDU); count = count+1;
Receive Server response at Client
% Decode the received Bluetooth LE waveform and retrieve the application % data receivedPDU = helperBLEDecodeData(bleWaveform); % Decode received ATT PDU and generate response PDU, if applicable [~, chrsticDiscRespCfg] = receiveData(gattClient, receivedPDU); % Expected response from the server: |'Read by type response'| or |'Error % response'| if strcmp(chrsticDiscRespCfg.Opcode, 'Error response') fprintf("Received error response at the client:\n") chrsticDiscRespCfg chrsticDescRespMsg = ['Error response(''' chrsticDiscRespCfg.ErrorMessage ''')']; else fprintf("Received characteristic discovery response at the client:\n") attributeValueCfg = helperBLEDecodeAttributeValue(... chrsticDiscRespCfg.AttributeValue, 'Characteristic'); attributeValueCfg chrsticDescRespMsg = ['Characteristic discovery response(''' attributeValueCfg.CharacteristicType ''')']; end
Received characteristic discovery response at the client:
attributeValueCfg = helperBLEAttributeValueConfig with properties: AttributeType: 'Characteristic' BroadcastFlag: 'False' ReadFlag: 'False' WriteWithoutResponseFlag: 'False' WriteFlag: 'False' NotifyFlag: 'True' IndicateFlag: 'False' AuthenticatedSignedWritesFlag: 'False' ExtendedPropertiesFlag: 'False' CharacteristicValueHandle: '0003' CharacteristicType: 'Heart rate measurement'
Characteristic Descriptor Discovery
A characteristic may consists of multiple characteristic descriptors. After discovering the characteristic, clients perform characteristic descriptors discovery to learn about the list of descriptors and their handles. In characteristic descriptor discovery, the client invokes 'Discover all descriptors'
by sending 'Information request' ATT PDU. The server responds with the available characteristic descriptors and their associated handles by sending a 'Information response' ATT PDU.
Client request for characteristic descriptors at Server
% Configure a GATT client to discover all the available characteristic % descriptors at the server gattClient.SubProcedure = 'Discover all descriptors'; gattClient.StartHandle = dec2hex(hex2dec(chrsticDiscRespCfg.AttributeHandle)+1, 4); chrsticDescDiscReqPDU = generateATTPDU(gattClient); % Transmit the application data (|chrsticDescDiscReqPDU|) to the client % through PHY [bleWaveform, pcapPackets{count}] = helperBLETransmitData(chrsticDescDiscReqPDU); count = count+1;
Receive Client request at Server
Decodes the received request and returns the list of available characteristic descriptors in a Information response ATT PDU.
% Decode the received Bluetooth LE waveform and retrieve the application % data receivedPDU = helperBLEDecodeData(bleWaveform); % Decode received ATT PDU and generate response PDU, if applicable [chrsticDescDiscRespPDU, chrsticDescDiscReqCfg, gattServer] = receiveData(gattServer, receivedPDU); fprintf("Received characteristic descriptor discovery request at the server:\n")
Received characteristic descriptor discovery request at the server:
chrsticDescDiscReqCfg
chrsticDescDiscReqCfg = bleATTPDUConfig with properties: Opcode: 'Information request' StartHandle: '0003' EndHandle: '0006'
% Transmit the application response data (|chrsticDescDiscRespPDU|) to the % client through PHY [bleWaveform, pcapPackets{count}] = helperBLETransmitData(chrsticDescDiscRespPDU); count = count+1;
Receive Server response at Client
% Decode the received Bluetooth LE waveform and retrieve the application % data receivedPDU = helperBLEDecodeData(bleWaveform); % Decode received ATT PDU and generate response PDU, if applicable [~, chrsticDescDiscRespCfg] = receiveData(gattClient, receivedPDU); % Expected response from the server: |'Information response'| or |'Error % response'| if strcmp(chrsticDescDiscRespCfg.Opcode, 'Error response') fprintf("Received error response at the client:\n") chrsticDescDiscRespCfg chrsticDescDiscRespMsg = ['Error response(''' chrsticDescDiscRespCfg.ErrorMessage ''')']; else fprintf("Received characteristic descriptor discovery response at the client:\n") chrsticDescDiscRespCfg descriptor = helperBluetoothID.getBluetoothName(chrsticDescDiscRespCfg.AttributeType); chrsticDescDiscRespMsg = ['Characteristic descriptor discovery response(''' descriptor ''')']; end
Received characteristic descriptor discovery response at the client:
chrsticDescDiscRespCfg = bleATTPDUConfig with properties: Opcode: 'Information response' Format: '16 bit' AttributeHandle: '0004' AttributeType: '2902'
Subscribe for Notifications
After discovering the characteristic descriptors, the client may enable or disable notifications for its characteristic value. To enable notifications, the client must set the notification bit (first bit) of Client Characteristic Configuration Descriptor (CCCD) value by invoking 'Write characteristic value'
sub-procedure.
Client subscribe for notifications at Server
% Configure a GATT client to enable the notifications of Heart rate % measurement characteristic gattClient.SubProcedure = 'Write characteristic value'; gattClient.AttributeHandle = chrsticDescDiscRespCfg.AttributeHandle; gattClient.AttributeValue = '0100'; enableNotificationReqPDU = generateATTPDU(gattClient); % Transmit the application data (|enableNotificationReqPDU|) to the client % through PHY [bleWaveform, pcapPackets{count}] = helperBLETransmitData(enableNotificationReqPDU); count = count+1;
Receive Client request at Server
Decodes the received request and sends the response in a Write response ATT PDU.
% Decode the received Bluetooth LE waveform and retrieve the application % data receivedPDU = helperBLEDecodeData(bleWaveform); % Decode received ATT PDU and generate response PDU, if applicable [enableNotificationRespPDU, enableNotificationReqCfg, gattServer] = receiveData(gattServer, receivedPDU); fprintf("Received enable notification request at the server:\n")
Received enable notification request at the server:
enableNotificationReqCfg
enableNotificationReqCfg = bleATTPDUConfig with properties: Opcode: 'Write request' AttributeHandle: '0004' AttributeValue: [2x2 char]
% Transmit the application response data (|enableNotificationRespPDU|) to % the client through PHY [bleWaveform, pcapPackets{count}] = helperBLETransmitData(enableNotificationRespPDU); count = count+1;
Receive Server response at Client
% Decode the received Bluetooth LE waveform and retrieve the application % data receivedPDU = helperBLEDecodeData(bleWaveform); % Decode received ATT PDU and generate response PDU, if applicable [~, enableNotificationRespCfg] = receiveData(gattClient, receivedPDU); % Expected response from the server: |'Write response'| or |'Error % response'| if strcmp(enableNotificationRespCfg.Opcode, 'Error response') fprintf("Received error response at the client:\n") enableNotificationRespCfg enableNotificRespMsg = ['Error response(''' enableNotificationRespCfg.ErrorMessage ''')']; else fprintf("Received enable notification response at the client:\n") enableNotificationRespCfg enableNotificRespMsg = 'Notifications enabled(''Heart rate measurement '')'; end
Received enable notification response at the client:
enableNotificationRespCfg = bleATTPDUConfig with properties: Opcode: 'Write response'
Notifying the Heart Rate Measurement Value to the Client
When a client enables notifications for a characteristic, the server periodically notifies the value of characteristic (Heart rate measurement) to the client.
The HRP server notifies heart rate measurement to the client after its subscription.
Server sends notifications to Client
The notifyHeartRateMeasurement
object function of the helperBLEGATTServer
helper object generates notification PDU as specified in the Bluetooth core specification.
% Reset the random number generator seed rng default % Measure heart rate value using sensor (generate a random number for heart % rate measurement value) heartRateMeasurementValue = randi([65 95]); % Notify the heart rate measurement [gattServer, notificationPDU] = notifyHeartRateMeasurement(gattServer, ... heartRateMeasurementValue); % Transmit the application data (|notificationPDU|) to the client through % PHY [bleWaveform, pcapPackets{count}] = helperBLETransmitData(notificationPDU); count = count+1;
Receive Server notifications at Client
% Decode the received Bluetooth LE waveform and retrieve the application % data receivedPDU = helperBLEDecodeData(bleWaveform); % Decode received ATT PDU and generate response PDU, if applicable [~, notificationCfg] = receiveData(gattClient, receivedPDU); fprintf("Received notification at the client:\n")
Received notification at the client:
% Decode the received heart rate measurement characteristic value heartRateCharacteristicValue = helperBLEDecodeAttributeValue(... notificationCfg.AttributeValue, 'Heart rate measurement'); heartRateCharacteristicValue
heartRateCharacteristicValue = helperBLEAttributeValueConfig with properties: AttributeType: 'Heart rate measurement' HeartRateValueFormat: 'UINT8' SensorContactStatus: 'Contact detected' EnergyExpendedFieldFlag: 'Present, Units: Kilo Joules' RRIntervalFieldFlag: 'Present' HeartRateValue: 90 EnergyExpended: 100 RRInterval: 10
heartRateMeasurementValue = heartRateCharacteristicValue.HeartRateValue; % Visualize the Bluetooth LE GATT Client-Server model helperBLEVisualizeHRPFrame(serviceDiscRespMsg, chrsticDescRespMsg, ... chrsticDescDiscRespMsg, enableNotificRespMsg, heartRateMeasurementValue);
Exporting to a PCAP File
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.
Create an object of type blePCAPWriter
and specify the packet capture file name.
% Create the Bluetooth LE PCAP Writer file object pcapObj = blePCAPWriter("FileName", "bluetoothLEHRP");
Use the write
object function to write all the Bluetooth LE 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(pcapPackets) write(pcapObj, pcapPackets{idx}, timestamp, "PacketFormat", "bits"); end % Clear the object clear pcapObj; fprintf("Open generated pcap file 'bluetoothLEHRP.pcap' in a protocol analyzer to view the generated frames.\n")
Open generated pcap file 'bluetoothLEHRP.pcap' in a protocol analyzer to view the generated frames.
Visualization of the Generated ATT PDUs
Since the generated heart rate profile packets are compliant with the Bluetooth standard, you can open, analyze and visualize the PCAP file using a third party packet analyzer such as Wireshark [ 4 ]. The data shown in these figures uses the heart rate profile packets generated in this example.
Service discovery request
Service discovery response
Notifying heart rate measurement value
Conclusion
This example demonstrated the modeling of Bluetooth LE devices with Heart Rate Profile using the GATT client-server scenario as specified in the Bluetooth core specification [ 2 ]. You can use a packet analyzer to view the generated frames.
Appendix
The example uses these helpers:
helperBLEGATTClient
helperBLEGATTServer
—Create a GATT server objecthelperBLEAttributeValueConfig
— Create configuration object for a Bluetooth LE attribute valuehelperBLEGenerateAttributeValue
— Bluetooth LE attribute value generationhelperBLEDecodeAttributeValue
— Bluetooth LE attribute value decoderhelperBLEDecodeData
— Decode the received waveform and retrieve the application datahelperBLETransmitData
— Transmit application data by generating Bluetooth LE waveformhelperBluetoothID
— Bluetooth identifiers and their names assigned by the Bluetooth Special Interest Group (SIG)helperBLEVisualizeHRPFrame
— Visualize the Heart Rate Profile (HRP) frames exchanged in HRP ExamplehelperBLEPlotHRPFrames
— Plot the data frame exchange between the Heart rate profile server and client
Selected Bibliography
Bluetooth® Technology Website. "Bluetooth Technology Website | The Official Website of Bluetooth Technology." Accessed November 29, 2021. https://www.bluetooth.com
Bluetooth Special Interest Group (SIG). "Bluetooth Core Specification" Version 5.3. https://www.bluetooth.com
Bluetooth Special Interest Group (SIG). "Heart Rate Profile" Version 1.0. https://www.bluetooth.com
“Development/LibpcapFileFormat - The Wireshark Wiki.” Accessed November 29, 2021. https://www.wireshark.org
Group, The Tcpdump. “Tcpdump/Libpcap Public Repository.” Accessed November 29, 2021. https://www.wireshark.org
Tuexen, M. “PCAP Next Generation (Pcapng) Capture File Format.” 2021. https://www.ietf.org