//! Bluetooth events and event deserialization.
//!
//! This module defines all of the HCI events that can be generated by the Bluetooth controller. In
//! addition to all of the event types, the core functionality of the module is the `Event` enum,
//! which converts a byte buffer into an HCI event.
#![macro_use]
/// Verifies that the length of the LHS expression is exactly the RHS expression. Fails with a
/// [`BadLength`](crate::event::Error::BadLength) error if not.
#[macro_export]
macro_rules! require_len {
($left:expr, $right:expr) => {
if $left.len() != $right {
return Err($crate::event::Error::BadLength($left.len(), $right));
}
};
}
/// Verifies that the length of the LHS expression is greater than or equal to the RHS expression.
/// Fails with a [`BadLength`](crate::event::Error::BadLength) error if not.
#[macro_export]
macro_rules! require_len_at_least {
($left:expr, $right:expr) => {
if $left.len() < $right {
return Err($crate::event::Error::BadLength($left.len(), $right));
}
};
}
/// Converts a specific generic enum value between specializations. This is used below to convert
/// from [`Error<NeverError>`] to [`Error<VendorError>`] in various places where only one error
/// value is possible (such as from `try_into`).
macro_rules! self_convert {
($val:path) => {
|e| {
if let $val(value) = e {
return $val(value);
}
unreachable!();
}
};
}
pub mod command;
use crate::types::{ConnectionIntervalError, FixedConnectionInterval};
use crate::{BadStatusError, ConnectionHandle, Status};
use byteorder::{ByteOrder, LittleEndian};
use core::convert::{TryFrom, TryInto};
use core::fmt::{Debug, Formatter, Result as FmtResult};
use core::marker::{PhantomData, Sized};
use core::mem;
/// Potential events that can be generated by the controller.
///
/// See the Bluetooth Spec v4.1, Vol 2, Part E, Section 7.7 for a description of each event. The
/// events are the same for versions 4.1, 4.2, and 5.0 except where noted.
///
/// The spec defines an "LE Meta-Event" event. This event is not exposed directly. Instead,
/// individual LE events are included in this enum.
#[allow(clippy::large_enum_variant)]
#[derive(Clone, Debug)]
pub enum Event<V>
where
V: VendorEvent,
{
/// Vol 2, Part E, Section 7.7.3
ConnectionComplete(ConnectionComplete<V::Status>),
/// Vol 2, Part E, Section 7.7.5
DisconnectionComplete(DisconnectionComplete<V::Status>),
/// Vol 2, Part E, Section 7.7.8
EncryptionChange(EncryptionChange<V::Status>),
/// Vol 2, Part E, Section 7.7.12
ReadRemoteVersionInformationComplete(RemoteVersionInformation<V::Status>),
/// Vol 2, Part E, Section 7.7.14
CommandComplete(command::CommandComplete<V>),
/// Vol 2, Part E, Section 7.7.15
CommandStatus(CommandStatus<V::Status>),
/// Vol 2, Part E, Section 7.7.16
HardwareError(HardwareError),
/// Vol 2, Part E, Section 7.7.19
NumberOfCompletedPackets(NumberOfCompletedPackets),
/// Vol 2, Part E, Section 7.7.26
DataBufferOverflow(DataBufferOverflow),
/// Vol 2, Part E, Section 7.7.39
EncryptionKeyRefreshComplete(EncryptionKeyRefreshComplete<V::Status>),
/// Vol 2, Part E, Section 7.7.65.1
LeConnectionComplete(LeConnectionComplete<V::Status>),
/// Vol 2, Part E, Section 7.7.65.2
LeAdvertisingReport(LeAdvertisingReport),
/// Vol 2, Part E, Section 7.7.65.3
LeConnectionUpdateComplete(LeConnectionUpdateComplete<V::Status>),
/// Vol 2, Part E, Section 7.7.65.4
LeReadRemoteUsedFeaturesComplete(LeReadRemoteUsedFeaturesComplete<V::Status>),
/// Vol 2, Part E, Section 7.7.65.5
LeLongTermKeyRequest(LeLongTermKeyRequest),
/// Vendor-specific events (opcode 0xFF)
Vendor(V),
}
/// Trait for [vendor-specific events](Event::Vendor).
pub trait VendorEvent {
/// Enumeration of vendor-specific errors that may occur when deserializing events. Generally,
/// this means some values in the buffer are out of range for the event.
type Error;
/// Enumeration of vendor-specific status codes.
type Status: TryFrom<u8, Error = BadStatusError> + Clone + Debug;
/// Enumeration of return parameters for vendor-specific commands.
type ReturnParameters: VendorReturnParameters<Error = Self::Error> + Clone + Debug;
/// Creates a new vendor-specific event from the contents of buffer. The buffer contains only
/// the payload of the event, which does not include the BLE event type (which must be 0xFF) or
/// the parameter length (which is provided by `buffer.len()`).
///
/// # Errors
///
/// - Shall return one of the appropriate error types (potentially including vendor-specific
/// errors) if the buffer does not describe a valid event.
fn new(buffer: &[u8]) -> Result<Self, Error<Self::Error>>
where
Self: Sized;
}
/// Trait for return parameters for vendor-specific commands.
pub trait VendorReturnParameters {
/// Enumeration of vendor-specific errors that may occur when deserializing return parameters
/// for vendor-specific commands.
type Error;
/// Deserializes vendor-specific return parameters from the contents of the buffer. The buffer
/// is the full payload of the command complete event, starting with the length (1 byte) and
/// opcode (2 bytes).
fn new(buffer: &[u8]) -> Result<Self, Error<Self::Error>>
where
Self: Sized;
}
/// Errors that may occur when deserializing an event. Must be specialized by the vendor crate to
/// allow for vendor-specific event errors.
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum Error<V> {
/// The event type byte was unknown. The byte is provided.
UnknownEvent(u8),
/// The buffer provided that is supposed to contain an event does not have the correct
/// length. Field 0 is the provided length, field 1 is the expected length.
BadLength(usize, usize),
/// For all events: The status was not recognized (reserved for future use). Includes the
/// unrecognized byte.
BadStatus(u8),
/// For the [Connection Complete](Event::ConnectionComplete) or [Data Buffer
/// Overflow](Event::DataBufferOverflow) events: the link type was not recognized (reserved for
/// future use). Includes the unrecognized byte.
BadLinkType(u8),
/// For the [Connection Complete](Event::ConnectionComplete) event: the encryption enabled value
/// was not recognized (reserved for future use). Includes the unrecognized byte.
BadEncryptionEnabledValue(u8),
/// For the [Disconnection Complete](Event::DisconnectionComplete) event: the disconnection
/// reason was not recognized. Includes the unrecognized byte.
BadReason(u8),
/// For the [Encryption Change](Event::EncryptionChange) event: The encryption type was not
/// recognized. Includes the unrecognized byte.
BadEncryptionType(u8),
/// For the [Command Complete](Event::CommandComplete) event: The event indicated a command
/// completed whose opcode was not recognized. Includes the unrecognized opcode.
UnknownOpcode(crate::opcode::Opcode),
/// For the [Command Complete](Event::CommandComplete) event, for the Read Local Supported
/// Commands command return parameters: The returned command flags are invalid (i.e., they
/// include a flag that is reserved for future use).
BadCommandFlag,
/// For the [Command Complete](Event::CommandComplete) event, for the [LE Read Channel
/// Map](command::ReturnParameters::LeReadChannelMap) command return parameters: The returned
/// channel map includes a reserved bit.
InvalidChannelMap([u8; 5]),
/// For the [Command Complete](Event::CommandComplete) event, for the [LE Read Supported
/// States](command::ReturnParameters::LeReadSupportedStates) command return parameters: The
/// returned supported states bitfield includes a reserved bit.
InvalidLeStates(u64),
/// For the [LE Connection Complete](Event::LeConnectionComplete) event: The connection role was
/// not recognized. Includes the unrecognized byte.
BadLeConnectionRole(u8),
/// For the [LE Connection Complete](Event::LeConnectionComplete) or [LE Advertising
/// Report](Event::LeAdvertisingReport) events: The address type was not recognized. Includes
/// the unrecognized byte.
BadLeAddressType(u8),
/// For the [LE Connection Complete](Event::LeConnectionComplete) event: The returned connection
/// interval was invalid. Includes the error returned when attempting to create the
/// [FixedConnectionInterval].
BadConnectionInterval(ConnectionIntervalError),
/// For the [LE Connection Complete](Event::LeConnectionComplete) event: The central clock
/// accuracy value was not recognized. Includes the unrecognized byte.
BadLeCentralClockAccuracy(u8),
/// For the [LE Advertising Report](Event::LeAdvertisingReport) event: The packet ended with a
/// partial report.
LeAdvertisementReportIncomplete,
/// For the [LE Advertising Report](Event::LeAdvertisingReport) event: The packet includes an
/// invalid advertisement type. Includes the unrecognized byte.
BadLeAdvertisementType(u8),
/// For the [LE Read Remote Used Features Complete](Event::LeReadRemoteUsedFeaturesComplete)
/// event: The response included an invalid bit set for the remote features. Includes the 8
/// bytes of flags.
BadRemoteUsedFeatureFlag(u64),
/// A vendor-specific error was detected when deserializing a vendor-specific event.
Vendor(V),
}
/// Extracts the value from a [`BadStatusError`](BadStatusError) and returns it as a
/// [`BadStatus`](Error::BadStatus) error.
pub fn rewrap_bad_status<VE>(bad_status: BadStatusError) -> Error<VE> {
let BadStatusError::BadValue(v) = bad_status;
Error::BadStatus(v)
}
fn rewrap_bad_reason<VE>(bad_status: BadStatusError) -> Error<VE> {
let BadStatusError::BadValue(v) = bad_status;
Error::BadReason(v)
}
fn rewrap_bd_addr_type_err<VE>(bad_addr_type: crate::BdAddrTypeError) -> Error<VE> {
Error::BadLeAddressType(bad_addr_type.0)
}
/// Defines a newtype to indicate that the buffer is supposed to contain an HCI event.
pub struct Packet<'a>(pub &'a [u8]);
impl<'a> Packet<'a> {
fn full_length(&self) -> usize {
PACKET_HEADER_LENGTH + self.0[PARAM_LEN_BYTE] as usize
}
}
const PACKET_HEADER_LENGTH: usize = 2;
const EVENT_TYPE_BYTE: usize = 0;
const PARAM_LEN_BYTE: usize = 1;
impl<V> Event<V>
where
V: VendorEvent,
{
/// Deserializes an event from the given packet. The packet should contain all of the data
/// needed to deserialize the event.
///
/// # Errors
///
/// - [`UnknownEvent`](Error::UnknownEvent) error if the first byte of the header is not a
/// recognized event type. This includes events that may be valid BLE events, but are not yet
/// be implemented by this crate.
/// - [`BadLength`](Error::BadLength) error if the length of the packet is not sufficient to
/// either (1) contain a packet header, or (2) contain the packet data as defined by the
/// header.
/// - Other errors if the particular event cannot be correctly deserialized from the
/// packet. This includes vendor-specific errors for vendor events.
pub fn new(packet: Packet) -> Result<Event<V>, Error<V::Error>> {
require_len_at_least!(packet.0, PACKET_HEADER_LENGTH);
require_len!(packet.0, packet.full_length());
let event_type = packet.0[EVENT_TYPE_BYTE];
let payload = &packet.0[PACKET_HEADER_LENGTH..packet.full_length()];
match event_type {
0x03 => Ok(Event::ConnectionComplete(to_connection_complete(payload)?)),
0x05 => Ok(Event::DisconnectionComplete(to_disconnection_complete(
payload,
)?)),
0x08 => Ok(Event::EncryptionChange(to_encryption_change(payload)?)),
0x0C => Ok(Event::ReadRemoteVersionInformationComplete(
to_remote_version_info(payload)?,
)),
0x0E => Ok(Event::CommandComplete(command::CommandComplete::new(
payload,
)?)),
0x0F => Ok(Event::CommandStatus(to_command_status(payload)?)),
0x10 => Ok(Event::HardwareError(to_hardware_error(payload)?)),
0x13 => Ok(Event::NumberOfCompletedPackets(
to_number_of_completed_packets(payload)?,
)),
0x1A => Ok(Event::DataBufferOverflow(to_data_buffer_overflow(payload)?)),
0x30 => Ok(Event::EncryptionKeyRefreshComplete(
to_encryption_key_refresh_complete(payload)?,
)),
0x3E => to_le_meta_event(payload),
0xFF => Ok(Event::Vendor(V::new(payload)?)),
_ => Err(Error::UnknownEvent(event_type)),
}
}
}
fn to_le_meta_event<V>(payload: &[u8]) -> Result<Event<V>, Error<V::Error>>
where
V: VendorEvent,
{
require_len_at_least!(payload, 1);
match payload[0] {
0x01 => Ok(Event::LeConnectionComplete(to_le_connection_complete(
payload,
)?)),
0x02 => Ok(Event::LeAdvertisingReport(to_le_advertising_report(
payload,
)?)),
0x03 => Ok(Event::LeConnectionUpdateComplete(
to_le_connection_update_complete(payload)?,
)),
0x04 => Ok(Event::LeReadRemoteUsedFeaturesComplete(
to_le_read_remote_used_features_complete(payload)?,
)),
0x05 => Ok(Event::LeLongTermKeyRequest(to_le_ltk_request(payload)?)),
_ => Err(Error::UnknownEvent(payload[0])),
}
}
/// The [Connection Complete](Event::ConnectionComplete) event indicates to both of the Hosts
/// forming the connection that a new connection has been established.
///
/// This event also indicates to the Host which issued the connection command and then received a
/// [Command Status](Event::CommandStatus) event, if the issued command failed or was successful.
#[derive(Copy, Clone, Debug)]
pub struct ConnectionComplete<VS> {
/// Did the connection attempt fail, and if so, how?
pub status: Status<VS>,
/// Identifies a connection between two BR/ EDR Controllers. This is used as an identifier for
/// transmitting and receiving voice or data.
pub conn_handle: ConnectionHandle,
/// BD ADDR of the other connected device forming the connection.
pub bd_addr: crate::BdAddr,
/// Type of connection.
pub link_type: LinkType,
/// True if the connection is encrypted.
pub encryption_enabled: bool,
}
/// Permissible values for [`ConnectionComplete::link_type`].
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum LinkType {
/// Synchronous, connection-oriented link
Sco,
/// Asynchronous, connection-less link
Acl,
}
/// [TODO](https://doc.rust-lang.org/std/primitive.never.html): Replace NeverError with the
/// language's never type (!).
#[derive(Debug)]
pub enum NeverError {}
impl TryFrom<u8> for LinkType {
type Error = Error<NeverError>;
fn try_from(value: u8) -> Result<LinkType, Self::Error> {
match value {
0 => Ok(LinkType::Sco),
1 => Ok(LinkType::Acl),
_ => Err(Error::BadLinkType(value)),
}
}
}
fn to_connection_complete<VE, VS>(payload: &[u8]) -> Result<ConnectionComplete<VS>, Error<VE>>
where
Status<VS>: TryFrom<u8, Error = BadStatusError>,
{
require_len!(payload, 11);
let mut bd_addr = crate::BdAddr([0; 6]);
bd_addr.0.copy_from_slice(&payload[3..9]);
Ok(ConnectionComplete {
status: payload[0].try_into().map_err(rewrap_bad_status)?,
conn_handle: ConnectionHandle(LittleEndian::read_u16(&payload[1..])),
bd_addr,
link_type: payload[9]
.try_into()
.map_err(self_convert!(Error::BadLinkType))?,
encryption_enabled: try_into_encryption_enabled(payload[10])
.map_err(self_convert!(Error::BadEncryptionEnabledValue))?,
})
}
fn try_into_encryption_enabled(value: u8) -> Result<bool, Error<NeverError>> {
match value {
0 => Ok(false),
1 => Ok(true),
_ => Err(Error::BadEncryptionEnabledValue(value)),
}
}
/// The [Disconnection Complete](Event::DisconnectionComplete) event occurs when a connection is
/// terminated.
///
/// Note: When a physical link fails, one Disconnection Complete event will be returned for each
/// logical channel on the physical link with the corresponding [connection
/// handle](DisconnectionComplete::conn_handle) as a parameter.
///
/// See the Bluetooth v4.1 spec, Vol 2, Part E, Section 7.7.5.
#[derive(Copy, Clone, Debug)]
pub struct DisconnectionComplete<VS> {
/// Indicates if the disconnection was successful or not.
pub status: Status<VS>,
/// Connection handle which was disconnected.
pub conn_handle: ConnectionHandle,
/// Indicates the reason for the disconnection if the disconnection was successful. If the
/// disconnection was not successful, the value of the reason parameter can be ignored by the
/// Host. For example, this can be the case if the Host has issued the
/// [Disconnect](crate::host::Hci::disconnect) command and there was a parameter error, or the
/// command was not presently allowed, or a connection handle that didn't correspond to a
/// connection was given.
pub reason: Status<VS>,
}
fn to_disconnection_complete<VE, VS>(payload: &[u8]) -> Result<DisconnectionComplete<VS>, Error<VE>>
where
Status<VS>: TryFrom<u8, Error = BadStatusError>,
{
require_len!(payload, 4);
Ok(DisconnectionComplete {
status: payload[0].try_into().map_err(rewrap_bad_status)?,
conn_handle: ConnectionHandle(LittleEndian::read_u16(&payload[1..])),
reason: payload[3].try_into().map_err(rewrap_bad_reason)?,
})
}
/// The [Encryption Change](Event::EncryptionChange) event is used to indicate that the change of
/// the encryption mode has been completed.
///
/// This event will occur on both devices to notify the Hosts when Encryption has changed for the
/// specified connection handle between two devices. Note: This event shall not be generated if
/// encryption is paused or resumed; during a role switch, for example.
///
/// See the Bluetooth v4.1 spec, Vol 2, Part E, Section 7.7.8.
#[derive(Copy, Clone, Debug)]
pub struct EncryptionChange<VS> {
/// Indicates if the encryption change was successful or not.
pub status: Status<VS>,
/// Connection handle for which the link layer encryption has been enabled/disabled for all
/// connection handles with the same BR/EDR Controller endpoint as the specified
/// connection handle.
///
/// The connection handle will be a connection handle for an ACL connection.
pub conn_handle: ConnectionHandle,
/// Specifies the new encryption type parameter for
/// [`conn_handle`](EncryptionChange::conn_handle).
pub encryption: Encryption,
}
/// The type of used encryption for the connection.
///
/// The meaning of the encryption type depends on whether the Host has indicated support for Secure
/// Connections in the secure connections host support parameter. When secure connections host
/// support is 'disabled' or the connection handle refers to an LE link, the Controller shall only
/// use values [`Off`](Encryption::Off) and [`On`](Encryption::On). When secure connections host
/// support is 'enabled' and the connection handle refers to a BR/EDR link, the Controller shall set
/// the encryption type [`Off`](Encryption::Off) when encryption is off, to [`On`](Encryption::On)
/// when encryption is on and using E0 and to [`OnAesCcmForBrEdr`](Encryption::OnAesCcmForBrEdr)
/// when encryption is on and using AES-CCM.
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum Encryption {
/// Encryption is disabled.
Off,
/// - On a BR/EDR link, encryption is enabled using E0
/// - On an LE link, encryption is enabled using AES-CCM
On,
/// On a BR/EDR link, encryption is enabled using AES-CCM. Unused for LE links.
OnAesCcmForBrEdr,
}
impl TryFrom<u8> for Encryption {
type Error = Error<NeverError>;
fn try_from(value: u8) -> Result<Encryption, Self::Error> {
match value {
0x00 => Ok(Encryption::Off),
0x01 => Ok(Encryption::On),
0x02 => Ok(Encryption::OnAesCcmForBrEdr),
_ => Err(Error::BadEncryptionType(value)),
}
}
}
fn to_encryption_change<VE, VS>(payload: &[u8]) -> Result<EncryptionChange<VS>, Error<VE>>
where
Status<VS>: TryFrom<u8, Error = BadStatusError>,
{
require_len!(payload, 4);
Ok(EncryptionChange {
status: payload[0].try_into().map_err(rewrap_bad_status)?,
conn_handle: ConnectionHandle(LittleEndian::read_u16(&payload[1..])),
encryption: payload[3]
.try_into()
.map_err(self_convert!(Error::BadEncryptionType))?,
})
}
/// Indicates the completion of the process obtaining the version information of the remote
/// Controller specified by [`conn_handle`](RemoteVersionInformation::conn_handle).
///
/// See [`RemoteVersionInformationComplete`](Event::ReadRemoteVersionInformationComplete).
#[derive(Copy, Clone, Debug)]
pub struct RemoteVersionInformation<VS> {
/// Status of the read event.
pub status: Status<VS>,
/// Connection Handle which was used for the
/// [`read_remote_version_information`](crate::host::Hci::read_remote_version_information)
/// command. The connection handle shall be for an ACL connection.
pub conn_handle: ConnectionHandle,
/// Version of the Current LMP in the remote Controller. See [LMP] version and [Link Layer]
/// version in the Bluetooth Assigned Numbers.
/// - When the connection handle is associated with a BR/EDR ACL-U logical link, the Version
/// event parameter shall be LMP version parameter
/// - When the connection handle is associated with an LE-U logical link, the Version event
/// parameter shall be Link Layer version parameter
///
/// [LMP]: https://www.bluetooth.com/specifications/assigned-numbers/link-manager
/// [Link Layer]: https://www.bluetooth.com/specifications/assigned-numbers/link-layer
pub version: u8,
/// Manufacturer name of the remote Controller. See [CompId] in the Bluetooth Assigned Numbers.
///
/// [CompId]: https://www.bluetooth.com/specifications/assigned-numbers/company-identifiers
pub mfgr_name: u16,
/// Subversion of the [LMP] in the remote Controller. See the Bluetooth Spec, v4.1, Vol 2, Part
/// C, Table 5.2 and Vol 6, Part B, Section 2.4.2.13 (SubVersNr). The sections are the same in
/// v4.2 and v5.0 of the spec.
///
/// This field shall contain a unique value for each implementation or revision of an
/// implementation of the Bluetooth Controller.
///
/// The meaning of the subversion is implementation-defined.
///
/// [LMP]: https://www.bluetooth.com/specifications/assigned-numbers/link-manager
pub subversion: u16,
}
fn to_remote_version_info<VE, VS>(payload: &[u8]) -> Result<RemoteVersionInformation<VS>, Error<VE>>
where
Status<VS>: TryFrom<u8, Error = BadStatusError>,
{
require_len!(payload, 8);
Ok(RemoteVersionInformation {
status: payload[0].try_into().map_err(rewrap_bad_status)?,
conn_handle: ConnectionHandle(LittleEndian::read_u16(&payload[1..])),
version: payload[3],
mfgr_name: LittleEndian::read_u16(&payload[4..]),
subversion: LittleEndian::read_u16(&payload[6..]),
})
}
/// The [Command Status](Event::CommandStatus) event is used to indicate that the command described
/// by the [`opcode`](CommandStatus::opcode) parameter has been received, and that the Controller is
/// currently performing the task for this command.
///
/// Defined in Vol 2, Part E, Section 7.7.15 of the spec.
#[derive(Copy, Clone, Debug)]
pub struct CommandStatus<VS> {
/// Status of the command that has started.
pub status: Status<VS>,
/// Number of HCI Command packets that can be sent to the controller from the host.
pub num_hci_command_packets: u8,
/// Opcode of the command that generated this event. The controller can generate a spontaneous
/// [`Command Status`](Event::CommandStatus) with opcode 0 if the number of allowed HCI commands
/// has changed.
pub opcode: crate::opcode::Opcode,
}
fn to_command_status<VE, VS>(buffer: &[u8]) -> Result<CommandStatus<VS>, Error<VE>>
where
Status<VS>: TryFrom<u8, Error = BadStatusError>,
{
require_len!(buffer, 4);
Ok(CommandStatus {
status: buffer[0].try_into().map_err(rewrap_bad_status)?,
num_hci_command_packets: buffer[1],
opcode: crate::opcode::Opcode(LittleEndian::read_u16(&buffer[2..])),
})
}
/// The [Hardware Error](Event::HardwareError) event is used to notify the Host that a hardware
/// failure has occurred in the Controller.
///
/// Defined in Vol 2, Part E, Section 7.7.16 of the spec.
#[derive(Copy, Clone, Debug)]
pub struct HardwareError {
/// These hardware codes will be implementation-specific, and can be assigned to indicate
/// various hardware problems.
pub code: u8,
}
fn to_hardware_error<VE>(payload: &[u8]) -> Result<HardwareError, Error<VE>> {
require_len!(payload, 1);
Ok(HardwareError { code: payload[0] })
}
/// The [`Number of Completed Packets`](Event::NumberOfCompletedPackets) event is used by the
/// Controller to indicate to the Host how many HCI Data Packets have been completed (transmitted or
/// flushed) for each connection handle since the previous Number Of Completed Packets event was
/// sent to the Host.
///
/// Defined in Vol 2, Part E, Section 7.7.19 of the spec.
#[derive(Copy, Clone)]
pub struct NumberOfCompletedPackets {
/// Number of connection handles whose data is sent in this event.
num_handles: usize,
/// Data buffer for the event.
data_buf: [u8; NUMBER_OF_COMPLETED_PACKETS_MAX_LEN],
}
// The maximum number of bytes in the buffer is the max HCI packet size (255) less the other data in
// the packet.
const NUMBER_OF_COMPLETED_PACKETS_MAX_LEN: usize = 254;
impl Debug for NumberOfCompletedPackets {
fn fmt(&self, f: &mut Formatter) -> FmtResult {
write!(f, "{{")?;
for pair in self.iter() {
write!(f, "{:?}", pair)?;
}
write!(f, "}}")
}
}
impl NumberOfCompletedPackets {
/// Returns an iterator over the connection handle-number of completed packet pairs.
pub fn iter(&self) -> NumberOfCompletedPacketsIterator {
NumberOfCompletedPacketsIterator {
event: self,
next_index: 0,
}
}
}
/// Iterator over the connection handle-number of completed packet pairs from the
/// [`NumberOfCompletedPackets`] event.
pub struct NumberOfCompletedPacketsIterator<'a> {
event: &'a NumberOfCompletedPackets,
next_index: usize,
}
const NUM_COMPLETED_PACKETS_PAIR_LEN: usize = 4;
impl<'a> Iterator for NumberOfCompletedPacketsIterator<'a> {
type Item = NumberOfCompletedPacketsPair;
/// Returns the next connection handle-number of completed packets pair from the event.
fn next(&mut self) -> Option<Self::Item> {
if self.next_index >= self.event.num_handles * NUM_COMPLETED_PACKETS_PAIR_LEN {
return None;
}
let index = self.next_index;
self.next_index += NUM_COMPLETED_PACKETS_PAIR_LEN;
Some(NumberOfCompletedPacketsPair {
conn_handle: ConnectionHandle(LittleEndian::read_u16(&self.event.data_buf[index..])),
num_completed_packets: LittleEndian::read_u16(&self.event.data_buf[index + 2..])
as usize,
})
}
}
/// The [`NumberOfCompletedPackets`] event includes a series of connection handle-number of
/// completed packets pairs.
#[derive(Copy, Clone, Debug)]
pub struct NumberOfCompletedPacketsPair {
/// Connection handle
pub conn_handle: ConnectionHandle,
/// The number of HCI Data Packets that have been completed (transmitted or flushed) for
/// [`conn_handle`](NumberOfCompletedPacketsPair::conn_handle) since the previous time the event
/// was returned.
pub num_completed_packets: usize,
}
fn to_number_of_completed_packets<VE>(
payload: &[u8],
) -> Result<NumberOfCompletedPackets, Error<VE>> {
require_len_at_least!(payload, 1);
let num_pairs = payload[0] as usize;
require_len!(payload, 1 + num_pairs * NUM_COMPLETED_PACKETS_PAIR_LEN);
let mut data_buf = [0; NUMBER_OF_COMPLETED_PACKETS_MAX_LEN];
data_buf[..num_pairs * NUM_COMPLETED_PACKETS_PAIR_LEN].copy_from_slice(&payload[1..]);
Ok(NumberOfCompletedPackets {
num_handles: num_pairs,
data_buf,
})
}
/// Indicates that the Controller's data buffers have been overflowed. This can occur if the Host
/// has sent more packets than allowed.
///
/// Defined in Vol 2, Part E, Section 7.7.26 of the spec.
#[derive(Copy, Clone, Debug)]
pub struct DataBufferOverflow {
/// Indicates whether the overflow was caused by ACL or synchronous data.
pub link_type: LinkType,
}
fn to_data_buffer_overflow<VE>(payload: &[u8]) -> Result<DataBufferOverflow, Error<VE>> {
require_len!(payload, 1);
Ok(DataBufferOverflow {
link_type: payload[0]
.try_into()
.map_err(self_convert!(Error::BadLinkType))?,
})
}
/// Indicates to the Host that the encryption key was refreshed.
///
/// The encryption key is refreshed on the given
/// [`conn_handle`](EncryptionKeyRefreshComplete::conn_handle) any time encryption is paused and
/// then resumed. The BR/EDR Controller shall send this event when the encryption key has been
/// refreshed due to encryption being started or resumed.
///
/// If the [Encryption Key Refresh Complete](Event::EncryptionKeyRefreshComplete) event was
/// generated due to an encryption pause and resume operation embedded within a change connection
/// link key procedure, the Encryption Key Refresh Complete event shall be sent prior to the Change
/// Connection Link Key Complete event.
///
/// If the Encryption Key Refresh Complete event was generated due to an encryption pause and resume
/// operation embedded within a role switch procedure, the Encryption Key Refresh Complete event
/// shall be sent prior to the Role Change event.
///
/// Defined in Vol 2, Part E, Section 7.7.39 of the spec.
#[derive(Copy, Clone, Debug)]
pub struct EncryptionKeyRefreshComplete<VS> {
/// Did the encryption key refresh fail, and if so, how?
pub status: Status<VS>,
/// Connection Handle for the ACL connection to have the encryption key refreshed on.
pub conn_handle: ConnectionHandle,
}
fn to_encryption_key_refresh_complete<VE, VS>(
payload: &[u8],
) -> Result<EncryptionKeyRefreshComplete<VS>, Error<VE>>
where
Status<VS>: TryFrom<u8, Error = BadStatusError>,
{
require_len!(payload, 3);
Ok(EncryptionKeyRefreshComplete {
status: payload[0].try_into().map_err(rewrap_bad_status)?,
conn_handle: ConnectionHandle(LittleEndian::read_u16(&payload[1..])),
})
}
/// Indicates to both of the Hosts forming the connection that a new connection has been
/// created. Upon the creation of the connection a connection handle shall be assigned by the
/// Controller, and passed to the Host in this event. If the connection establishment fails this
/// event shall be provided to the Host that had issued the [LE Create
/// Connection](crate::host::Hci::le_create_connection) command.
///
/// This event indicates to the Host which issued a [LE Create
/// Connection](crate::host::Hci::le_create_connection) command and received a [Command
/// Status](Event::CommandStatus) event if the connection establishment failed or was successful.
///
/// Defined in Vol 2, Part E, Section 7.7.65.1 of the spec.
#[derive(Copy, Clone, Debug)]
pub struct LeConnectionComplete<VS> {
/// Did the LE Connection fail, and if so, how?
pub status: Status<VS>,
/// Connection handle to be used to identify a connection between two Bluetooth devices. The
/// connection handle is used as an identifier for transmitting and receiving data.
pub conn_handle: ConnectionHandle,
/// Role of the device receiving this event in the connection.
pub role: ConnectionRole,
/// Address of the peer device.
pub peer_bd_addr: crate::BdAddrType,
/// Connection interval used on this connection.
pub conn_interval: FixedConnectionInterval,
/// This is only valid for a peripheral. On a central device, this parameter shall be set to
/// Ppm500.
pub central_clock_accuracy: CentralClockAccuracy,
}
/// Connection roles as returned by the [LE Connection Complete](Event::LeConnectionComplete) event.
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum ConnectionRole {
/// The device is the central device for the connection.
///
/// The Bluetooth spec refers to these as "master" devices.
Central,
/// The device is a peripheral device for the connection.
///
/// The Bluetooth spec refers to these as "slave" devices.
Peripheral,
}
impl TryFrom<u8> for ConnectionRole {
type Error = Error<NeverError>;
fn try_from(value: u8) -> Result<ConnectionRole, Self::Error> {
match value {
0 => Ok(ConnectionRole::Central),
1 => Ok(ConnectionRole::Peripheral),
_ => Err(Error::BadLeConnectionRole(value)),
}
}
}
/// Values for the central (master) clock accuracy as returned by the [LE Connection
/// Complete](Event::LeConnectionComplete) event.
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum CentralClockAccuracy {
/// The central clock is accurate to at least 500 parts-per-million. This value is also used
/// when the device is a central device.
Ppm500,
/// The central clock is accurate to at least 250 parts-per-million.
Ppm250,
/// The central clock is accurate to at least 150 parts-per-million.
Ppm150,
/// The central clock is accurate to at least 100 parts-per-million.
Ppm100,
/// The central clock is accurate to at least 75 parts-per-million.
Ppm75,
/// The central clock is accurate to at least 50 parts-per-million.
Ppm50,
/// The central clock is accurate to at least 30 parts-per-million.
Ppm30,
/// The central clock is accurate to at least 20 parts-per-million.
Ppm20,
}
impl TryFrom<u8> for CentralClockAccuracy {
type Error = Error<NeverError>;
fn try_from(value: u8) -> Result<CentralClockAccuracy, Self::Error> {
match value {
0 => Ok(CentralClockAccuracy::Ppm500),
1 => Ok(CentralClockAccuracy::Ppm250),
2 => Ok(CentralClockAccuracy::Ppm150),
3 => Ok(CentralClockAccuracy::Ppm100),
4 => Ok(CentralClockAccuracy::Ppm75),
5 => Ok(CentralClockAccuracy::Ppm50),
6 => Ok(CentralClockAccuracy::Ppm30),
7 => Ok(CentralClockAccuracy::Ppm20),
_ => Err(Error::BadLeCentralClockAccuracy(value)),
}
}
}
fn to_le_connection_complete<VE, VS>(payload: &[u8]) -> Result<LeConnectionComplete<VS>, Error<VE>>
where
Status<VS>: TryFrom<u8, Error = BadStatusError>,
{
require_len!(payload, 19);
let mut bd_addr = crate::BdAddr([0; 6]);
bd_addr.0.copy_from_slice(&payload[6..12]);
Ok(LeConnectionComplete {
status: payload[1].try_into().map_err(rewrap_bad_status)?,
conn_handle: ConnectionHandle(LittleEndian::read_u16(&payload[2..])),
role: payload[4]
.try_into()
.map_err(self_convert!(Error::BadLeConnectionRole))?,
peer_bd_addr: crate::to_bd_addr_type(payload[5], bd_addr)
.map_err(rewrap_bd_addr_type_err)?,
conn_interval: FixedConnectionInterval::from_bytes(&payload[12..18])
.map_err(Error::BadConnectionInterval)?,
central_clock_accuracy: payload[18]
.try_into()
.map_err(self_convert!(Error::BadLeCentralClockAccuracy))?,
})
}
/// The [LE Advertising Report](Event::LeAdvertisingReport) event indicates that a Bluetooth device
/// or multiple Bluetooth devices have responded to an active scan or received some information
/// during a passive scan. The Controller may queue these advertising reports and send information
/// from multiple devices in one event.
///
/// For Bluetooth Version 5.0: This event shall only be generated if scanning was enabled using the
/// [LE Set Scan Enable](crate::host::Hci::le_set_scan_enable) command. It only reports advertising
/// events that used legacy advertising PDUs.
///
/// Defined in Vol 2, Part E, Section 7.7.65.2 of the spec.
#[derive(Copy, Clone)]
pub struct LeAdvertisingReport {
data_len: usize,
data_buf: [u8; MAX_ADVERTISING_REPORT_LEN],
}
const MAX_ADVERTISING_REPORT_LEN: usize = 253;
impl LeAdvertisingReport {
/// Returns an iterator over the advertisements from the event.
pub fn iter(&self) -> LeAdvertisingReportIterator {
LeAdvertisingReportIterator {
inner_iter: self.inner_iter(),
}
}
fn inner_iter<VE>(&self) -> LeAdvertisingReportInnerIterator<'_, VE> {
LeAdvertisingReportInnerIterator {
event_data: &self.data_buf[..self.data_len],
next_index: 0,
phantom: PhantomData,
}
}
}
/// Collection of functions to aid in external tests.
pub mod test_helpers {
use super::*;
/// Create an [`LeAdvertisingReport`] from a slice of [`LeAdvertisement`] structs.
///
/// Panics if the resulting report would be too big to fit in a report event.
pub fn report_with_advertisements<'a>(
advertisements: &[LeAdvertisement<'a>],
) -> LeAdvertisingReport {
let mut data_len = 0;
let mut data_buf = [0; MAX_ADVERTISING_REPORT_LEN];
for advertisement in advertisements {
let event_type_index = data_len;
let addr_index = 1 + event_type_index;
let data_len_index = 7 + addr_index;
let data_start_index = 1 + data_len_index;
let rssi_index = data_start_index + advertisement.data.len();
data_buf[event_type_index] = advertisement.event_type as u8;
advertisement
.address
.copy_into_slice(&mut data_buf[addr_index..data_len_index]);
data_buf[data_len_index] = advertisement.data.len() as u8;
data_buf[data_start_index..rssi_index].copy_from_slice(advertisement.data);
data_buf[rssi_index] =
unsafe { mem::transmute::<i8, u8>(advertisement.rssi.unwrap_or(127)) };
data_len = 1 + rssi_index;
}
LeAdvertisingReport { data_len, data_buf }
}
}
impl Debug for LeAdvertisingReport {
fn fmt(&self, f: &mut Formatter) -> FmtResult {
write!(f, "{{")?;
for report in self.iter() {
write!(f, "{:?}", report)?;
}
write!(f, "}}")
}
}
/// Iterator over the individual LE advertisement responses in the [LE Advertising
/// Report](Event::LeAdvertisingReport) event.
pub struct LeAdvertisingReportIterator<'a> {
inner_iter: LeAdvertisingReportInnerIterator<'a, NeverError>,
}
struct LeAdvertisingReportInnerIterator<'a, VE> {
event_data: &'a [u8],
next_index: usize,
phantom: PhantomData<VE>,
}
impl<'a> Iterator for LeAdvertisingReportIterator<'a> {
type Item = LeAdvertisement<'a>;
/// Returns the next connection handle-number of completed packets pair from the event.
fn next(&mut self) -> Option<Self::Item> {
self.inner_iter.next().unwrap()
}
}
impl<'a, VE> LeAdvertisingReportInnerIterator<'a, VE> {
fn next(&mut self) -> Result<Option<LeAdvertisement<'a>>, Error<VE>> {
if self.next_index >= self.event_data.len() {
return Ok(None);
}
let event_type_index = self.next_index;
let addr_type_index = event_type_index + 1;
let addr_index = addr_type_index + 1;
let data_len_index = addr_index + 6;
let data_len = self.event_data[data_len_index] as usize;
let data_start_index = data_len_index + 1;
let rssi_index = data_start_index + data_len;
self.next_index = rssi_index + 1;
if self.next_index > self.event_data.len() {
return Err(Error::LeAdvertisementReportIncomplete);
}
let mut bd_addr = crate::BdAddr([0; 6]);
bd_addr
.0
.copy_from_slice(&self.event_data[addr_index..data_len_index]);
Ok(Some(LeAdvertisement {
event_type: self.event_data[event_type_index]
.try_into()
.map_err(self_convert!(Error::BadLeAdvertisementType))?,
address: crate::to_bd_addr_type(self.event_data[addr_type_index], bd_addr)
.map_err(rewrap_bd_addr_type_err)?,
data: &self.event_data[data_start_index..rssi_index],
rssi: match unsafe { mem::transmute::<u8, i8>(self.event_data[rssi_index]) } {
127 => None,
value => Some(value),
},
}))
}
}
/// A single advertising report returned by the [LE Advertising Report](Event::LeAdvertisingReport)
/// event.
#[derive(Copy, Clone, Debug)]
pub struct LeAdvertisement<'a> {
/// Advertising respons type
pub event_type: AdvertisementEvent,
/// Address of the advertising device
pub address: crate::BdAddrType,
/// Advertising or scan response data formatted as defined in Vol 3, Part C, Section 11 of the
/// spec.
pub data: &'a [u8],
/// Received signal strength.
///
/// - Range is -128 dBm to 20 dBm.
/// - If the controller sends the value 127, `None` is returned here, since that value indicates
/// "RSSI is not available".
pub rssi: Option<i8>,
}
/// Types of advertisement reports.
///
/// See [`LeAdvertisement`]($crate::event::LeAdvertisement).
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum AdvertisementEvent {
/// Connectable undirected advertising
Advertisement,
/// Connectable directed advertising
DirectAdvertisement,
/// Scannable undirected advertising
Scan,
/// Non connectable undirected advertising
NonConnectableAdvertisement,
/// Scan Response
ScanResponse,
}
impl TryFrom<u8> for AdvertisementEvent {
type Error = Error<NeverError>;
fn try_from(value: u8) -> Result<AdvertisementEvent, Self::Error> {
match value {
0 => Ok(AdvertisementEvent::Advertisement),
1 => Ok(AdvertisementEvent::DirectAdvertisement),
2 => Ok(AdvertisementEvent::Scan),
3 => Ok(AdvertisementEvent::NonConnectableAdvertisement),
4 => Ok(AdvertisementEvent::ScanResponse),
_ => Err(Error::BadLeAdvertisementType(value)),
}
}
}
fn to_le_advertising_report<VE>(payload: &[u8]) -> Result<LeAdvertisingReport, Error<VE>> {
let mut check_iter = LeAdvertisingReportInnerIterator {
event_data: &payload[2..],
next_index: 0,
phantom: PhantomData,
};
while let Some(_) = check_iter.next()? {}
let data_len = payload.len() - 2;
let mut data_buf = [0; MAX_ADVERTISING_REPORT_LEN];
data_buf[..data_len].copy_from_slice(&payload[2..]);
Ok(LeAdvertisingReport { data_len, data_buf })
}
/// Indicates that the Controller process to update the connection has completed.
///
/// On a peripheral, if no connection parameters are updated, then this event shall not
/// be issued.
///
/// On a central device, this event shall be issued if the
/// [`connection_update`](crate::host::Hci::le_connection_update) command was sent.
///
/// Note: This event can be issued autonomously by the central device's Controller if it decides to
/// change the connection interval based on the range of allowable connection intervals for that
/// connection.
///
/// Note: The parameter values returned in this event may be different from the parameter values
/// provided by the Host through the [LE Connection Update](crate::host::Hci::le_connection_update)
/// command or the LE Remote Connection Parameter Request Reply command (Section 7.8.31).
///
/// Defined in Vol 2, Part E, Section 7.7.65.3 of the spec.
#[derive(Copy, Clone, Debug)]
pub struct LeConnectionUpdateComplete<VS> {
/// Did the LE Connection Update fail, and if so, how?
pub status: Status<VS>,
/// Connection handle to be used to identify a connection between two Bluetooth devices. The
/// connection handle is used as an identifier for transmitting and receiving data.
pub conn_handle: ConnectionHandle,
/// Connection interval used on this connection.
pub conn_interval: FixedConnectionInterval,
}
fn to_le_connection_update_complete<VE, VS>(
payload: &[u8],
) -> Result<LeConnectionUpdateComplete<VS>, Error<VE>>
where
Status<VS>: TryFrom<u8, Error = BadStatusError>,
{
require_len!(payload, 10);
Ok(LeConnectionUpdateComplete {
status: payload[1].try_into().map_err(rewrap_bad_status)?,
conn_handle: ConnectionHandle(LittleEndian::read_u16(&payload[2..])),
conn_interval: FixedConnectionInterval::from_bytes(&payload[4..10])
.map_err(Error::BadConnectionInterval)?,
})
}
/// Indicates the completion of the process of the Controller obtaining the features used on the
/// connection and the features supported by the remote Bluetooth device specified by
/// [`conn_handle`](LeReadRemoteUsedFeaturesComplete::conn_handle).
///
/// Note (v5.0): If the features are requested more than once while a connection exists between the
/// two devices, the second and subsequent requests may report a cached copy of the features rather
/// than fetching the feature mask again.
///
/// Defined in Vol 2, Part E, Section 7.7.65.4 of the spec.
#[derive(Copy, Clone, Debug)]
pub struct LeReadRemoteUsedFeaturesComplete<VS> {
/// Did the read fail, and if so, how?
pub status: Status<VS>,
/// Connection handle to be used to identify a connection between two Bluetooth devices.
pub conn_handle: ConnectionHandle,
/// Bit Mask List of used LE features.
pub features: crate::LinkLayerFeature,
}
fn to_le_read_remote_used_features_complete<VE, VS>(
payload: &[u8],
) -> Result<LeReadRemoteUsedFeaturesComplete<VS>, Error<VE>>
where
Status<VS>: TryFrom<u8, Error = BadStatusError>,
{
require_len!(payload, 12);
let feature_flags = LittleEndian::read_u64(&payload[4..]);
Ok(LeReadRemoteUsedFeaturesComplete {
status: payload[1].try_into().map_err(rewrap_bad_status)?,
conn_handle: ConnectionHandle(LittleEndian::read_u16(&payload[2..])),
features: crate::LinkLayerFeature::from_bits(feature_flags)
.ok_or_else(|| Error::BadRemoteUsedFeatureFlag(feature_flags))?,
})
}
/// The [LE Long Term Key Request](Event::LeLongTermKeyRequest) event indicates that the master
/// device is attempting to encrypt or re-encrypt the link and is requesting the Long Term Key from
/// the Host. (See Vol 6, Part B, Section 5.1.3).
///
/// Defined in Vol 2, Part E, Section 7.7.65.5 of the spec.
#[derive(Copy, Clone, Debug)]
pub struct LeLongTermKeyRequest {
/// Connection handle to be used to identify a connection between two Bluetooth devices.
pub conn_handle: ConnectionHandle,
/// 64-bit random number.
pub random_value: u64,
/// 16-bit encrypted diversifier
pub encrypted_diversifier: u16,
}
fn to_le_ltk_request<VE>(payload: &[u8]) -> Result<LeLongTermKeyRequest, Error<VE>> {
require_len!(payload, 13);
Ok(LeLongTermKeyRequest {
conn_handle: ConnectionHandle(LittleEndian::read_u16(&payload[1..])),
random_value: LittleEndian::read_u64(&payload[3..]),
encrypted_diversifier: LittleEndian::read_u16(&payload[11..]),
})
}