910  Bluetooth Protocol Stack and GATT

910.1 Learning Objectives

By the end of this chapter, you will be able to:

  • Describe the Bluetooth protocol stack from PHY to application layer
  • Understand GATT architecture with services, characteristics, and descriptors
  • Design custom GATT services for IoT sensor applications
  • Choose between Notify and Indicate for different reliability requirements
  • Implement standard Bluetooth SIG profiles for interoperability

910.2 Prerequisites

Before diving into this chapter, you should be familiar with:

910.3 Bluetooth Protocol Stack

910.3.1 Classic Bluetooth Stack

The Classic Bluetooth stack is designed for continuous data streaming:

Layer Purpose Key Components
Application User applications Audio, file transfer
Profiles Application behavior A2DP, HFP, SPP, HID
RFCOMM Serial port emulation Virtual COM ports
L2CAP Logical link control Multiplexing, segmentation
Link Manager Connection management Security, power control
Baseband Packet handling Piconet, frequency hopping
Radio Physical transmission 2.4 GHz, GFSK modulation

910.3.2 BLE Protocol Stack

BLE uses a simplified stack optimized for low power:

Layer Purpose Key Components
Application User applications Sensor data, beacons
GATT Data organization Services, characteristics
ATT Attribute protocol Read, write, notify
L2CAP Logical link Fixed channels, CoC
Link Layer Packets, connections Advertising, data channels
PHY Physical layer 1M, 2M, Coded PHY

910.3.3 Key Differences

Aspect Classic Bluetooth BLE
Data Model Stream-based (RFCOMM) Attribute-based (GATT)
Connection Persistent Can be transient
Profiles Complex (A2DP, HFP) Simple (GATT services)
Discovery Profile-specific Universal GATT discovery

910.4 GATT Architecture

GATT (Generic Attribute Profile) organizes data like a file system:

910.4.1 Hierarchy

Profile (Use case definition)
  |
  +-- Service (Group of related data)
        |
        +-- Characteristic (Individual data point)
              |
              +-- Value (The actual data)
              +-- Descriptor (Metadata, configuration)

910.4.2 Services

Services group related characteristics:

Standard Services (Bluetooth SIG defined):

UUID Service Description
0x1800 Generic Access Device name, appearance
0x1801 Generic Attribute Service change indication
0x180A Device Information Manufacturer, model, serial
0x180F Battery Service Battery level
0x181A Environmental Sensing Temperature, humidity
0x180D Heart Rate Heart rate measurement

Custom Services:

Use 128-bit UUIDs for proprietary data:

// Custom service UUID (generated)
#define CUSTOM_SERVICE_UUID "4fafc201-1fb5-459e-8fcc-c5c9c331914b"

910.4.3 Characteristics

Characteristics are individual data values with properties:

Properties:

Property Code Description
Read 0x02 Client can read value
Write 0x08 Client can write (with response)
Write No Response 0x04 Client can write (no ack)
Notify 0x10 Server can push (no ack)
Indicate 0x20 Server can push (with ack)

Choosing Properties:

Use Case Properties Example
On-demand sensor reading Read Temperature on request
Real-time streaming Notify Heart rate updates
Critical alerts Indicate Low battery warning
Configuration Read + Write Alarm threshold
Commands Write No Response LED on/off

910.4.4 Descriptors

Descriptors provide metadata about characteristics:

Common Descriptors:

UUID Name Purpose
0x2900 Characteristic Extended Properties Additional properties
0x2901 Characteristic User Description Human-readable name
0x2902 Client Characteristic Configuration Enable notify/indicate
0x2904 Characteristic Presentation Format Units, exponent

CCCD (0x2902):

The Client Characteristic Configuration Descriptor is critical for notifications:

// Client writes to CCCD to enable/disable notifications
// 0x0000 = Disabled
// 0x0001 = Notifications enabled
// 0x0002 = Indications enabled

910.5 Notification vs Indication

Understanding when to use each is crucial:

