BLE GAP Characteristics & Discovery Procedures

 

GAP Characteristics & Discovery Procedures

Chapter 14 · Part 2 of 3 · GAP Service Characteristics · Broadcast Mode · Discovery Modes · Limited, General & Name Discovery

5GAP characteristics
3 modesNondiscoverable to General
3 proceduresLimited, General, Name
AD Type flags0x01/0x02 discoverable bits
SEO Keywords

BLE GAP Device Name Characteristic 0x2A00 GATT read BLE Appearance Characteristic 0x2A01 icon type BLE PPCP 0x2A04 min max connection interval slave latency BLE broadcast mode ADV_NONCONN_IND unreliable BLE Limited Discoverable mode LE Limited flag BLE General Discoverable mode LE General flag BLE Name Discovery GATT Read UUID 0x2A00 BlueZ btmgmt advertising discoverable

14.5 — GAP Characteristics

The GAP Service — One Instance Per Device

GAP defines its own GATT service (UUID = <<Generic Access Profile>>) that every LE device exposes exactly once. This service holds characteristics that provide basic device information — name, visual appearance, privacy settings, and preferred connection parameters. Any Central can read these after connecting without any special permissions.

0x2A00

14.5.1 — Device Name

A UTF-8 encoded string up to 248 octets long, null-terminated if shorter. This is how any Central learns what to call this device on screen without asking the user. Value: “BT Thermometer”, “SmartPhone”, etc.

Figure 14.7 — Reading Device Name Characteristic (4 ATT frames)
Master (Central)Slave (Peripheral)
Frame #283 — Read Request (Handle=2, UUID=Characteristic 0x2803)
Frame #286 — Read Response: Char = Device Name, Value Handle = 3
Frame #289 — Read Request (Handle=3, UUID=Device Name 0x2A00)
Frame #292 — Read Response: Value = “Battery V1.0”

The Master first reads the Characteristic Declaration at handle 2 to confirm it contains Device Name, then reads the actual Device Name value at handle 3. Two round trips instead of one — but the result is an unambiguous confirmed name read.

0x2A01

14.5.2 — Appearance

A 2-byte value (from the Bluetooth Assigned Numbers document) that tells the connecting device what category this device belongs to. The Central can then show an appropriate icon — headset, phone, printer, watch, thermometer. This is the LE equivalent of the BR/EDR Class of Device.

Figure 14.8 — Reading Appearance Characteristic (4 ATT frames)
MasterSlave
Frame #299 — Read Request (Handle=4, UUID=Characteristic)
Frame #302 — Read Response: Char = Appearance, Value Handle = 5
Frame #305 — Read Request (Handle=5, UUID=Appearance 0x2A01)
Frame #308 — Read Response: “Unknown Appearance”

0x2A02

14.5.3 — Peripheral Privacy Flag

A 1-byte flag indicating whether the Peripheral is currently using a random private address. Value 0x00 = privacy off, 0x01 = privacy on. If the Central is allowed to write this characteristic, it can remotely toggle privacy on the Peripheral without physical access to the device.

0x2A03

14.5.4 — Reconnection Address

A 6-byte address the Peripheral stores so the Central knows which address to connect to next session. When a device using privacy rotates its random address, it writes the new address here so its bonded peers can find it again without scanning. Updated at each connection as needed.

0x2A04

14.5.5 — Peripheral Preferred Connection Parameters (PPCP)

An 8-byte structure that tells the Central what connection parameters this Peripheral would prefer. The Central is not obligated to use these values but should consider them when setting up the connection to balance performance and power consumption for the Peripheral.

