TrouBLE Documentation

repository·main·Indexed 19 days ago

https://github.com/embassy-rs/trouble

A 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.

Tokens
42.4K
Snippets
118
Records
172
Agent score
66%

What's inside TrouBLE

  1. Current functionality of TrouBLE

    main

    The 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).
  2. Use the Linux HCI socket interface with bt-hci-linux

    main
    The bt-hci-linux crate provides a Transport implementation for the bt-hci ecosystem. 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.
  3. What is L2CAP and Connection-Oriented Channels (CoC)?

    main

    L2CAP (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.

  4. What is TrouBLE and how does it work?

    main

    TrouBLE is a Bluetooth Low Energy (BLE) Host implementation written in Rust.

    In the BLE specification, the software is split into two layers:

    1. Controller: The lower layer (hardware/firmware).
    2. 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-hci crate. Any controller that implements the bt-hci traits is compatible with TrouBLE.

  5. Understand Bluetooth Device Addresses (Public vs Random)

    main

    Every 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.
  6. Understand BLE Security: Pairing, Bonding, and Levels

    main

    BLE 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

    1. No Encryption: No protection; default for new connections.
    2. Encrypted: Link is encrypted, but the peer is not authenticated (e.g., via JustWorks).
    3. Encrypted and Authenticated: Link is encrypted and the peer's identity is verified via MITM-protected pairing (e.g., PassKey or Numeric Comparison).
  7. How to define GATT services and characteristics

    main

    Trouble 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], and heapless::Vec<u8, N>.

    Descriptors

    Descriptors are defined as additional attributes on the field using #[descriptor(...)]:

    • uuid (required)
    • read
    • value
    • name
    • type
    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,
    }
  8. Configure HostResources generics

    main

    The HostResources type 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 (requires security feature; 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();
  9. Supported BLE Controllers for TrouBLE

    main

    TrouBLE can interface with any controller that implements the bt-hci traits. 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
  10. Calculate required L2CAP channels

    main

    The L2CAP_CHANNELS_MAX parameter on HostResources must 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.
  11. Understand BLE Central and Peripheral roles

    main

    In 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:

    1. The Peripheral sends advertising packets.
    2. The Central scans and initiates a connection.
    3. Once connected, they may open an L2CAP channel and/or a GATT server/client relationship.