910.5.1 Notifications (Fire-and-Forget)

  • Server pushes data without confirmation
  • Lower latency (no round-trip)
  • Possible data loss if packet dropped
  • Best for: High-frequency telemetry
// Server sends notification
pCharacteristic->setValue(sensorData, sizeof(sensorData));
pCharacteristic->notify();  // No confirmation expected

910.5.2 Indications (Confirmed Delivery)

  • Server waits for client acknowledgment
  • Higher latency (requires ACK)
  • Guaranteed delivery (retries if failed)
  • Best for: Critical data, configuration
// Server sends indication
pCharacteristic->setValue(alertData, sizeof(alertData));
pCharacteristic->indicate();  // Blocks until ACK received

910.5.3 Comparison

Aspect Notify Indicate
Acknowledgment No Yes
Latency Lower Higher
Throughput Higher Lower
Reliability Best-effort Guaranteed
Use Case Sensor streaming Alerts, config

910.5.4 Common Pitfall

CautionPitfall: Misunderstanding GATT Notification vs Indication

The Mistake: Using indications (confirmed) when notifications (unconfirmed) would suffice, or vice versa, leading to either unnecessary latency/overhead or silent data loss.

Why It Happens: Both seem to “push” data from peripheral to central. Developers don’t realize indications require ACK (adding round-trip latency) while notifications are fire-and-forget.

The Fix: Use notifications for high-frequency telemetry where occasional packet loss is acceptable (sensor readings, heart rate). Use indications only for critical data that must be confirmed (configuration changes, alarms). Never use indications for streaming data—the ACK overhead will throttle throughput to a fraction of potential.

910.6 Designing Custom GATT Services

910.6.1 Example: Environmental Sensor

Design a GATT service for a multi-sensor environmental monitor:

Service Definition:

Environmental Monitoring Service (Custom UUID)
  |
  +-- Temperature Characteristic
  |     UUID: 0x2A6E (standard)
  |     Properties: Read, Notify
  |     Format: sint16 (0.01 degree resolution)
  |
  +-- Humidity Characteristic
  |     UUID: 0x2A6F (standard)
  |     Properties: Read, Notify
  |     Format: uint16 (0.01% resolution)
  |
  +-- Pressure Characteristic
  |     UUID: Custom 128-bit
  |     Properties: Read, Notify
  |     Format: uint32 (0.1 Pa resolution)
  |
  +-- Sampling Rate Characteristic
        UUID: Custom 128-bit
        Properties: Read, Write
        Format: uint16 (seconds)

910.6.2 Implementation

// Service UUIDs
#define ENV_SERVICE_UUID           "181A"  // Standard Environmental Sensing
#define TEMP_CHAR_UUID             "2A6E"  // Standard Temperature
#define HUMIDITY_CHAR_UUID         "2A6F"  // Standard Humidity
#define PRESSURE_CHAR_UUID         "custom-uuid-here"
#define SAMPLING_CHAR_UUID         "custom-uuid-here"

void setupGATT() {
    // Create service
    BLEService* pEnvService = pServer->createService(ENV_SERVICE_UUID);

    // Temperature (Read + Notify)
    pTempChar = pEnvService->createCharacteristic(
        TEMP_CHAR_UUID,
        BLECharacteristic::PROPERTY_READ |
        BLECharacteristic::PROPERTY_NOTIFY
    );
    pTempChar->addDescriptor(new BLE2902());  // Enable CCCD

    // Humidity (Read + Notify)
    pHumidityChar = pEnvService->createCharacteristic(
        HUMIDITY_CHAR_UUID,
        BLECharacteristic::PROPERTY_READ |
        BLECharacteristic::PROPERTY_NOTIFY
    );
    pHumidityChar->addDescriptor(new BLE2902());

    // Sampling Rate (Read + Write for configuration)
    pSamplingChar = pEnvService->createCharacteristic(
        SAMPLING_CHAR_UUID,
        BLECharacteristic::PROPERTY_READ |
        BLECharacteristic::PROPERTY_WRITE
    );

    pEnvService->start();
}

910.6.3 Data Formatting

BLE uses little-endian byte order:

