pw_bluetooth#

The pw_bluetooth module contains APIs and utilities for the host layer of Bluetooth Low Energy.

Host API#

Attention

This module is still under construction, the API is not yet stable.

The headers in public/pw_bluetooth constitute a Bluetooth Host API. host.h is the entry point from which all other APIs are exposed. Currently, only Low Energy APIs exist.

Host#

class Host#

Host is the entrypoint API for interacting with a Bluetooth host stack. Host is an abstract class that is implemented by a host stack implementation.

Public Types

enum class PairingSecurityLevel : uint8_t#

The security level required for this pairing. This corresponds to the security levels defined in the Security Manager Protocol in Core spec v5.3, Vol 3, Part H, Section 2.3.1

Values:

enumerator kEncrypted#

Encrypted without person-in-the-middle protection (unauthenticated)

enumerator kAuthenticated#

Encrypted with person-in-the-middle protection (authenticated), although this level of security does not fully protect against passive eavesdroppers

enumerator kLeSecureConnections#

Encrypted with person-in-the-middle protection (authenticated). This level of security fully protects against eavesdroppers.

enum class BondableMode : uint8_t#

Whether or not the device should form a bluetooth bond during the pairing prodecure. As described in Core Spec v5.2, Vol 3, Part C, Sec 4.3

Values:

enumerator kBondable#

The device will form a bond during pairing with peers.

enumerator kNonBondable#

The device will not form a bond during pairing with peers.

Public Functions

virtual ~Host() = default#

Close() should complete before Host is destroyed.

virtual void Initialize(Controller *controller, PersistentData data, Function<void(Status)> &&on_initialization_complete) = 0#

Initializes the host stack. Vendor specific controller initialization (e.g. loading firmware) must be done before initializing Host.

Parameters:
  • controller – Pointer to a concrete Controller that the host stack should use to communicate with the controller.

  • data – Data to persist from a previous instance of Host.

  • on_initialization_complete – Called when initialization is complete. Other methods should not be called until initialization completes.

virtual void Close(Closure callback) = 0#

Safely shuts down the host, ending all active Bluetooth procedures:

  • All objects/pointers associated with this host are destroyed/invalidated and all connections disconnected.

  • All scanning and advertising procedures are stopped.

The Host may send events or call callbacks as procedures get terminated.

Parameters:

callback – Will be called once all procedures have terminated.

virtual low_energy::Central *Central() = 0#

Returns a pointer to the Central API, which is used to scan and connect to peers.

virtual low_energy::Peripheral *Peripheral() = 0#

Returns a pointer to the Peripheral API, which is used to advertise and accept connections from peers.

virtual gatt::Server *GattServer() = 0#

Returns a pointer to the GATT Server API, which is used to publish GATT services.

virtual Status ForgetPeer(PeerId peer_id) = 0#

Deletes a peer from the Bluetooth host. If the peer is connected, it will be disconnected. peer_id will no longer refer to any peer.

Returns OK after no peer exists that’s identified by peer_id (even if it didn’t exist), ABORTED if the peer could not be disconnected or deleted and still exists.

virtual void EnablePrivacy(bool enabled) = 0#

Enable or disable the LE privacy feature. When enabled, the host will use a private device address in all LE procedures. When disabled, the public identity address will be used instead (which is the default).

virtual void SetSecurityMode(low_energy::SecurityMode security_mode) = 0#

Set the GAP LE Security Mode of the host. Only encrypted, connection-based security modes are supported, i.e. Mode 1 and Secure Connections Only mode. If the security mode is set to Secure Connections Only, any existing encrypted connections which do not meet the security requirements of Secure Connections Only mode will be disconnected.

virtual void SetPairingDelegate(InputCapability input, OutputCapability output, PairingDelegate *pairing_delegate) = 0#

Assigns the pairing delegate that will respond to authentication challenges using the given I/O capabilities. Calling this method cancels any on-going pairing procedure started using a previous delegate. Pairing requests will be rejected if no PairingDelegate has been assigned.

virtual void Pair(PeerId peer_id, PairingOptions options, Function<void(Status)> &&callback) = 0#

NOTE: This is intended to satisfy test scenarios that require pairing procedures to be initiated without relying on service access. In normal operation, Bluetooth security is enforced during service access.

Initiates pairing to the peer with the supplied peer_id and options. Returns an error if no connected peer with peer_id is found or the pairing procedure fails.

If options specifies a higher security level than the current pairing, this method attempts to raise the security level. Otherwise this method has no effect and returns success.

Returns the following errors via callback: NOT_FOUND - The peer peer_id was not found. ABORTED - The pairing procedure failed.

virtual void SetBondDataCallback(Function<void(low_energy::BondData)> &&callback) = 0#

Configures a callback to be called when new bond data for a peer has been created. This data should be persisted and used to initialize Host in the future. New bond data may be received for an already bonded peer, in which case the new data should overwrite the old data.

virtual std::optional<PeerId> PeerIdFromAddress(Address address) = 0#

Looks up the PeerId corresponding to address. If address does not correspond to a known peer, a new PeerId will be generated for the address. If a PeerId cannot be generated, std::nullopt will be returned.

virtual std::optional<Address> DeviceAddressFromPeerId(PeerId peer_id) = 0#

