TrouBLE Documentation
repository·main·Indexed 19 days ago
https://github.com/embassy-rs/troubleA Rust-based Bluetooth Low Energy (BLE) Host implementation for embedded devices. Designed to be hardware-agnostic via bt-hci traits, it supports various controllers including Linux HCI sockets (via bt-hci-linux), USB adapters (via bt-hci-usb), and specific hardware targets such as ESP32, nRF52, and nRF54.
What's inside TrouBLE
- TrouBLE Tester is a Bluetooth Test Protocol (BTP) implementation designed for automated conformance testing of the TrouBLE Bluetooth host. It enables testing via the Bluetooth SIG's Profile Tuning Suite (PTS) by utilizing auto-pts.
Current functionality of TrouBLE
mainThe current implementation supports the following BLE features:
- Peripheral role: Advertising as a peripheral and accepting connections.
- Central role: Scanning for devices and establishing connections.
- GATT Server: Basic support for write, read, and notifications.
- GATT Client: Basic support for service/characteristic lookup and read/write.
- L2CAP CoC: Connection-oriented Channels with credit management (supported for both central and peripheral roles).
Use the Linux HCI socket interface with bt-hci-linux
mainThebt-hci-linuxcrate provides aTransportimplementation for thebt-hciecosystem. It allows you to communicate with Bluetooth hardware via the Linux HCI socket interface (BlueZ). This is useful for running Bluetooth protocol tests or applications on Linux systems that have access to Bluetooth controllers via standard HCI sockets.What is L2CAP and Connection-Oriented Channels (CoC)?
mainL2CAP (Logical Link Control and Adaptation Protocol) is the data transport layer for BLE. GATT and other protocols run on top of it.
While GATT uses fixed channels, BLE also supports Connection-Oriented Channels (CoC) for transferring arbitrary data with credit-based flow control.
Use CoC when:
- GATT's attribute-based model is too restrictive.
- You need to perform bulk data transfers.
- You are implementing a custom protocol.
Each CoC is identified by a SPSM (Simplified Protocol/Service Multiplexer) value, similar to a port number.
What is TrouBLE and how does it work?
mainTrouBLE is a Bluetooth Low Energy (BLE) Host implementation written in Rust.
In the BLE specification, the software is split into two layers:
- Controller: The lower layer (hardware/firmware).
- Host: The upper layer (software logic).
These layers communicate via the Host Controller Interface (HCI) protocol. Because TrouBLE implements the Host side, it can be reused across different hardware controllers as long as they communicate via a standardized HCI transport (such as UART, USB, or in-memory IPC).
TrouBLE relies on the
bt-hcicrate. Any controller that implements thebt-hcitraits is compatible with TrouBLE.Understand Bluetooth Device Addresses (Public vs Random)
mainEvery BLE device is identified by a 48-bit Bluetooth Device Address. These are categorized into two types:
Public Address
Globally unique and assigned by the IEEE. These remain constant and are used for stable identification.
Random Address
Used to enhance privacy by preventing device tracking. They are subdivided into:
- Static Random Address: Remains fixed until the device restarts or resets.
- Private Random Address: Changes periodically.
- Resolvable: Can be linked back to the original device using an Identity Resolving Key (IRK).
- Non-Resolvable: Completely anonymous.
Understand BLE Security: Pairing, Bonding, and Levels
mainBLE security manages data encryption and device authentication.
Pairing vs. Bonding
- Pairing: The process of establishing encryption keys between two devices.
- LE Secure Connections (LESC): Uses ECDH key exchange (Recommended).
- Legacy Pairing: Simpler key exchange (Required for BLE 4.0/4.1 compatibility).
- The method (JustWorks, Numeric Comparison, PassKey Entry) depends on the IO capabilities of both devices.
- Bonding: The process of storing keys from a pairing session so they can be reused in future connections. This includes the Long Term Key (LTK) and optionally an Identity Resolving Key (IRK) for resolving private addresses.
Security Levels
- No Encryption: No protection; default for new connections.
- Encrypted: Link is encrypted, but the peer is not authenticated (e.g., via JustWorks).
- Encrypted and Authenticated: Link is encrypted and the peer's identity is verified via MITM-protected pairing (e.g., PassKey or Numeric Comparison).
- Pairing: The process of establishing encryption keys between two devices.
How to define GATT services and characteristics
mainTrouble uses procedural macros to define GATT structures. A service is a struct annotated with
#[gatt_service], and each field within that struct represents a characteristic.Service Attributes
uuid(required): The Service UUID. Supports 16-bit short strings ("180f"), 128-bit strings, or predefined constants.
Characteristic Attributes
uuid(required): The Characteristic UUID.read: Allows clients to read the value.write: Allows clients to write a value (with response).write_without_response: Allows clients to write without waiting for a response.notify: Enables server-initiated notifications (no confirmation).indicate: Enables server-initiated indications (requires client confirmation).value = <expr>: Sets the initial value. Supports literals, byte arrays, and const expressions.permissions(encrypted): Requires an encrypted connection.permissions(authenticated): Requires an authenticated (MITM-protected) connection.
Supported Types
u8,u16,u32,u64,f32,f64,bool,[u8; N], andheapless::Vec<u8, N>.Descriptors
Descriptors are defined as additional attributes on the field using
#[descriptor(...)]:uuid(required)readvaluenametype
use trouble_host::prelude::*; #[gatt_service(uuid = "180f")] struct BatteryService { #[characteristic(uuid = "2a19", read, notify, value = 10)] level: u8, #[descriptor(uuid = descriptors::VALID_RANGE, read, value = [0, 100])] #[descriptor(uuid = descriptors::MEASUREMENT_DESCRIPTION, name = "hello", read, value = "Battery Level", type = &'static str)] #[characteristic(uuid = characteristic::BATTERY_LEVEL, read, notify, value = 10)] level: u8, }Configure HostResources generics
mainThe
HostResourcestype manages the memory for packets, connections, and channels. You must specify the following generic parameters when instantiating it:PacketPool: The allocator used for payloads (size should match your attribute size or L2CAP MTU).CONNS: Maximum number of BLE connections.CHANNELS: Maximum number of L2CAP channels (excluding GATT).ADV_SETS: Maximum number of advertising sets (default of 1 is usually sufficient).BONDS: Maximum number of stored bond records (requiressecurityfeature; default is 10).
// Example: 4 connections, 2 L2CAP channels, 1 advertising set, 10 bonds let mut resources: HostResources<DefaultPacketPool, 4, 2, 1, 10> = HostResources::new();Supported BLE Controllers for TrouBLE
mainTrouBLE can interface with any controller that implements the
bt-hcitraits. Currently supported controllers include:- nRF Softdevice Controller
- UART HCI (e.g., Zephyr HCI UART)
- Raspberry Pi Pico W
- Apache NimBLE Controller
- ESP32
- STM32WB
- Linux HCI Sockets
Calculate required L2CAP channels
mainThe
L2CAP_CHANNELS_MAXparameter onHostResourcesmust account for all internal and user-defined channels. The total count is calculated as follows:- 1 for the signaling channel (always required).
- 1 for ATT/GATT (if using GATT).
- 1 per concurrent L2CAP CoC channel you intend to use.
Examples:
- GATT-only application: Set to
2(signaling + ATT). - GATT + one CoC channel: Set to
3.
Understand BLE Central and Peripheral roles
mainIn BLE communication, devices operate in one of two primary roles:
- Central: A device that scans for and initiates connections to other devices. Typically a more powerful device like a PC or smartphone, though embedded devices can also act as centrals.
- Peripheral: A device that advertises its presence and waits for connections. Peripherals often use GATT (Generic Attribute Profile) to expose services and characteristics, or support L2CAP connection-oriented channels.
Communication Flow:
- The Peripheral sends advertising packets.
- The Central scans and initiates a connection.
- Once connected, they may open an L2CAP channel and/or a GATT server/client relationship.