HCI CODING EXAMPLES:
—————————————-
ADVERTISING:
1. Advertising Types (ADV Types)
This controls how your device behaves.
ADV_IND (0x00) → Connectable + scannable (most common)
ADV_DIRECT_IND (0x01) → Directed (connect to a specific device)
ADV_SCAN_IND (0x02) → Scannable only (no connections)
ADV_NONCONN_IND (0x03) → Non-connectable beacon
ADV_DIRECT_IND_LOW_DUTY (0x04) → Directed, low duty
👉 Use cases:
Connectable device → ADV_IND
Beacon → NONCONN_IND
Fast reconnect → DIRECT_IND
2. Advertising Intervals
Controls how frequently packets are sent
Range: 20 ms → 10.24 seconds
Formula:
interval = value * 0.625 ms
Examples:
0x0020 → 20 ms (fast advertising)
0x0800 → 1.28 sec (low power)
0x4000 → 10.24 sec (very low power)
3. Advertising Channels
BLE uses 3 primary channels:
Channel 37
Channel 38
Channel 39
You can configure:
adv_params.chan_map = 0x01; // only ch37
adv_params.chan_map = 0x07; // all channels
4. Address Types (Very Important)
Defines identity/privacy behavior:
Public Address (0x00)
→ Fixed MAC (hardware)
Random Address (0x01)
Types inside:
Static random
Private resolvable
Private non-resolvable
5. Advertising Data (Payload)
Max size: 31 bytes
Common AD structures:
Flags (mandatory)
Local Name (short/full)
Manufacturer Specific Data
Service UUIDs
TX Power
Appearance
6. Scan Response Data
Extra 31 bytes sent only when scanner requests
👉 Use when:
Advertising packet is full
You want detailed info only for interested devices
7. Advertising Filter Policy
Controls who can:
Scan you
Connect to you
Options:
Allow all
Allow only whitelist
8. Directed Advertising
You can target a specific device:
adv_params.advtype = ADV_DIRECT_IND;
bacpy(&adv_params.direct_bdaddr, &target_addr);
👉 Used for:
Fast reconnection (no scanning needed)
🔹 9. Whitelisting
You can restrict advertising to known devices:
Add device to whitelist
Set filter policy
🔹 10. TX Power Control
Some controllers support:
Set advertising TX power
Reduce power for nearby devices
Increase for range
🔹 11. Extended Advertising (BLE 5+)
(Advanced, not in your current code)
Payload > 31 bytes (up to 255 bytes)
Secondary channels
Multiple advertising sets
🔹 12. Periodic Advertising (BLE 5)
Broadcast data at fixed intervals
No connection required
🔹 13. Scannable vs Non-Scannable
Scannable → responds with scan response
Non-scannable → pure broadcast (beacon)
🔹 14. Connectable vs Non-Connectable
Connectable → allows GATT connection
Non-connectable → beacon only
🔹 15. Advertising Modes (Behavioral)
Not explicit in HCI, but derived:
Fast advertising
Slow advertising
Directed fast
Directed slow
🔥 Summary (What you can vary)
You can create combinations like:
Fast connectable advertiser
Low power beacon
Private address rotating advertiser
Directed reconnect advertiser
Manufacturer data broadcaster (like iBeacon)
Service UUID advertiser
Secure whitelist advertiser
Fast advertising (20 ms)
Low power advertising (5 sec)
Non-connectable beacon (iBeacon style)
Random address advertiser
Directed advertising example
Manufacturer data example
UUID-based advertising
Whitelist-based advertising
What you can do purely using HCI (no GAP/GATT)
All of these are controller-level features, so your current approach supports them:
🔹 Core Advertising Control
Set advertising parameters (LE Set Advertising Parameters)
Set advertising interval (fast/slow)
Set advertising type (ADV_IND, NONCONN, DIRECT, etc.)
Enable/disable advertising
🔹 Payload Control
Set advertising data (31 bytes)
Set scan response data (31 bytes)
Add:
Local name
Manufacturer data (iBeacon-style)
Service UUIDs
Flags
🔹 Addressing & Privacy
Public address
Random address (LE Set Random Address)
Static / private random (if controller supports it)
🔹 Filtering & Security (basic level)
Whitelist (add/remove devices)
Filter policy (who can scan/connect)
🔹 Directed Advertising
Target specific device using its MAC
🔹 Channel & PHY-level configs
Channel map (37/38/39)
TX power (if supported via vendor commands)
🔹 Extended / Periodic Advertising (BLE 5+)
Yes, still HCI, but:
Requires newer commands:
LE Set Extended Advertising Parameters
LE Set Extended Advertising Data
Controller must support it
1. Advertising “Dimensions” (All controllable via HCI)
These are the parameters you can mix & match:
🔹 (A) Advertising Type
Connectable + Scannable → ADV_IND
Directed (high duty / low duty)
Scannable only → ADV_SCAN_IND
Non-connectable → ADV_NONCONN_IND
🔹 (B) Address Type
Public
Random Static
Random Private Resolvable (RPA)
Random Private Non-Resolvable (NRPA)
🔹 (C) Advertising Interval
Ultra fast → 20–100 ms
Fast → 100–500 ms
Medium → 500 ms–2 sec
Slow → 2–10 sec
🔹 (D) Channels
Single channel (37 / 38 / 39)
Dual channel
All channels (recommended)
🔹 (E) Payload Composition (31 bytes legacy / 255 extended)
Flags
Device Name
Manufacturer Data (0xFF)
Service UUIDs (16/32/128-bit)
Service Data
TX Power
Appearance
🔹 (F) Scan Response
Enabled / Disabled
Carry extra data
🔹 (G) Filter Policy
Allow all
Whitelist scan
Whitelist connect
Both restricted
🔹 (H) TX Power
Low / Medium / High (controller dependent)
🔹 (I) PHY (BLE 5 feature)
1M PHY
2M PHY
Coded PHY (Long Range – S2/S8)
🔹 (J) Advertising Mode (Behavior)
Undirected
Directed (to specific device)
High duty cycle
Low duty cycle
🔹 (K) Extended Advertising (BLE 5+)
Multiple advertising sets
Secondary channels
Large payloads (up to 255 bytes)
🔹 (L) Periodic Advertising (BLE 5+)
Broadcast at fixed intervals
No connection needed
🔥 2. Now the REAL part: Practical Combinations
Instead of listing thousands, here are real meaningful combinations you can implement using HCI.
✅ CATEGORY 1: Standard Device Advertising
1. Connectable Device (Typical Peripheral)
ADV_IND
Public/Random address
Medium interval (100–500 ms)
Scan response enabled
👉 Example: BLE sensor, smartwatch
2. Fast Pairing Mode
ADV_IND
Very fast interval (20–50 ms)
All channels
👉 Used during pairing window
3. Low Power Connectable
ADV_IND
Slow interval (1–5 sec)
👉 Battery devices
✅ CATEGORY 2: Beacon / Broadcast Devices
4. Non-connectable Beacon
ADV_NONCONN_IND
Manufacturer data
No scan response
👉 iBeacon / Eddystone style
5. Scannable Beacon
ADV_SCAN_IND
Extra data in scan response
6. Privacy Beacon
Non-connectable
Random private address (rotating)
👉 Anti-tracking systems
✅ CATEGORY 3: Directed Advertising
7. Fast Reconnect
ADV_DIRECT_IND (high duty)
Target specific MAC
👉 Earbuds reconnecting to phone
8. Low Duty Directed
ADV_DIRECT_IND_LOW
👉 Power-saving reconnect attempts
✅ CATEGORY 4: Secure / Restricted Advertising
9. Whitelist-Based Device
Only known devices can scan/connect
10. Private Identity Device
RPA address + whitelist
👉 Secure IoT
✅ CATEGORY 5: Advanced Payload Designs
11. Service-Based Advertising
Advertise UUIDs
Connectable
12. Manufacturer Data Streaming
Encode sensor data in payload
13. Split Data Strategy
Basic info in ADV
Detailed info in scan response
✅ CATEGORY 6: BLE 5 Extended Advertising
14. Large Payload Broadcaster
Extended ADV
100–255 bytes
15. Multi-Advertising Sets
Multiple identities simultaneously
👉 Example:
Device name A
Beacon mode B
Debug mode C
16. High-Speed Advertising
2M PHY
17. Long Range Advertising
Coded PHY (S=2 / S=8)
✅ CATEGORY 7: Periodic Advertising
18. Sensor Broadcasting System
Periodic advertising
No connection
19. Sync-Based Systems
Devices sync to periodic advertiser
————————————–
scanning:
1. Scanning “Dimensions” (HCI controllable)
🔹 (A) Scan Type
Passive Scanning (0x00)
Just listen to advertisements
No scan requests sent
Active Scanning (0x01)
Sends Scan Request
Receives Scan Response
👉 Key difference:
Passive → low power, silent
Active → more data, more power
🔹 (B) Scan Interval & Window
These are the most important parameters.
Scan Interval → how often scanning starts
Scan Window → how long scanning stays ON
Formula:
time = value × 0.625 ms
💡 Behavior based on combination:
window == interval → Continuous scanning
window < interval → Duty-cycled scanning
Examples:
High performance → interval=window=50 ms
Low power → interval=1 sec, window=100 ms
🔹 (C) Address Type (Scanner side)
Public
Random
Private (RPA)
🔹 (D) Filter Policy
Controls which packets you accept:
Accept all
Only whitelist devices
Ignore non-whitelist
🔹 (E) Duplicate Filtering
Enabled → avoids repeated reports
Disabled → get every packet
👉 Very important for:
RSSI tracking
Real-time monitoring
🔹 (F) PHY (BLE 5+)
1M PHY
Coded PHY (long range)
🔹 (G) Extended Scanning (BLE 5)
Scan extended advertisements
Receive large payloads
Multiple PHYs simultaneously
🔹 (H) Scan Timeout / Duration
Scan continuously
Scan for fixed duration
🔥 2. What You Actually Receive (HCI Events)
When scanning, controller sends:
🔹 LE Advertising Report
Contains:
Advertiser address
Address type
RSSI
Advertising data
Event type (ADV_IND, SCAN_RSP, etc.)
🔹 LE Extended Advertising Report (BLE 5)
Includes:
PHY info
SID (advertising set ID)
Data status (complete/partial)
🔥 3. Practical Scanning Combinations
Now the real part—what you can build.
✅ CATEGORY 1: Basic Scanners
1. Passive Scanner (Sniffer Mode)
Passive scan
Continuous window
No duplicates filtering
👉 Use case:
Debugging BLE traffic
Learning packet formats
2. Active Scanner (Full Data Collector)
Active scan
Receives scan response
Duplicate filtering OFF
👉 You get:
Full device name
Extra payload
3. Low Power Scanner
Passive scan
Small window, large interval
👉 Battery-efficient devices
✅ CATEGORY 2: Smart Filtering Scanners
4. Whitelist Scanner
Only accept known devices
5. Manufacturer Data Filter
(You filter in software after HCI event)
👉 Example:
Only detect iBeacons
6. UUID-Based Scanner
Parse service UUIDs
✅ CATEGORY 3: Advanced Monitoring
7. RSSI Tracker
Disable duplicate filtering
Continuously receive packets
👉 Used for:
Distance estimation
Indoor positioning
8. Presence Detection System
Detect device appearance/disappearance
9. Packet Frequency Analyzer
Measure advertising interval of devices
✅ CATEGORY 4: BLE 5 Advanced Scanning
10. Extended Advertising Scanner
Receive >31 byte payloads
11. Multi-PHY Scanner
Scan on:
1M PHY
Coded PHY simultaneously
12. Long Range Scanner
Focus only on coded PHY
✅ CATEGORY 5: Hybrid / Intelligent Scanners
13. Adaptive Scanner
Start passive
Switch to active if interesting device found
14. Trigger-Based Scanner
Scan → detect device → trigger action
15. Selective Deep Scan
Passive scan all
Active scan only specific devices
🔥 4. Powerful Combinations (Real Systems)
🚀 Combo 1: BLE Sniffer Tool
Passive
No duplicate filtering
Continuous scan
Log raw packets
🚀 Combo 2: Smart Device Discovery
Passive → detect devices
Active → fetch full data
🚀 Combo 3: Indoor Positioning Node
Passive
No duplicate filtering
RSSI tracking
🚀 Combo 4: Secure Scanner
Whitelist enabled
Ignore unknown devices
⚠️ Important Limitations (HCI-only)
Even though scanning is powerful:
You only get advertising data
No connection-level interaction
No GATT reads/writes
👉 Same rule:
HCI = observation
GATT = interaction
What you can do with HCI (connections)
Using raw HCI commands (like you’re already using in BlueZ), you can:
🔹 1. Initiate a Connection (Central role)
Use:
LE Create Connection
You can:
Scan for a device
Connect using its address
Set connection parameters:
Interval
Latency
Supervision timeout
👉 So yes — you can act as a central device
🔹 2. Accept a Connection (Peripheral role)
If you’re advertising:
A remote device connects
You receive:
LE Connection Complete Event
👉 So you can act as a peripheral
🔹 3. Manage Connection Parameters
You can:
Update connection parameters
Disconnect
Monitor RSSI
Handle connection events
🔹 4. Exchange Raw Data (L2CAP level)
You can go one level deeper:
Send/receive L2CAP packets
👉 This is below GATT
❌ What you CANNOT realistically do (without GAP/GATT)
This is where things break down.
🔴 1. No GATT = No Real Application
You cannot:
Define services
Define characteristics
Read/write attributes
Send notifications
👉 So connection exists, but:
👉 no meaningful data exchange at application level
🔴 2. No ATT Protocol Handling
GATT is built on ATT.
Without it:
You must manually implement:
ATT request/response
Attribute database
👉 That’s basically writing your own BLE stack
🔴 3. Pairing & Security is Hard
You’ll need to implement:
SMP (Security Manager Protocol)
Key exchange
Encryption handling
👉 HCI gives primitives, not full flow
🔴 4. No GAP State Machine
You lose:
Role management
Advertising state transitions
Connection policies
👉 Everything becomes manual
⚠️ Reality Check (Important)
Yes, technically:
👉 HCI allows connection creation
👉 BUT it does NOT give you a usable BLE application
🔥 Practical Meaning
✔ With HCI-only you can build:
Connection tester
Controller-level debugger
Custom experimental protocol (L2CAP based)
BLE stack (if you’re brave 😄)
❌ You cannot easily build:
BLE app (like mobile apps)
Sensor service (read temperature, etc.)
Standard BLE profiles
🧠 Key Insight
Think in layers:
Application (Your logic)
↑
GATT ← ❌ missing
↑
ATT ← ❌ missing
↑
L2CAP ← ⚠️ partial access
↑
HCI ← ✅ you are here
↑
Controller (hardware)
🚀 If you REALLY want HCI-only connection
You must implement:
Connection (HCI) ✅
L2CAP channels ⚠️
ATT protocol ❌
GATT database ❌
👉 That’s basically rebuilding Bluetooth stack
👍 Recommendation (based on your learning path)
Since you’re doing low-level work:
👉 Best approach:
Use HCI for:
Advertising
Scanning
Connection events
Then gradually explore:
ATT packets
GATT basics
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <bluetooth/bluetooth.h>
#include <bluetooth/hci.h>
#include <bluetooth/hci_lib.h>
int main(void)
{
int sock;
struct hci_request rq;
/* Open HCI device */
sock = hci_open_dev(1);
if (sock < 0) {
perror(“hci_open_dev”);
return 1;
}
/* ——————————-
* 1. Set Advertising Parameters
* ——————————- */
le_set_advertising_parameters_cp adv_params;
memset(&adv_params, 0, sizeof(adv_params));
adv_params.min_interval = htobs(0x0800); // 1.28 sec
adv_params.max_interval = htobs(0x0800);
adv_params.advtype = 0x00; // ADV_IND (connectable)
adv_params.own_bdaddr_type = 0x00; // Public
adv_params.direct_bdaddr_type = 0x00;
bacpy(&adv_params.direct_bdaddr, BDADDR_ANY);
adv_params.chan_map = 0x07; // Channels 37,38,39
adv_params.filter = 0x00;
memset(&rq, 0, sizeof(rq));
rq.ogf = OGF_LE_CTL;
rq.ocf = OCF_LE_SET_ADVERTISING_PARAMETERS;
rq.cparam = &adv_params;
rq.clen = LE_SET_ADVERTISING_PARAMETERS_CP_SIZE;
if (hci_send_req(sock, &rq, 1000) < 0) {
perror(“LE Set Advertising Parameters”);
close(sock);
return 1;
}
/* ——————————-
* 2. Set Advertising Data
* ——————————- */
le_set_advertising_data_cp adv_data;
memset(&adv_data, 0, sizeof(adv_data));
uint8_t data[] = {
0x02, 0x01, 0x06, // Flags
0x09, 0x09, ‘B’,’L’,’E’,’-‘,’T’,’E’,’S’,’T’
};
adv_data.length = sizeof(data);
memcpy(adv_data.data, data, sizeof(data));
memset(&rq, 0, sizeof(rq));
rq.ogf = OGF_LE_CTL;
rq.ocf = OCF_LE_SET_ADVERTISING_DATA;
rq.cparam = &adv_data;
rq.clen = LE_SET_ADVERTISING_DATA_CP_SIZE;
if (hci_send_req(sock, &rq, 1000) < 0) {
perror(“LE Set Advertising Data”);
close(sock);
return 1;
}
/* ——————————-
* 3. Set Scan Response Data
* ——————————- */
le_set_scan_response_data_cp scan_rsp;
memset(&scan_rsp, 0, sizeof(scan_rsp));
const char *name = “BLE-GATT-Test”;
uint8_t rsp_len = strlen(name);
scan_rsp.data[0] = rsp_len + 1;
scan_rsp.data[1] = 0x09; // Complete Local Name
memcpy(&scan_rsp.data[2], name, rsp_len);
scan_rsp.length = rsp_len + 2;
memset(&rq, 0, sizeof(rq));
rq.ogf = OGF_LE_CTL;
rq.ocf = OCF_LE_SET_SCAN_RESPONSE_DATA;
rq.cparam = &scan_rsp;
rq.clen = LE_SET_SCAN_RESPONSE_DATA_CP_SIZE;
if (hci_send_req(sock, &rq, 1000) < 0) {
perror(“LE Set Scan Response Data”);
close(sock);
return 1;
}
/* ——————————-
* 4. Enable Advertising
* ——————————- */
le_set_advertise_enable_cp enable;
memset(&enable, 0, sizeof(enable));
enable.enable = 0x01;
memset(&rq, 0, sizeof(rq));
rq.ogf = OGF_LE_CTL;
rq.ocf = OCF_LE_SET_ADVERTISE_ENABLE;
rq.cparam = &enable;
rq.clen = LE_SET_ADVERTISE_ENABLE_CP_SIZE;
if (hci_send_req(sock, &rq, 1000) < 0) {
perror(“LE Enable Advertising”);
close(sock);
return 1;
}
printf(“BLE advertising started successfully\n”);
/* Keep advertising */
while (1) {
sleep(1);
}
close(sock);
return 0;
}