Looks up the Address corresponding to peer_id. Returns null if peer_id does not correspond to a known peer.

struct PairingOptions#

Parameters that give a caller more fine-grained control over the pairing process.

Public Members

PairingSecurityLevel security_level = PairingSecurityLevel::kAuthenticated#

Determines the Security Manager security level to pair with.

BondableMode bondable_mode = BondableMode::kBondable#

Indicated whether the device should form a bond or not during pairing. If not present, interpreted as bondable mode.

struct PersistentData#

Represents the persistent configuration of a single Host instance. This is used for identity representation in advertisements & bonding secrets recall.

Public Members

std::optional<Key> identity_resolving_key#

The local Identity Resolving Key used by a Host to generate Resolvable Private Addresses when privacy is enabled. May be absent for hosts that do not use LE privacy, or that only use Non-Resolvable Private Addresses.

NOTE: This key is distributed to LE peers during pairing procedures. The client must take care to assign an IRK that consistent with the local Host identity.

span<const low_energy::BondData> bonds#

All bonds that use a public identity address must contain the same local address.

low_energy::Central#

class Central#

Represents the LE central role. Used to scan and connect to peripherals.

Public Types

enum class ConnectError : uint8_t#

Possible errors returned by Connect.

Values:

enumerator kUnknownPeer#

The peer ID is unknown.

enumerator kInvalidOptions#

The ConnectionOptions were invalid.

enumerator kAlreadyExists#

A connection to the peer already exists.

enumerator kCouldNotBeEstablished#

A connection could not be established.

using ConnectResult = Result<ConnectError, Connection::Ptr>#

The Result type returned by Connect() via the passed callback.

Public Functions

virtual void Connect(PeerId peer_id, ConnectionOptions options, Function<void(ConnectResult)> &&callback) = 0#

Connect to the peer with the given identifier.

The requested Connection represents the client’s interest in the LE connection to the peer. Destroying the Connection will disconnect from the peer. Only 1 connection per peer may exist at a time.

The Connection will be closed by the system if the connection to the peer is lost or an error occurs, as indicated by Connection.OnError.

Possible errors are documented in ConnectError.

Parameters:
  • peer_id – Identifier of the peer to initiate a connection to.

  • options – Options used to configure the connection.

  • callback – Called when a connection is successfully established, or an error occurs.

virtual void Scan(
ScanOptions options,
Function<void(ScanResult)> &&scan_result_callback,
Function<void(Result<StartScanError, ScanHandle::Ptr>)> &&scan_started_callback,
) = 0#

Scans for nearby LE peripherals and broadcasters. The lifetime of the scan session is tied to the returned ScanHandle object. Once a scan is started, scan_result_callback will be called with scan results. Only 1 scan may be active at a time. It is OK to destroy the ScanHandle::Ptr object in scan_result_callback to stop scanning (no more results will be returned).

Parameters:
  • options – Options used to configure the scan session.

  • scan_result_callback – If scanning starts successfully,called for LE peers that satisfy the filters indicated in options. The initial calls may report recently discovered peers. Subsequent calls will be made only when peers have been scanned or updated since the last call.

  • scan_started_callback – Called with a ScanHandle object if the scan successfully starts, or a ScanError otherwise.

struct ScanData#

Information obtained from advertising and scan response data broadcast by a peer.

Public Members

std::optional<uint8_t> tx_power#

The radio transmit power level.

Note

This field should NOT be confused with the “connection TX Power

Level” of a peer that is currently connected to the system obtained via the “Transmit Power reporting” feature.

std::optional<Appearance> appearance#

The appearance of the device.

Vector<std::string_view> uris#

String representing a URI to be advertised, as defined in IETF STD 66: https://tools.ietf.org/html/std66. Each entry should be a UTF-8 string including the scheme. For more information, see https://www.iana.org/assignments/uri-schemes/uri-schemes.xhtml for allowed schemes;

Note

Bluetooth advertising compresses schemas over the air to save space. See https://www.bluetooth.com/specifications/assigned-numbers/uri-scheme-name-string-mapping.

chrono::SystemClock::time_point timestamp#

The time when this scan data was received.

struct ScanFilter#

Filter parameters for use during a scan. A discovered peer only matches the filter if it satisfies all of the present filter parameters.

Public Members

std::optional<Uuid> service_uuid#

Filter based on advertised service UUID.

std::optional<Uuid> service_data_uuid#

Filter based on service data containing the given UUID.

std::optional<uint16_t> manufacturer_id#

Filter based on a manufacturer identifier present in the manufacturer data. If this filter parameter is set, then the advertising payload must contain manufacturer specific data with the provided company identifier to satisfy this filter. Manufacturer identifiers can be found at https://www.bluetooth.com/specifications/assigned-numbers/company-identifiers/

std::optional<bool> connectable#

Filter based on whether or not a device is connectable. For example, a client that is only interested in peripherals that it can connect to can set this to true. Similarly a client can scan only for broadcasters by setting this to false.

std::optional<std::string_view> name#

Filter results based on a portion of the advertised device name. Substring matches are allowed. The name length must be at most pw::bluetooth::kMaxDeviceNameLength.

std::optional<uint8_t> max_path_loss#

