Skip to main content

trouble_host/
lib.rs

1#![no_std]
2#![allow(dead_code)]
3#![allow(unused_variables)]
4#![allow(clippy::needless_lifetimes)]
5#![doc = include_str!(concat!("../", env!("CARGO_PKG_README")))]
6#![warn(missing_docs)]
7
8use core::mem::MaybeUninit;
9
10use advertise::AdvertisementDataError;
11use bt_hci::cmd::status::ReadRssi;
12use bt_hci::cmd::{AsyncCmd, SyncCmd};
13use bt_hci::param::{AddrKind, BdAddr};
14use bt_hci::FromHciBytesError;
15use embassy_time::Duration;
16#[cfg(feature = "security")]
17use heapless::Vec;
18use rand_core::{CryptoRng, RngCore};
19
20use crate::att::AttErrorCode;
21use crate::channel_manager::ChannelStorage;
22use crate::connection::Connection;
23use crate::connection_manager::ConnectionStorage;
24#[cfg(feature = "security")]
25pub use crate::security_manager::{BondInformation, IdentityResolvingKey, LongTermKey};
26pub use crate::types::capabilities::IoCapabilities;
27
28/// Number of bonding information stored
29pub(crate) const BI_COUNT: usize = 10; // Should be configurable
30
31mod fmt;
32
33#[cfg(not(any(feature = "central", feature = "peripheral")))]
34compile_error!("Must enable at least one of the `central` or `peripheral` features");
35
36pub mod att;
37#[cfg(feature = "central")]
38pub mod central;
39mod channel_manager;
40mod codec;
41mod command;
42pub mod config;
43mod connection_manager;
44mod cursor;
45#[cfg(feature = "default-packet-pool")]
46mod packet_pool;
47mod pdu;
48#[cfg(feature = "peripheral")]
49pub mod peripheral;
50#[cfg(feature = "security")]
51mod security_manager;
52pub mod types;
53
54#[cfg(feature = "central")]
55use central::*;
56#[cfg(feature = "peripheral")]
57use peripheral::*;
58
59pub mod advertise;
60pub mod connection;
61#[cfg(feature = "gatt")]
62pub mod gap;
63pub mod l2cap;
64#[cfg(feature = "scan")]
65pub mod scan;
66
67#[cfg(test)]
68pub(crate) mod mock_controller;
69
70pub(crate) mod host;
71use host::{AdvHandleState, BleHost, HostMetrics, Runner};
72
73pub mod prelude {
74    //! Convenience include of most commonly used types.
75    pub use bt_hci::controller::ExternalController;
76    pub use bt_hci::param::{AddrKind, BdAddr, LeConnRole as Role, PhyKind, PhyMask};
77    pub use bt_hci::transport::SerialTransport;
78    pub use bt_hci::uuid::*;
79    #[cfg(feature = "derive")]
80    pub use heapless::String as HeaplessString;
81    #[cfg(feature = "derive")]
82    pub use trouble_host_macros::*;
83
84    pub use super::att::AttErrorCode;
85    pub use super::{BleHostError, Controller, Error, Host, HostResources, Packet, PacketPool, Stack};
86    #[cfg(feature = "peripheral")]
87    pub use crate::advertise::*;
88    #[cfg(feature = "gatt")]
89    pub use crate::attribute::*;
90    #[cfg(feature = "gatt")]
91    pub use crate::attribute_server::*;
92    #[cfg(feature = "central")]
93    pub use crate::central::*;
94    pub use crate::connection::*;
95    #[cfg(feature = "gatt")]
96    pub use crate::gap::*;
97    #[cfg(feature = "gatt")]
98    pub use crate::gatt::*;
99    pub use crate::host::{ControlRunner, EventHandler, HostMetrics, Runner, RxRunner, TxRunner};
100    pub use crate::l2cap::*;
101    #[cfg(feature = "default-packet-pool")]
102    pub use crate::packet_pool::DefaultPacketPool;
103    pub use crate::pdu::Sdu;
104    #[cfg(feature = "peripheral")]
105    pub use crate::peripheral::*;
106    #[cfg(feature = "scan")]
107    pub use crate::scan::*;
108    #[cfg(feature = "security")]
109    pub use crate::security_manager::{BondInformation, IdentityResolvingKey, LongTermKey};
110    pub use crate::types::capabilities::IoCapabilities;
111    #[cfg(feature = "gatt")]
112    pub use crate::types::gatt_traits::{AsGatt, FixedGattValue, FromGatt};
113    pub use crate::{Address, Identity};
114}
115
116#[cfg(feature = "gatt")]
117pub mod attribute;
118#[cfg(feature = "gatt")]
119mod attribute_server;
120#[cfg(feature = "gatt")]
121pub mod gatt;
122
123/// A BLE address.
124/// Every BLE device is identified by a unique *Bluetooth Device Address*, which is a 48-bit identifier similar to a MAC address. BLE addresses are categorized into two main types: *Public* and *Random*.
125///
126/// A Public Address is globally unique and assigned by the IEEE. It remains constant and is typically used by devices requiring a stable identifier.
127///
128/// A Random Address can be *static* or *dynamic*:
129///
130/// - *Static Random Address*: Remains fixed until the device restarts or resets.
131/// - *Private Random Address*: Changes periodically for privacy purposes. It can be *Resolvable* (can be linked to the original device using an Identity Resolving Key) or *Non-Resolvable* (completely anonymous).
132///
133/// Random addresses enhance privacy by preventing device tracking.
134#[derive(Debug, Clone, Copy, PartialEq)]
135pub struct Address {
136    /// Address type.
137    pub kind: AddrKind,
138    /// Address value.
139    pub addr: BdAddr,
140}
141
142impl Address {
143    /// Create a new random address.
144    pub fn random(val: [u8; 6]) -> Self {
145        Self {
146            kind: AddrKind::RANDOM,
147            addr: BdAddr::new(val),
148        }
149    }
150
151    /// To bytes
152    pub fn to_bytes(&self) -> [u8; 7] {
153        let mut bytes = [0; 7];
154        bytes[0] = self.kind.into_inner();
155        let mut addr_bytes = self.addr.into_inner();
156        addr_bytes.reverse();
157        bytes[1..].copy_from_slice(&addr_bytes);
158        bytes
159    }
160}
161
162impl core::fmt::Display for Address {
163    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
164        let a = self.addr.into_inner();
165        write!(
166            f,
167            "{:02X}:{:02X}:{:02X}:{:02X}:{:02X}:{:02X}",
168            a[5], a[4], a[3], a[2], a[1], a[0]
169        )
170    }
171}
172
173#[cfg(feature = "defmt")]
174impl defmt::Format for Address {
175    fn format(&self, fmt: defmt::Formatter) {
176        let a = self.addr.into_inner();
177        defmt::write!(
178            fmt,
179            "{:02X}:{:02X}:{:02X}:{:02X}:{:02X}:{:02X}",
180            a[5],
181            a[4],
182            a[3],
183            a[2],
184            a[1],
185            a[0]
186        )
187    }
188}
189
190/// Identity of a peer device
191///
192/// Sometimes we have to save both the address and the IRK.
193/// Because sometimes the peer uses the static or public address even though the IRK is sent.
194/// In this case, the IRK exists but the used address is not RPA.
195/// Should `Address` be used instead?
196#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
197pub struct Identity {
198    /// Random static or public address
199    pub bd_addr: BdAddr,
200
201    /// Identity Resolving Key
202    #[cfg(feature = "security")]
203    pub irk: Option<IdentityResolvingKey>,
204}
205
206#[cfg(feature = "defmt")]
207impl defmt::Format for Identity {
208    fn format(&self, fmt: defmt::Formatter) {
209        defmt::write!(fmt, "BdAddr({:X}) ", self.bd_addr);
210        #[cfg(feature = "security")]
211        defmt::write!(fmt, "Irk({:X})", self.irk);
212    }
213}
214
215impl Identity {
216    /// Check whether the address matches the identity
217    pub fn match_address(&self, address: &BdAddr) -> bool {
218        if self.bd_addr == *address {
219            return true;
220        }
221        #[cfg(feature = "security")]
222        if let Some(irk) = self.irk {
223            return irk.resolve_address(address);
224        }
225        false
226    }
227
228    /// Check whether the given identity matches current identity
229    pub fn match_identity(&self, identity: &Identity) -> bool {
230        if self.match_address(&identity.bd_addr) {
231            return true;
232        }
233        #[cfg(feature = "security")]
234        if let Some(irk) = identity.irk {
235            if let Some(current_irk) = self.irk {
236                return irk == current_irk;
237            } else {
238                return irk.resolve_address(&self.bd_addr);
239            }
240        }
241        false
242    }
243}
244
245/// Errors returned by the host.
246#[derive(Debug)]
247#[cfg_attr(feature = "defmt", derive(defmt::Format))]
248pub enum BleHostError<E> {
249    /// Error from the controller.
250    Controller(E),
251    /// Error from the host.
252    BleHost(Error),
253}
254
255/// How many bytes of invalid data to capture in the error variants before truncating.
256pub const MAX_INVALID_DATA_LEN: usize = 16;
257
258/// Errors related to Host.
259#[derive(Debug, Clone, PartialEq)]
260#[cfg_attr(feature = "defmt", derive(defmt::Format))]
261pub enum Error {
262    /// Error encoding parameters for HCI commands.
263    Hci(bt_hci::param::Error),
264    /// Error decoding responses from HCI commands.
265    HciDecode(FromHciBytesError),
266    /// Error from the Attribute Protocol.
267    Att(AttErrorCode),
268    #[cfg(feature = "security")]
269    /// Error from the security manager
270    Security(crate::security_manager::Reason),
271    /// Insufficient space in the buffer.
272    InsufficientSpace,
273    /// Invalid value.
274    InvalidValue,
275
276    /// Unexpected data length.
277    ///
278    /// This happens if the attribute data length doesn't match the input length size,
279    /// and the attribute is deemed as *not* having variable length due to the characteristic's
280    /// `MAX_SIZE` and `MIN_SIZE` being defined as equal.
281    UnexpectedDataLength {
282        /// Expected length.
283        expected: usize,
284        /// Actual length.
285        actual: usize,
286    },
287
288    /// Error converting from GATT value.
289    CannotConstructGattValue([u8; MAX_INVALID_DATA_LEN]),
290
291    /// Scan config filter accept list is empty.
292    ConfigFilterAcceptListIsEmpty,
293
294    /// Unexpected GATT response.
295    UnexpectedGattResponse,
296
297    /// Received characteristic declaration data shorter than the minimum required length (5 bytes).
298    MalformedCharacteristicDeclaration {
299        /// Expected length.
300        expected: usize,
301        /// Actual length.
302        actual: usize,
303    },
304
305    /// Failed to decode the data structure within a characteristic declaration attribute value.
306    InvalidCharacteristicDeclarationData,
307
308    /// Failed to finalize the packet.
309    FailedToFinalize {
310        /// Expected length.
311        expected: usize,
312        /// Actual length.
313        actual: usize,
314    },
315
316    /// Codec error.
317    CodecError(codec::Error),
318
319    /// Extended advertising not supported.
320    ExtendedAdvertisingNotSupported,
321
322    /// Invalid UUID length.
323    InvalidUuidLength(usize),
324
325    /// Error decoding advertisement data.
326    Advertisement(AdvertisementDataError),
327    /// Invalid l2cap channel id provided.
328    InvalidChannelId,
329    /// No l2cap channel available.
330    NoChannelAvailable,
331    /// Resource not found.
332    NotFound,
333    /// Invalid state.
334    InvalidState,
335    /// Out of memory.
336    OutOfMemory,
337    /// Unsupported operation.
338    NotSupported,
339    /// L2cap channel closed.
340    ChannelClosed,
341    /// Operation timed out.
342    Timeout,
343    /// Controller is busy.
344    Busy,
345    /// No send permits available.
346    NoPermits,
347    /// Connection is disconnected.
348    Disconnected,
349    /// Connection limit has been reached.
350    ConnectionLimitReached,
351    /// GATT subscriber limit has been reached.
352    ///
353    /// The limit can be modified using the `gatt-client-notification-max-subscribers-N` features.
354    GattSubscriberLimitReached,
355    /// Other error.
356    Other,
357}
358
359impl<E> From<Error> for BleHostError<E> {
360    fn from(value: Error) -> Self {
361        Self::BleHost(value)
362    }
363}
364
365impl From<FromHciBytesError> for Error {
366    fn from(error: FromHciBytesError) -> Self {
367        Self::HciDecode(error)
368    }
369}
370
371impl From<AttErrorCode> for Error {
372    fn from(error: AttErrorCode) -> Self {
373        Self::Att(error)
374    }
375}
376
377impl<E> From<bt_hci::cmd::Error<E>> for BleHostError<E> {
378    fn from(error: bt_hci::cmd::Error<E>) -> Self {
379        match error {
380            bt_hci::cmd::Error::Hci(p) => Self::BleHost(Error::Hci(p)),
381            bt_hci::cmd::Error::Io(p) => Self::Controller(p),
382        }
383    }
384}
385
386impl<E> From<bt_hci::param::Error> for BleHostError<E> {
387    fn from(error: bt_hci::param::Error) -> Self {
388        Self::BleHost(Error::Hci(error))
389    }
390}
391
392impl From<codec::Error> for Error {
393    fn from(error: codec::Error) -> Self {
394        match error {
395            codec::Error::InsufficientSpace => Error::InsufficientSpace,
396            codec::Error::InvalidValue => Error::CodecError(error),
397        }
398    }
399}
400
401impl<E> From<codec::Error> for BleHostError<E> {
402    fn from(error: codec::Error) -> Self {
403        match error {
404            codec::Error::InsufficientSpace => BleHostError::BleHost(Error::InsufficientSpace),
405            codec::Error::InvalidValue => BleHostError::BleHost(Error::InvalidValue),
406        }
407    }
408}
409
410use bt_hci::cmd::controller_baseband::*;
411use bt_hci::cmd::info::*;
412use bt_hci::cmd::le::*;
413use bt_hci::cmd::link_control::*;
414use bt_hci::controller::{ControllerCmdAsync, ControllerCmdSync};
415
416/// Trait that defines the controller implementation required by the host.
417///
418/// The controller must implement the required commands and events to be able to be used with Trouble.
419pub trait Controller:
420    bt_hci::controller::Controller
421    + embedded_io::ErrorType
422    + ControllerCmdSync<LeReadBufferSize>
423    + ControllerCmdSync<Disconnect>
424    + ControllerCmdSync<SetEventMask>
425    + ControllerCmdSync<SetEventMaskPage2>
426    + ControllerCmdSync<LeSetEventMask>
427    + ControllerCmdSync<LeSetRandomAddr>
428    + ControllerCmdSync<HostBufferSize>
429    + ControllerCmdAsync<LeConnUpdate>
430    + ControllerCmdSync<LeReadFilterAcceptListSize>
431    + ControllerCmdSync<SetControllerToHostFlowControl>
432    + ControllerCmdSync<Reset>
433    + ControllerCmdSync<ReadRssi>
434    + ControllerCmdSync<LeCreateConnCancel>
435    + ControllerCmdSync<LeSetScanEnable>
436    + ControllerCmdSync<LeSetExtScanEnable>
437    + ControllerCmdAsync<LeCreateConn>
438    + ControllerCmdSync<LeClearFilterAcceptList>
439    + ControllerCmdSync<LeAddDeviceToFilterAcceptList>
440    + for<'t> ControllerCmdSync<LeSetAdvEnable>
441    + for<'t> ControllerCmdSync<LeSetExtAdvEnable<'t>>
442    + for<'t> ControllerCmdSync<HostNumberOfCompletedPackets<'t>>
443    + ControllerCmdSync<LeReadBufferSize>
444    + for<'t> ControllerCmdSync<LeSetAdvData>
445    + ControllerCmdSync<LeSetAdvParams>
446    + for<'t> ControllerCmdSync<LeSetAdvEnable>
447    + for<'t> ControllerCmdSync<LeSetScanResponseData>
448    + ControllerCmdSync<LeLongTermKeyRequestReply>
449    + ControllerCmdAsync<LeEnableEncryption>
450    + ControllerCmdSync<ReadBdAddr>
451{
452}
453
454impl<
455        C: bt_hci::controller::Controller
456            + embedded_io::ErrorType
457            + ControllerCmdSync<LeReadBufferSize>
458            + ControllerCmdSync<Disconnect>
459            + ControllerCmdSync<SetEventMask>
460            + ControllerCmdSync<SetEventMaskPage2>
461            + ControllerCmdSync<LeSetEventMask>
462            + ControllerCmdSync<LeSetRandomAddr>
463            + ControllerCmdSync<HostBufferSize>
464            + ControllerCmdAsync<LeConnUpdate>
465            + ControllerCmdSync<LeReadFilterAcceptListSize>
466            + ControllerCmdSync<LeClearFilterAcceptList>
467            + ControllerCmdSync<LeAddDeviceToFilterAcceptList>
468            + ControllerCmdSync<SetControllerToHostFlowControl>
469            + ControllerCmdSync<Reset>
470            + ControllerCmdSync<ReadRssi>
471            + ControllerCmdSync<LeSetScanEnable>
472            + ControllerCmdSync<LeSetExtScanEnable>
473            + ControllerCmdSync<LeCreateConnCancel>
474            + ControllerCmdAsync<LeCreateConn>
475            + for<'t> ControllerCmdSync<LeSetAdvEnable>
476            + for<'t> ControllerCmdSync<LeSetExtAdvEnable<'t>>
477            + for<'t> ControllerCmdSync<HostNumberOfCompletedPackets<'t>>
478            + ControllerCmdSync<LeReadBufferSize>
479            + for<'t> ControllerCmdSync<LeSetAdvData>
480            + ControllerCmdSync<LeSetAdvParams>
481            + for<'t> ControllerCmdSync<LeSetAdvEnable>
482            + for<'t> ControllerCmdSync<LeSetScanResponseData>
483            + ControllerCmdSync<LeLongTermKeyRequestReply>
484            + ControllerCmdAsync<LeEnableEncryption>
485            + ControllerCmdSync<ReadBdAddr>,
486    > Controller for C
487{
488}
489
490/// A Packet is a byte buffer for packet data.
491/// Similar to a `Vec<u8>` it has a length and a capacity.
492pub trait Packet: Sized + AsRef<[u8]> + AsMut<[u8]> {}
493
494/// A Packet Pool that can allocate packets of the desired size.
495///
496/// The MTU is usually related to the MTU of l2cap payloads.
497pub trait PacketPool: 'static {
498    /// Packet type provided by this pool.
499    type Packet: Packet;
500
501    /// The maximum size a packet can have.
502    const MTU: usize;
503
504    /// Allocate a new buffer with space for `MTU` bytes.
505    /// Return `None` when the allocation can't be fulfilled.
506    ///
507    /// This function is called by the L2CAP driver when it needs
508    /// space to receive a packet into.
509    /// It will later call `from_raw_parts` with the buffer and the
510    /// amount of bytes it has received.
511    fn allocate() -> Option<Self::Packet>;
512
513    /// Capacity of this pool in the number of packets.
514    fn capacity() -> usize;
515}
516
517/// HostResources holds the resources used by the host.
518///
519/// The l2cap packet pool is used by the host to handle inbound data, by allocating space for
520/// incoming packets and dispatching to the appropriate connection and channel.
521pub struct HostResources<P: PacketPool, const CONNS: usize, const CHANNELS: usize, const ADV_SETS: usize = 1> {
522    connections: MaybeUninit<[ConnectionStorage<P::Packet>; CONNS]>,
523    channels: MaybeUninit<[ChannelStorage<P::Packet>; CHANNELS]>,
524    advertise_handles: MaybeUninit<[AdvHandleState; ADV_SETS]>,
525}
526
527impl<P: PacketPool, const CONNS: usize, const CHANNELS: usize, const ADV_SETS: usize> Default
528    for HostResources<P, CONNS, CHANNELS, ADV_SETS>
529{
530    fn default() -> Self {
531        Self::new()
532    }
533}
534
535impl<P: PacketPool, const CONNS: usize, const CHANNELS: usize, const ADV_SETS: usize>
536    HostResources<P, CONNS, CHANNELS, ADV_SETS>
537{
538    /// Create a new instance of host resources.
539    pub const fn new() -> Self {
540        Self {
541            connections: MaybeUninit::uninit(),
542            channels: MaybeUninit::uninit(),
543            advertise_handles: MaybeUninit::uninit(),
544        }
545    }
546}
547
548/// Create a new instance of the BLE host using the provided controller implementation and
549/// the resource configuration
550pub fn new<
551    'resources,
552    C: Controller,
553    P: PacketPool,
554    const CONNS: usize,
555    const CHANNELS: usize,
556    const ADV_SETS: usize,
557>(
558    controller: C,
559    resources: &'resources mut HostResources<P, CONNS, CHANNELS, ADV_SETS>,
560) -> Stack<'resources, C, P> {
561    unsafe fn transmute_slice<T>(x: &mut [T]) -> &'static mut [T] {
562        unsafe { core::mem::transmute(x) }
563    }
564
565    // Safety:
566    // - HostResources has the exceeding lifetime as the returned Stack.
567    // - Internal lifetimes are elided (made 'static) to simplify API usage
568    // - This _should_ be OK, because there are no references held to the resources
569    //   when the stack is shut down.
570
571    let connections: &mut [ConnectionStorage<P::Packet>] =
572        &mut *resources.connections.write([const { ConnectionStorage::new() }; CONNS]);
573    let connections: &'resources mut [ConnectionStorage<P::Packet>] = unsafe { transmute_slice(connections) };
574
575    let channels = &mut *resources.channels.write([const { ChannelStorage::new() }; CHANNELS]);
576    let channels: &'static mut [ChannelStorage<P::Packet>] = unsafe { transmute_slice(channels) };
577
578    let advertise_handles = &mut *resources.advertise_handles.write([AdvHandleState::None; ADV_SETS]);
579    let advertise_handles: &'static mut [AdvHandleState] = unsafe { transmute_slice(advertise_handles) };
580    let host: BleHost<'_, C, P> = BleHost::new(controller, connections, channels, advertise_handles);
581
582    Stack { host }
583}
584
585/// Contains the host stack
586pub struct Stack<'stack, C, P: PacketPool> {
587    host: BleHost<'stack, C, P>,
588}
589
590/// Host components.
591#[non_exhaustive]
592pub struct Host<'stack, C, P: PacketPool> {
593    /// Central role
594    #[cfg(feature = "central")]
595    pub central: Central<'stack, C, P>,
596    /// Peripheral role
597    #[cfg(feature = "peripheral")]
598    pub peripheral: Peripheral<'stack, C, P>,
599    /// Host runner
600    pub runner: Runner<'stack, C, P>,
601}
602
603impl<'stack, C: Controller, P: PacketPool> Stack<'stack, C, P> {
604    /// Set the random address used by this host.
605    pub fn set_random_address(mut self, address: Address) -> Self {
606        self.host.address.replace(address);
607        #[cfg(feature = "security")]
608        self.host.connections.security_manager.set_local_address(address);
609        self
610    }
611    /// Set the random generator seed for random generator used by security manager
612    pub fn set_random_generator_seed<RNG: RngCore + CryptoRng>(self, _random_generator: &mut RNG) -> Self {
613        #[cfg(feature = "security")]
614        {
615            let mut random_seed = [0u8; 32];
616            _random_generator.fill_bytes(&mut random_seed);
617            self.host
618                .connections
619                .security_manager
620                .set_random_generator_seed(random_seed);
621        }
622        self
623    }
624    /// Set the IO capabilities used by the security manager.
625    ///
626    /// Only relevant if the feature `security` is enabled.
627    pub fn set_io_capabilities(&self, io_capabilities: IoCapabilities) {
628        #[cfg(feature = "security")]
629        {
630            self.host
631                .connections
632                .security_manager
633                .set_io_capabilities(io_capabilities);
634        }
635    }
636
637    /// Build the stack.
638    pub fn build(&'stack self) -> Host<'stack, C, P> {
639        #[cfg(all(feature = "security", not(feature = "dev-disable-csprng-seed-requirement")))]
640        {
641            if !self.host.connections.security_manager.get_random_generator_seeded() {
642                panic!(
643                    "The security manager random number generator has not been seeded from a cryptographically secure random number generator"
644                )
645            }
646        }
647        Host {
648            #[cfg(feature = "central")]
649            central: Central::new(self),
650            #[cfg(feature = "peripheral")]
651            peripheral: Peripheral::new(self),
652            runner: Runner::new(self),
653        }
654    }
655
656    /// Run a HCI command and return the response.
657    pub async fn command<T>(&self, cmd: T) -> Result<T::Return, BleHostError<C::Error>>
658    where
659        T: SyncCmd,
660        C: ControllerCmdSync<T>,
661    {
662        self.host.command(cmd).await
663    }
664
665    /// Run an async HCI command where the response will generate an event later.
666    pub async fn async_command<T>(&self, cmd: T) -> Result<(), BleHostError<C::Error>>
667    where
668        T: AsyncCmd,
669        C: ControllerCmdAsync<T>,
670    {
671        self.host.async_command(cmd).await
672    }
673
674    /// Read current host metrics
675    pub fn metrics<F: FnOnce(&HostMetrics) -> R, R>(&self, f: F) -> R {
676        self.host.metrics(f)
677    }
678
679    /// Log status information of the host
680    pub fn log_status(&self, verbose: bool) {
681        self.host.log_status(verbose);
682    }
683
684    #[cfg(feature = "security")]
685    /// Get bonded devices
686    pub fn add_bond_information(&self, bond_information: BondInformation) -> Result<(), Error> {
687        self.host
688            .connections
689            .security_manager
690            .add_bond_information(bond_information)
691    }
692
693    #[cfg(feature = "security")]
694    /// Remove a bonded device
695    pub fn remove_bond_information(&self, identity: Identity) -> Result<(), Error> {
696        self.host.connections.security_manager.remove_bond_information(identity)
697    }
698
699    #[cfg(feature = "security")]
700    /// Get bonded devices
701    pub fn get_bond_information(&self) -> Vec<BondInformation, BI_COUNT> {
702        self.host.connections.security_manager.get_bond_information()
703    }
704
705    /// Get a connection by its peer address
706    pub fn get_connection_by_peer_address(&'stack self, peer_address: Address) -> Option<Connection<'stack, P>> {
707        self.host.connections.get_connection_by_peer_address(peer_address)
708    }
709}
710
711pub(crate) fn bt_hci_duration<const US: u32>(d: Duration) -> bt_hci::param::Duration<US> {
712    bt_hci::param::Duration::from_micros(d.as_micros())
713}
714
715pub(crate) fn bt_hci_ext_duration<const US: u16>(d: Duration) -> bt_hci::param::ExtDuration<US> {
716    bt_hci::param::ExtDuration::from_micros(d.as_micros())
717}