// Temperature: 25.50 degrees Celsius
// Format: sint16, resolution 0.01
int16_t tempValue = 2550;  // 25.50 * 100

uint8_t tempData[2];
tempData[0] = tempValue & 0xFF;         // Low byte first
tempData[1] = (tempValue >> 8) & 0xFF;  // High byte second

pTempChar->setValue(tempData, 2);
pTempChar->notify();

910.7 Standard Profiles

910.7.1 Heart Rate Service (0x180D)

Used by fitness trackers and medical devices:

Characteristics:

UUID Name Properties
0x2A37 Heart Rate Measurement Notify
0x2A38 Body Sensor Location Read
0x2A39 Heart Rate Control Point Write

Data Format (0x2A37):

Byte 0: Flags
  Bit 0: Heart Rate Value Format (0=uint8, 1=uint16)
  Bit 1-2: Sensor Contact Status
  Bit 3: Energy Expended Present
  Bit 4: RR-Interval Present

Byte 1-2: Heart Rate Value (uint8 or uint16)
Byte 3-4: Energy Expended (optional, uint16)
Byte 5+: RR-Intervals (optional, uint16[])

910.7.2 Battery Service (0x180F)

Simple battery level reporting:

Characteristics:

UUID Name Properties
0x2A19 Battery Level Read, Notify

Data Format:

Single byte, 0-100 representing percentage.

910.7.3 Device Information Service (0x180A)

Manufacturer and model information:

Characteristics:

UUID Name Content
0x2A29 Manufacturer Name “Acme Inc”
0x2A24 Model Number “Sensor-v1”
0x2A25 Serial Number “SN123456”
0x2A26 Firmware Revision “1.2.3”
0x2A27 Hardware Revision “A”
0x2A28 Software Revision “2.0.0”

910.8 Adaptive Frequency Hopping

Bluetooth uses frequency hopping to avoid interference:

TipMinimum Viable Understanding: Adaptive Frequency Hopping (AFH)

Core Concept: Bluetooth mitigates 2.4 GHz interference by rapidly hopping between channels (1600 hops/second for Classic, variable for BLE) and adaptively blacklisting channels where interference is detected. Classic Bluetooth uses 79 channels (1 MHz each), while BLE uses 40 channels (2 MHz each) with 37 for data and 3 for advertising.

Why It Matters: The 2.4 GHz ISM band is the most crowded spectrum in IoT, shared by Wi-Fi, Zigbee, microwave ovens, and other Bluetooth devices. Without frequency hopping, a single interferer (like a Wi-Fi access point on channel 6) could completely block communication. AFH typically recovers from Wi-Fi interference within 5-10 seconds by mapping out and avoiding the occupied frequencies.

Key Takeaway: If you experience Bluetooth audio dropouts or BLE sensor disconnections, check for Wi-Fi channel overlap first. Move your Wi-Fi router to channel 1 or 11 (which overlap fewer Bluetooth data channels), or place the Bluetooth central device away from the Wi-Fi access point. For BLE, advertising channels 37, 38, and 39 are specifically positioned between Wi-Fi channels 1, 6, and 11 to ensure discovery works even in congested environments.

910.9 Summary

This chapter covered the Bluetooth protocol stack and GATT architecture:

  • Classic Bluetooth uses RFCOMM for stream-based data (audio, file transfer)
  • BLE uses GATT for attribute-based data (sensors, configuration)
  • GATT hierarchy: Profile -> Service -> Characteristic -> Descriptor
  • Properties (Read, Write, Notify, Indicate) control data access patterns
  • Notifications are fast but unconfirmed; Indications are confirmed but slower
  • Standard services (Heart Rate, Battery, Device Info) ensure interoperability
  • Custom services use 128-bit UUIDs for proprietary data
  • Little-endian byte order is mandatory for BLE data formatting

910.10 What’s Next

The next chapter, Bluetooth Profiles, explores the major Bluetooth profiles including SPP (Serial Port), HID (Human Interface Device), and A2DP (Advanced Audio Distribution) for audio streaming.