Filter results based on the path loss of the radio wave. A device that matches this filter must satisfy the following:

  1. Radio transmission power level and received signal strength must be available for the path loss calculation.

  2. The calculated path loss value must be less than, or equal to, max_path_loss.

Note

This field is calculated using the RSSI and TX Power information obtained from advertising and scan response data during a scan procedure. It should NOT be confused with information for an active connection obtained using the “Path Loss Reporting” feature.

class ScanHandle#

Represents an ongoing LE scan.

Public Types

enum class ScanError : uint8_t#

Possible errors that can cause a scan to stop prematurely.

Values:

enumerator kCanceled#
using Ptr = internal::RaiiPtr<ScanHandle, &ScanHandle::StopScan>#

Movable ScanHandle smart pointer. The controller will continue scanning until the ScanHandle::Ptr is destroyed.

Public Functions

virtual void SetErrorCallback(Function<void(ScanError)> &&callback) = 0#

Set a callback that will be called if the scan is stopped due to an error in the BLE stack.

struct ScanOptions#

Parameters used during a scan.

Public Members

Vector<ScanFilter> filters#

List of filters for use during a scan. A peripheral that satisfies any of these filters will be reported. At least 1 filter must be specified. While not recommended, clients that require that all peripherals be reported can specify an empty filter.

uint16_t interval = 0x0010#

The time interval between scans.

  • Time = N * 0.625ms

  • Range: 0x0004 (2.5ms) - 10.24ms (0x4000)

  • Default: 10ms

uint16_t window = 0x0010#

The duration of the scan. The window must be less than or equal to the interval.

  • Time = N * 0.625ms

  • Range: 0x0004 (2.5ms) - 10.24ms (0x4000)

  • Default: 10ms

struct ScanResult#

Public Functions

ScanResult(const ScanResult&) = delete#

ScanResult is non-copyable because strings are only valid in the result callback.

Public Members

PeerId peer_id#

Uniquely identifies this peer on the current system.

bool connectable#

Whether or not this peer is connectable. Non-connectable peers are typically in the LE broadcaster role.

std::optional<uint8_t> rssi#

The last observed signal strength of this peer. This field is only present for a peer that is broadcasting. The RSSI can be stale if the peer has not been advertising.

Note

This field should NOT be confused with the “connection RSSI” of a peer that is currently connected to the system.

ScanData scan_data#

Information from advertising and scan response data broadcast by this peer. This contains the advertising data last received from the peer.

std::optional<std::string_view> name#

The name of this peer. The name is often obtained during a scan procedure and can get updated during the name discovery procedure following a connection.

This field is present if the name is known.

chrono::SystemClock::time_point last_updated#

Timestamp of when the information in this ScanResult was last updated.

low_energy::Peripheral#

class Peripheral#

Represents the LE Peripheral role, which advertises and is connected to.

Public Types

enum class AdvertiseError#

Errors returned by Advertise.

Values:

enumerator kNotSupported#

The operation or parameters requested are not supported on the current hardware.

enumerator kAdvertisingDataTooLong#

The provided advertising data exceeds the maximum allowed length when encoded.

enumerator kScanResponseDataTooLong#

The provided scan response data exceeds the maximum allowed length when encoded.

enumerator kInvalidParameters#

The requested parameters are invalid.

enumerator kNotEnoughAdvertisingSlots#

This may be called if the maximum number of simultaneous advertisements has already been reached.

enumerator kFailed#

Advertising could not be initiated due to a hardware or system error.

using AdvertiseCallback = Function<void(Result<AdvertiseError, AdvertisedPeripheral::Ptr>)>#

Callback for Advertise() method.

Public Functions

virtual void Advertise(const AdvertisingParameters &parameters, AdvertiseCallback &&result_callback) = 0#

Start advertising continuously as a LE peripheral. If advertising cannot be initiated then result_callback will be called with an error. Once started, advertising can be stopped by destroying the returned AdvertisedPeripheral::Ptr.

If the system supports multiple advertising, this may be called as many times as there are advertising slots. To reconfigure an advertisement, first close the original advertisement and then initiate a new advertisement.

Parameters:
  • parameters – Parameters used while configuring the advertising instance.

  • result_callback – Called once advertising has started or failed. On success, called with an AdvertisedPeripheral that models the lifetime of the advertisement. Destroying it will stop advertising.

struct AdvertisingIntervalRange#

The range of the time interval between advertisements. Shorter intervals result in faster discovery at the cost of higher power consumption. The exact interval used is determined by the Bluetooth controller.

  • Time = N * 0.625ms.

  • Time range: 0x0020 (20ms) - 0x4000 (10.24s)

Public Members

uint16_t min = 0x0800#

Default: 1.28s.

uint16_t max = 0x0800#

Default: 1.28s.

struct AdvertisingParameters#

Represents the parameters for configuring advertisements.

Public Members

AdvertisingData data#

The fields that will be encoded in the data section of advertising packets.

std::optional<AdvertisingData> scan_response#

The fields that are to be sent in a scan response packet. Clients may use this to send additional data that does not fit inside an advertising packet on platforms that do not support the advertising data length extensions.

If present advertisements will be configured to be scannable.

AdvertisingIntervalRange interval_range#

See AdvertisingIntervalRange documentation.