Figure 14.9 + Table 14.2 — PPCP Read and Decode (8 octets)
Field Size Value (ff ff / 00 00) Meaning
Min Connection Interval 2 ff ff No specific minimum
Max Connection Interval 2 ff ff No specific maximum
Slave Latency 2 00 00 0 events — respond to every event
Supervision Timeout Multiplier 2 ff ff No specific value requested
Raw 8-byte PPCP value: ff ff ff ff 00 00 ff ff (little-endian, from Frame #328)

When all interval fields are 0xFFFF it means the Peripheral has no preference — the Central can choose whatever interval works best for the use case. Peripherals that need specific timing (e.g. a device streaming audio that requires short intervals) would set concrete values here.

/* Read all GAP service characteristics:                      */
gatttool -b AA:BB:CC:DD:EE:FF --primary --uuid=0x1800
/* attr handle: 0x0001, end grp handle: 0x0007 uuid: 0x1800  */

gatttool -b AA:BB:CC:DD:EE:FF --characteristics \
         --start=0x0001 --end=0x0007

/* Read Device Name (handle 3 in most devices):               */
gatttool -b AA:BB:CC:DD:EE:FF --char-read --handle=0x0003

/* Read Appearance:                                           */
gatttool -b AA:BB:CC:DD:EE:FF --char-read --handle=0x0005

/* Read PPCP (8 bytes, little-endian fields):                 */
gatttool -b AA:BB:CC:DD:EE:FF --char-read --handle=0x0007
/* ff ff ff ff 00 00 ff ff → no preference for most params   */

/* With bluetoothctl after connecting:                        */
[AA:BB:CC:DD:EE:FF]# info
/* Name: Battery V1.0                                        */
/* Appearance: Generic tag                                   */

14.6.1 — Broadcast Mode and Observation Procedure

Simplest LE Data Distribution — No Connection, No Ack

The Broadcast mode is the most stripped-down data delivery mechanism in BLE. A Broadcaster sends data outward in advertising events continuously, with no mechanism to know if anyone received it. An Observer receives those events with no ability to respond or connect. Data is considered unreliable — lost packets are simply gone.

This one-way pattern is extremely power-efficient for the Broadcaster because there is no connection state to maintain. iBeacon transmitters, Eddystone beacons, environmental sensor tags, and retail price displays all operate in broadcast mode.

Broadcast Mode vs Observation Procedure
Broadcast Mode (Broadcaster)
→ ADV_NONCONN_IND or ADV_SCAN_IND
→ Periodic, no ACK expected
→ May have no receiver hardware
Unreliable — lost = lost
Observation Procedure (Observer)
← Passive scan: just receive AdvData
← Active scan: send SCAN_REQ too
← May have no transmitter hardware
No CONNECT_REQ ever sent
/* Set up a broadcaster with BlueZ hcitool:                   */
/* Set non-connectable advertising:                           */
sudo hcitool -i hci0 cmd 0x08 0x0008 \
    00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

/* Enable advertising (non-connectable type = 0x03):          */
sudo hciconfig hci0 leadv 3

/* With btmgmt (newer BlueZ interface):                       */
sudo btmgmt add-adv --connectable false --scannable false \
    --data "020106 09094d79426561636f6e"

/* Observe advertising with hcitool passive scan:             */
sudo hcitool lescan --passive
/* Devices appear with addresses and names (if in AdvData)    */

/* Raw advertising reports via btmon:                         */
sudo btmon 2>&1 | grep -A 8 "ADV_NONCONN_IND"

14.6.2 — Discovery Modes and Procedures

Three Modes, Three Procedures — How Devices Find Each Other

Discovery is the mechanism by which a Central finds Peripherals nearby and decides which ones to connect to. The Peripheral controls whether it is discoverable (via the Flags AD Type in its advertisements). The Central controls which Peripherals it considers found (via the discovery procedure it is running).

Nondiscoverable Mode (Mandatory)
No advertising packets OR
Flags not set (both bits = 0)
Device is invisible to all discovery procedures. Does not appear in any scan results.
Limited Discoverable (Optional)
Flags byte: LE_Limited_Disc = 1
LE_General_Disc = 0
Visible for a limited time only — e.g. 30s after pressing a button. Found by Limited and General discovery.
General Discoverable (Mandatory*)
Flags byte: LE_Limited_Disc = 0
LE_General_Disc = 1
Indefinitely visible. Found by General discovery only (not Limited). Standard mode for most devices.
* General Discoverable is mandatory if Limited Discoverable is not implemented, otherwise optional.

14.6.2.2 & 14.6.2.3 — Limited Discoverable Mode + Limited Discovery Procedure

Limited discoverability is designed for devices that should only be pairable for a short window — like a sensor that enters pairing mode when the user holds a button. After the window expires, the device stops advertising with the Limited flag, becoming invisible until the user activates it again.

Figure 14.10 — Limited Discoverable Mode and Limited Discovery Procedure
Central (executing Limited Discovery) Peripheral (Limited Discoverable)

Start Scanning
For each packet received: check Flags AD Type
If LE_Limited_Discoverable = 1 → add to list
Stop Scanning

Advertising Event (Flags=Limited)

Set Flags AD Type:
LE_Limited = 1, LE_General = 0
ADV_IND / ADV_NONCONN_IND /
ADV_SCAN_IND with Limited flag
/* Enable Limited Discoverable mode with btmgmt:              */
/* Flags 0x01 = LE Limited Discoverable                       */
sudo btmgmt power on
sudo btmgmt connectable on
sudo btmgmt limited-discov on      /* sets Limited flag       */

/* After timeout, disable:                                    */
sudo btmgmt limited-discov off

/* With hciconfig (older interface):                          */
sudo hciconfig hci0 up
sudo hciconfig hci0 leadv 0   /* 0 = connectable + limited   */

/* Check Flags value in advertising packet:                   */
sudo btmon 2>&1 | grep "Flags:"
/* Flags: 0x01 (LE Limited Discoverable Mode)                 */

14.6.2.4 & 14.6.2.5 — General Discoverable Mode + General Discovery Procedure

General discoverability is the default mode for most BLE devices. The device advertises continuously with the LE General Discoverable flag set and stays visible indefinitely. The General Discovery Procedure on the Central collects both General and Limited Discoverable devices — it is intentionally inclusive. Any device with either discoverable flag set gets added to the Central’s found-devices list.

Figure 14.11 — General Discoverable Mode and General Discovery Procedure
Central (General Discovery) Peripheral (General Discoverable)
Start Scanning
For each packet: check Flags AD Type
If LE_General = 1 OR LE_Limited = 1
→ add to found list
Stop Scanning
Advertising Event (Flags=General)
Set Flags AD Type:
LE_Limited = 0, LE_General = 1
ADV_IND / ADV_NONCONN_IND /
ADV_SCAN_IND continuously
/* Enable General Discoverable mode with btmgmt:              */
sudo btmgmt power on
sudo btmgmt connectable on
sudo btmgmt discov on              /* sets General flag        */

/* BlueZ hciconfig:                                           */
sudo hciconfig hci0 piscan         /* page + inquiry scan      */
/* For LE advertising with General Discoverable flag:         */
sudo hciconfig hci0 leadv          /* default = general        */

/* Flags byte in advertisement:                               */
/* 0x02 = LE General Discoverable Only                        */
/* 0x06 = LE General Discoverable + BR/EDR Not Supported      */

/* Scan from Central side:                                    */
sudo hcitool lescan
/* [AA:BB:CC:DD:EE:FF] Battery V1.0 (found via General disc.) */

14.6.2.6 — Name Discovery Procedure

Once a Central has discovered a device through General or Limited discovery, it may have only a shortened name (or no name at all) from the advertising packet. Name Discovery fills in the full name by reading the Device Name Characteristic via GATT. The procedure involves connecting, reading the characteristic, then disconnecting if the connection was opened only for this purpose.

Figure 14.12 — Name Discovery: Advertising + GATT Fallback
Central Peripheral
Path 1 — Name available in advertising event:
Advertising Event (AD Type 0x08 or 0x09 = Local Name included)
Central reads name from advertising packet directly — no connection needed
Path 2 — Shortened name or no name in ads → use GATT:
CONNECT_REQ → connection established
Read By Type Request (Start=0x0000, End=0xFFFF, UUID=0x2A00)
Read By Type Response (Length, Attribute Handle, Full Device Name)
Terminate connection (if opened only for name discovery)
/* Name Discovery — BlueZ does this automatically:            */
/* When you scan and connect, BlueZ reads Device Name char    */

/* Manual: read name characteristic after connecting:         */
gatttool -b AA:BB:CC:DD:EE:FF --char-read --uuid=0x2A00
/* This uses Read Using Characteristic UUID sub-procedure     */
/* = Read By Type Request with UUID=0x2A00                    */

/* In bluetoothctl:                                           */
[AA:BB:CC:DD:EE:FF]# info
/* Name: Battery V1.0  (fetched from GATT if not in adv)     */

/* Check if name is in advertising data first:               */
sudo btmon 2>&1 | grep "Name:"
/* Complete Local Name: Battery V1.0  ← from AD Type 0x09    */
/* Shortened Local Name: Battery      ← from AD Type 0x08    */

Leave a Reply

Your email address will not be published. Required fields are marked *