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