std::optional<ConnectionOptions> connection_options#

If present, the controller will broadcast connectable advertisements which allow peers to initiate connections to the Peripheral. The fields of ConnectionOptions will configure any connections set up from advertising.

low_energy::AdvertisedPeripheral#

class AdvertisedPeripheral#

AdvertisedPeripheral instances are valid for the duration of advertising.

Public Types

using Ptr = internal::RaiiPtr<AdvertisedPeripheral, &AdvertisedPeripheral::StopAdvertising>#

Movable AdvertisedPeripheral smart pointer. The peripheral will continue advertising until the returned AdvertisedPeripheral::Ptr is destroyed.

Public Functions

virtual void SetErrorCallback(Closure callback) = 0#

Set a callback that will be called when an error occurs and advertising has been stopped (invalidating this object). It is OK to destroy the AdvertisedPeripheral::Ptr object from within callback.

virtual void SetConnectionCallback(Function<void(Connection::Ptr)> &&callback) = 0#

For connectable advertisements, this callback will be called when an LE central connects to the advertisement. It is recommended to set this callback immediately after advertising starts to avoid dropping connections.

The returned Connection can be used to interact with the peer. It also represents a peripheral’s ownership over the connection: the client can drop the object to request a disconnection. Similarly, the Connection error handler is called by the system to indicate that the connection to the peer has been lost. While connections are exclusive among peripherals, they may be shared with centrals.

If advertising is not stopped, this callback may be called with multiple connections over the lifetime of an advertisement. It is OK to destroy the AdvertisedPeripheral::Ptr object from within callback in order to stop advertising.

low_energy::Connection#

class Connection#

Class that represents a connection to a peer. This can be used to interact with GATT services and establish LE L2CAP channels.

This lifetime of this object is tied to that of the LE connection it represents. Destroying the object results in a disconnection.

Public Types

enum class ConnectionParameterUpdateError : uint8_t#

Possible errors when updating the connection parameters.

Values:

enumerator kFailure#
enumerator kInvalidParameters#
enumerator kRejected#
enum class DisconnectReason : uint8_t#

Possible reasons a connection was disconnected.

Values:

enumerator kFailure#
enumerator kRemoteUserTerminatedConnection#
enumerator kConnectionTimeout#

This usually indicates that the link supervision timeout expired.

using Ptr = internal::RaiiPtr<Connection, &Connection::Disconnect>#

Movable Connection smart pointer. When Connection::Ptr is destroyed the Connection will disconnect automatically.

Public Functions

virtual ~Connection() = default#

If a disconnection has not occurred, destroying this object will result in disconnection.

virtual void SetDisconnectCallback(Function<void(DisconnectReason)> &&callback) = 0#

Sets a callback that will be called when the peer disconnects or there is a connection error that causes a disconnection. This should be configured by the client immediately after establishing the connection. callback will not be called for disconnections initiated by the client (e.g. by destroying Connection). It is OK to destroy this object from within callback.

virtual gatt::Client *GattClient() = 0#

Returns a GATT client to the connected peer that is valid for the lifetime of this connection. The client is valid for the lifetime of this connection.

virtual uint16_t AttMtu() = 0#

Returns the current ATT Maximum Transmission Unit. By subtracting ATT headers from the MTU, the maximum payload size of messages can be calculated.

virtual void SetAttMtuChangeCallback(Function<void(uint16_t)> callback) = 0#

Sets a callback that will be called with the new ATT MTU whenever it is updated.

virtual ConnectionParameters Parameters() = 0#

Returns the current connection parameters.

virtual void RequestConnectionParameterUpdate(
RequestedConnectionParameters parameters,
Function<void(Result<ConnectionParameterUpdateError>)> &&callback,
) = 0#

Requests an update to the connection parameters. callback will be called with the result of the request.

low_energy::ConnectionOptions#

struct ConnectionOptions#

Represents parameters that are set on a per-connection basis.

Public Members

bool bondable_mode = true#

When true, the connection operates in bondable mode. This means pairing will form a bond, or persist across disconnections, if the peer is also in bondable mode. When false, the connection operates in non-bondable mode, which means the local device only allows pairing that does not form a bond.

std::optional<Uuid> service_filter#

When present, service discovery performed following the connection is restricted to primary services that match this field. Otherwise, by default all available services are discovered.

std::optional<RequestedConnectionParameters> parameters#

When present, specifies the initial connection parameters. Otherwise, the connection parameters will be selected by the implementation.

low_energy::RequestedConnectionParameters#

struct RequestedConnectionParameters#

Connection parameters that either the local device or a peer device are requesting.

Public Members

uint16_t min_interval#

Minimum value for the connection interval. This shall be less than or equal to max_interval. The connection interval indicates the frequency of link layer connection events over which data channel PDUs can be transmitted. See Core Spec v5.3, Vol 6, Part B, Section 4.5.1 for more information on the link layer connection events.

  • Range: 0x0006 to 0x0C80

  • Time: N * 1.25 ms

  • Time Range: 7.5 ms to 4 s.

uint16_t max_interval#

Maximum value for the connection interval. This shall be greater than or equal to min_interval. The connection interval indicates the frequency of link layer connection events over which data channel PDUs can be transmitted. See Core Spec v5.3, Vol 6, Part B, Section 4.5.1 for more information on the link layer connection events.

  • Range: 0x0006 to 0x0C80

  • Time: N * 1.25 ms

  • Time Range: 7.5 ms to 4 s.

uint16_t max_latency#

Maximum peripheral latency for the connection in number of connection events. See Core Spec v5.3, Vol 6, Part B, Section 4.5.2.

  • Range: 0x0000 to 0x01F3

uint16_t supervision_timeout#

This defines the maximum time between two received data packet PDUs before the connection is considered lost. See Core Spec v5.3, Vol 6, Part B, Section 4.5.2.

  • Range: 0x000A to 0x0C80

  • Time: N * 10 ms

  • Time Range: 100 ms to 32 s

low_energy::ConnectionParameters#

struct ConnectionParameters#

Actual connection parameters returned by the controller.

Public Members

uint16_t interval#

The connection interval indicates the frequency of link layer connection events over which data channel PDUs can be transmitted. See Core Spec v5.3, Vol 6, Part B, Section 4.5.1 for more information on the link layer connection events.

  • Range: 0x0006 to 0x0C80

  • Time: N * 1.25 ms

  • Time Range: 7.5 ms to 4 s.

uint16_t latency#

The maximum allowed peripheral connection latency in number of connection events. See Core Spec v5.3, Vol 6, Part B, Section 4.5.2.

  • Range: 0x0000 to 0x01F3

uint16_t supervision_timeout#

This defines the maximum time between two received data packet PDUs before the connection is considered lost. See Core Spec v5.3, Vol 6, Part B, Section 4.5.2.

  • Range: 0x000A to 0x0C80

  • Time: N * 10 ms

  • Time Range: 100 ms to 32 s

gatt::Server#

class Server#

Interface for a GATT server that serves many GATT services.

Public Types

using PublishServiceResult = Result<PublishServiceError, LocalService::Ptr>#

The Result passed by PublishService.

Public Functions

virtual void PublishService(
const LocalServiceInfo &info,
LocalServiceDelegate *delegate,
Function<void(PublishServiceResult)> &&result_callback,
) = 0#

Publishes the service defined by info and implemented by delegate so that it is available to all remote peers.

The caller must assign distinct handles to the characteristics and descriptors listed in info. These identifiers will be used in requests sent to delegate. On success, a LocalService::Ptr is returned. When the LocalService::Ptr is destroyed or an error occurs (LocalServiceDelegate.OnError), the service will be unpublished.

gatt::LocalServiceInfo#

struct LocalServiceInfo#

Parameters for registering a local GATT service.

Public Members

Handle handle#

A unique (within a Server) handle identifying this service.

bool primary#

Indicates whether this is a primary or secondary service.

Uuid type#

The UUID that identifies the type of this service. There may be multiple services with the same UUID.

span<const Characteristic> characteristics#

The characteristics of this service.

span<const Handle> includes#

Handles of other services that are included by this service.

gatt::LocalService#

class LocalService#

Interface provided by the backend to interact with a published service. LocalService is valid for the lifetime of a published GATT service. It is used to control the service and send notifications/indications.

Public Types

using ValueChangedResult = Result<Error>#

The Result type for a ValueChanged indication or notification message. The error can be locally generated for notifications and either locally or remotely generated for indications.

using ValueChangedCallback = Function<void(ValueChangedResult)>#

The callback type for a ValueChanged indication or notification completion.

using Ptr = internal::RaiiPtr<LocalService, &LocalService::UnpublishService>#

Movable LocalService smart pointer. When the LocalService::Ptr object is destroyed the service will be unpublished.

Public Functions

virtual void NotifyValue(const ValueChangedParameters &parameters, ValueChangedCallback &&completion_callback) = 0#

Sends a notification to peers. Notifications should be used instead of indications when the service does not require peer confirmation of the update.

Notifications should not be sent to peers which have not enabled notifications on a particular characteristic or that have disconnected since - if they are sent, they will not be propagated and the completion_callback will be called with an error condition. The Bluetooth stack will track this configuration for the lifetime of the service.

The maximum size of the parameters.value field depends on the MTU negotiated with the peer. A 3-byte header plus the value contents must fit in a packet of MTU bytes.

Parameters:
  • parameters – The parameters associated with the changed characteristic.

  • completion_callback – Called when the notification has been sent to all peers or an error is produced when trying to send the notification to any of the peers. This function is called only once when all associated work is done, if the implementation wishes to receive a call on a per-peer basis, they should send this event with a single PeerId in parameters.peer_ids. Additional values should not be notified until this callback is called.

virtual void IndicateValue(const ValueChangedParameters &parameters, ValueChangedCallback &&confirmation) = 0#

Sends an indication to peers. Indications should be used instead of notifications when the service does require peer confirmation of the update.

Indications should not be sent to peers which have not enabled indications on a particular characteristic - if they are sent, they will not be propagated. The Bluetooth stack will track this configuration for the lifetime of the service.

If any of the peers in parameters.peer_ids fails to confirm the indication within the ATT transaction timeout (30 seconds per Bluetooth 5.2 Vol. 4 Part G 3.3.3), the link between the peer and the local adapter will be closed.

The maximum size of the parameters.value field depends on the MTU negotiated with the peer. A 3-byte header plus the value contents must fit in a packet of MTU bytes.

Parameters:
  • parameters – The parameters associated with the changed characteristic.

  • confirmation – When all the peers listed in parameters.peer_ids have confirmed the indication, confirmation is called. If the implementation wishes to receive indication confirmations on a per-peer basis, they should send this event with a single PeerId in parameters.peer_ids. Additional values should not be indicated until this callback is called.

struct ValueChangedParameters#

The parameters used to signal a characteristic value change from a LocalService to a peer.

Public Members

span<const PeerId> peer_ids#

The PeerIds of the peers to signal. The LocalService should respect the Characteristic Configuration associated with a peer+handle when deciding whether to signal it. If empty, all peers are signalled.

Handle handle#

The handle of the characteristic value being signaled.

span<const std::byte> value#

The new value for the descriptor/characteristic.

gatt::LocalServiceDelegate#

class LocalServiceDelegate#

Interface for serving a local GATT service. This is implemented by the API client.

Public Functions

virtual void OnError(Error error) = 0#

Called when there is a fatal error related to this service that forces the service to close. LocalServiceDelegate methods will no longer be called. This invalidates the associated LocalService. It is OK to destroy both LocalServiceDelegate and the associated LocalService::Ptr from within this method.

virtual void CharacteristicConfiguration(PeerId peer_id, Handle handle, bool notify, bool indicate) = 0#

This notifies the current configuration of a particular characteristic/descriptor for a particular peer. It will be called when the peer GATT client changes the configuration.

The Bluetooth stack maintains the state of each peer’s configuration across reconnections. As such, this method will be called with both notify and indicate set to false for each characteristic when a peer disconnects. Also, when a peer reconnects this method will be called again with the initial, persisted state of the newly-connected peer’s configuration. However, clients should not rely on this state being persisted indefinitely by the Bluetooth stack.

Parameters:
  • peer_id – The PeerId of the GATT client associated with this particular CCC.

  • handle – The handle of the characteristic associated with the notify and indicate parameters.

  • notify – True if the client has enabled notifications, false otherwise.

  • indicate – True if the client has enabled indications, false otherwise.

virtual void ReadValue(
PeerId peer_id,
Handle handle,
uint32_t offset,
Function<void(Result<Error, span<const std::byte>>)> &&result_callback,
) = 0#

Called when a peer requests to read the value of a characteristic or descriptor. It is guaranteed that the peer satisfies the permissions associated with this attribute.

Parameters:
  • peer_id – The PeerId of the GATT client making the read request.

  • handle – The handle of the requested descriptor/characteristic.

  • offset – The offset at which to start reading the requested value.

  • result_callback – Called with the value of the characteristic on success, or an Error on failure. The value will be truncated to fit in the MTU if necessary. It is OK to call result_callback in ReadValue.

virtual void WriteValue(
PeerId peer_id,
Handle handle,
uint32_t offset,
span<const std::byte> value,
Function<void(Result<Error>)> &&status_callback,
) = 0#

Called when a peer issues a request to write the value of a characteristic or descriptor. It is guaranteed that the peer satisfies the permissions associated with this attribute.

Parameters:
  • peer_id – The PeerId of the GATT client making the write request.

  • handle – The handle of the requested descriptor/characteristic.

  • offset – The offset at which to start writing the requested value. If the offset is 0, any existing value should be overwritten by the new value. Otherwise, the existing value between offset:(offset + len(value)) should be changed to value.

  • value – The new value for the descriptor/characteristic.

  • status_callback – Called with the result of the write.

virtual void MtuUpdate(PeerId peer_id, uint16_t mtu) = 0#

Called when the MTU of a peer is updated. Also called for peers that are already connected when the server is published.

Notifications and indications must fit in a single packet including both the 3-byte notification/indication header and the user-provided payload. If these are not used, the MTU can be safely ignored as it is intended for use cases where the throughput needs to be optimized.

gatt::Client#

class Client#

Represents a GATT client that interacts with services on a GATT server.

Public Functions

virtual void WatchServices(
Vector<Uuid> uuid_allowlist,
Function<void(RemoteServiceInfo)> &&updated_callback,
Function<void(Handle)> &&removed_callback,
) = 0#

Enumerates existing services found on the peer that this Client represents, and provides a stream of updates thereafter. Results can be filtered by specifying a list of UUIDs in uuids. To further interact with services, clients must obtain a RemoteService protocol by calling ConnectToService(). uuid_allowlist - The allowlist of UUIDs to filter services with. updated_callback - Will be called with services that are updated/modified. removed_callback - Called with the handles of services that have been removed. Note that handles may be reused.

virtual void StopWatchingServices()#

Stops service watching if started by WatchServices.

virtual Result<Error, RemoteService::Ptr> ConnectToService(Handle handle) = 0#

Connects to a RemoteService. Only 1 connection per service is allowed. handle - the handle of the service to connect to.

This may fail with the following errors: kInvalidParameters - handle does not correspond to a known service.

struct RemoteServiceInfo#

Represents a remote GATT service.

Public Members

Handle handle#

Uniquely identifies this GATT service.

bool primary#

Indicates whether this is a primary or secondary service.

Uuid type#

The UUID that identifies the type of this service. There may be multiple services with the same UUID.

gatt::RemoteService#

class RemoteService#

Represents a GATT service on a remote GATT server. Clients should call SetErrorCallback before using in order to handle fatal errors.

Public Types

enum class WriteMode : uint8_t#

Represents the supported write modes for writing characteristics & descriptors to the server.

Values:

enumerator kDefault#

Wait for a response from the server before returning but do not verify the echo response. Supported for both characteristics and descriptors.

enumerator kReliable#

Every value blob is verified against an echo response from the server. The procedure is aborted if a value blob has not been reliably delivered to the peer. Only supported for characteristics.

enumerator kWithoutResponse#

Delivery will not be confirmed before returning. Writing without a response is only supported for short characteristics with the WRITE_WITHOUT_RESPONSE property. The value must fit into a single message. It is guaranteed that at least 20 bytes will fit into a single message. If the value does not fit, a kFailure error will be produced. The value will be written at offset 0. Only supported for characteristics.

using Ptr = internal::RaiiPtr<RemoteService, &RemoteService::Disconnect>#

Movable RemoteService smart pointer. The remote server will remain connected until the returned RemoteService::Ptr is destroyed.

Public Functions

void SetErrorCallback(Function<void(RemoteServiceError)> &&error_callback)#

Set a callback that will be called when there is an error with this RemoteService, after which this RemoteService will be invalid.

void DiscoverCharacteristics(Function<void(Characteristic)> &&characteristic_callback)#

Calls characteristic_callback with the characteristics and descriptors in this service.

void ReadByType(Uuid uuid, ReadByTypeCallback &&result_callback)#

Reads characteristics and descriptors with the specified type. This method is useful for reading values before discovery has completed, thereby reducing latency.

This may fail with the following errors:

  • kInvalidParameters: if uuid refers to an internally reserved descriptor type (e.g. the Client Characteristic Configuration descriptor).

  • kTooManyResults: More results were read than can fit in a Vector. Consider reading characteristics/descriptors individually after performing discovery.

  • kFailure: The server returned an error not specific to a single result.

Parameters:
  • uuid – The UUID of the characteristics/descriptors to read.

  • result_callback – Results are returned via this callback. Results may be empty if no matching values are read. If reading a value results in a permission error, the handle and error will be included.

void ReadCharacteristic(Handle handle, std::optional<LongReadOptions> options, ReadCallback &&result_callback)#

Reads the value of a characteristic.

Parameters:
  • handle – The handle of the characteristic to be read.

  • options – If null, a short read will be performed, which may be truncated to what fits in a single message (at least 22 bytes). If long read options are present, performs a long read with the indicated options.

  • result_callback – called with the result of the read and the value of the characteristic if successful.

Return values:
  • kInvalidHandlehandle is invalid.

  • kInvalidParametersoptions is invalid.

  • kReadNotPermitted – The server rejected the request.

  • kInsufficient* – The server rejected the request.

  • kFailure – The server returned an error not covered by the above.

void WriteCharacteristic(
Handle handle,
span<const std::byte> value,
WriteOptions options,
Function<void(Result<Error>)> &&result_callback,
)#

Writes value to the characteristic with handle using the provided options. It is not recommended to send additional writes while a write is already in progress (the server may receive simultaneous writes in any order).

Parameters:
  • handle – Handle of the characteristic to be written to

  • value – The value to be written.

  • options – Options that apply to the write.

  • result_callback – Returns a result upon completion of the write.

Return values:
  • kInvalidHandlehandle is invalid.

  • kInvalidParameters`options – is invalid.

  • kWriteNotPermitted – The server rejected the request.

  • kInsufficient* – The server rejected the request.

  • kFailure – The server returned an error not covered by the above errors.

void ReadDescriptor(Handle handle, std::optional<LongReadOptions> options, ReadCallback &&result_callback)#

Reads the value of the characteristic descriptor with handle and returns it in the reply.

Parameters:
  • handle – The descriptor handle to read.

  • options – Options that apply to the read.

  • result_callback – Returns a result containing the value of the descriptor on success.

Return values:
  • kInvalidHandlehandle is invalid.

  • kInvalidParameters`options` – is invalid.

  • kReadNotPermitted

  • kInsufficient* – The server rejected the request.

  • kFailure – The server returned an error not covered by the above errors.

void WriteDescriptor(
Handle handle,
span<const std::byte> value,
WriteOptions options,
Function<void(Result<Error>)> &&result_callback,
)#

Writes value to the descriptor with handle using the provided options. It is not recommended to send additional writes while a write is already in progress (the server may receive simultaneous writes in any order).

Parameters:
  • handle – Handle of the descriptor to be written to

  • value – The value to be written.

  • options – Options that apply to the write.

  • result_callback – Returns a result upon completion of the write.

Return values:
  • kInvalidHandlehandle is invalid.

  • kInvalidParameters – `options is invalid

  • kWriteNotPermitted – The server rejected the request.

  • kInsufficient* – The server rejected the request.

  • kFailure – The server returned an error not covered by the above errors.

void RegisterNotificationCallback(
Handle handle,
NotificationCallback &&notification_callback,
Function<void(Result<Error>)> &&result_callback,
)#

Subscribe to notifications & indications from the characteristic with the given handle.

Either notifications or indications will be enabled depending on characteristic properties. Indications will be preferred if they are supported. This operation fails if the characteristic does not have the “notify” or “indicate” property.

A write request will be issued to configure the characteristic for notifications/indications if it contains a Client Characteristic Configuration descriptor. This method fails if an error occurs while writing to the descriptor.

On success, notification_callback will be called when the peer sends a notification or indication. Indications are automatically confirmed.

Subscriptions can be canceled with StopNotifications.

Parameters:
  • handle – the handle of the characteristic to subscribe to.

  • notification_callback – will be called with the values of notifications/indications when received.

  • result_callback – called with the result of enabling notifications/indications.

Return values:
  • kFailure – The characteristic does not support notifications or indications.

  • kInvalidHandlehandle is invalid.

  • kWriteNotPermitted – CCC descriptor write error.

  • Insufficient* – CCC descriptor write error.

void StopNotifications(Handle handle)#

Stops notifications for the characteristic with the given handle.

struct LongReadOptions#

Represents the supported options to read a long characteristic or descriptor value from a server. Long values are those that may not fit in a single message (longer than 22 bytes).

Public Members

uint16_t offset = 0#

The byte to start the read at. Must be less than the length of the value.

uint16_t max_bytes = kMaxValueLength#

The maximum number of bytes to read.

struct ReadByTypeResult#

A result returned by ReadByType.

Public Members

Handle handle#

Characteristic or descriptor handle.

Result<Error, ReadValue> result#

The value of the characteristic or descriptor, if it was read successfully, or an error explaining why the value could not be read.

struct ReadValue#

Wrapper around a possible truncated value received from the server.

Public Members

Handle handle#

Characteristic or descriptor handle.

Vector<std::byte, 20> value#

The value of the characteristic or descriptor.

bool maybe_truncated#

True if value might be truncated (the buffer was completely filled by the server and the read was a short read). ReadCharacteristic or ReadDescriptor should be used to read the complete value.

struct WriteOptions#

Represents the supported options to write a characteristic/descriptor value to a server.

Public Members

WriteMode mode = WriteMode::kDefault#

The mode of the write operation. For descriptors, only WriteMode::kDefault is supported

uint16_t offset = 0#

Request a write starting at the byte indicated. Must be 0 if mode is WriteMode.kWithoutResponse.

Callbacks#

This module contains callback-heavy APIs. Callbacks must not call back into the pw_bluetooth APIs unless otherwise noted. This includes calls made by destroying objects returned by the API. Additionally, callbacks must not block.

Emboss Packet Definitions#

pw_bluetooth contains Emboss packet definitions. So far, some packets and enums from the following protocols are defined:

  • HCI

  • L2CAP

  • H4

Usage#

  1. Add Emboss to your project as described in Emboss.

  1. Add the Emboss target you require to your build target’s dependency list - for example, @pigweed//pw_bluetooth:emboss_hci_group for HCI packets.

  1. Add the Emboss target you require to your build target’s dependency list - for example, $dir_pw_bluetooth/emboss_hci_group for HCI packets.

  1. Add the Emboss target you require to your build target’s dependency list - for example, pw_bluetooth.emboss_hci_group for HCI packets.

  1. Include the generated header files you require in your source files.

#include "pw_bluetooth/hci_commands.emb.h"
#include "pw_bluetooth/hci_vendor.emb.h"
  1. Construct an Emboss view over a buffer as described in the Emboss User Guide.

  std::array<uint8_t, 4> buffer = {0x00, 0x01, 0x02, 0x03};
  auto view = emboss::MakeTestCommandPacketView(&buffer);
  EXPECT_TRUE(view.IsComplete());
  EXPECT_EQ(view.payload().Read(), 0x03);

Note

When you first add generated headers, clangd may complain that the generated header files do not exist. You need to build your project to resolve this. Similarly, you need to rebuild in order for .emb file updates to be reflected in the generated headers.

Contributing#

Emboss .emb files can be edited to add additional packets and enums.

Emboss files should be formatted by running the following from the Pigweed root.

(export EMBOSS_PATH="/ssd2/dev2/pigweed/environment/packages/emboss" &&
    export PYTHONPATH+=":${EMBOSS_PATH}" &&
    python3 "${EMBOSS_PATH}/compiler/front_end/format.py" pw_bluetooth/public/pw_bluetooth/*.emb)

If adding files, be sure to update the GN, Bazel, and CMake build rules. Presubmit runs the emboss_test.cc test on all three.

Size Report#

Delta of +972 when constructing the first packet view and reading/writing a field. This includes the runtime library and the 4-byte buffer.

Label

Segment

Delta

Emboss not configured.

(ALL)

0

Delta of +96 when adding a second packet view and reading/writing a field.

Label

Segment

Delta

Emboss not configured.

(ALL)

0

Roadmap#

  • Bluetooth Proxy (WIP in in pw_bluetooth_proxy)

  • Add automated Emboss file formatting to pw format (b/331195584)

  • Create a backend for the Bluetooth API using Fuchsia’s Bluetooth stack (Sapphire).

  • Stabilize the Bluetooth API.

  • Add BR/EDR APIs.