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::cell::{Cell, RefCell};
9use core::mem::{ManuallyDrop, MaybeUninit};
10
11use advertise::AdvertisementDataError;
12use bt_hci::cmd::le::LeReadMinimumSupportedConnectionInterval;
13use bt_hci::cmd::status::ReadRssi;
14use bt_hci::cmd::{AsyncCmd, SyncCmd};
15use bt_hci::param::{AddrKind, BdAddr, ConnHandle};
16use bt_hci::FromHciBytesError;
17use embassy_time::Duration;
18#[cfg(feature = "security")]
19use heapless::{Vec, VecView};
20
21use crate::att::AttErrorCode;
22use crate::channel_manager::ChannelStorage;
23use crate::connection::Connection;
24use crate::connection_manager::ConnectionStorage;
25#[cfg(feature = "security")]
26pub use crate::security_manager::{
27 BondInformation, IdentityResolvingKey, LongTermKey, OobData, Reason as PairingFailedReason,
28};
29pub use crate::types::capabilities::IoCapabilities;
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 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, HostResources, Packet, PacketPool, Stack, StackBuilder};
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::{ConnectRateParams, *};
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::{
110 BondInformation, IdentityResolvingKey, LongTermKey, OobData, Reason as PairingFailedReason,
111 };
112 pub use crate::types::capabilities::IoCapabilities;
113 #[cfg(feature = "gatt")]
114 pub use crate::types::gatt_traits::{AsGatt, FixedGattValue, FromGatt};
115 pub use crate::{Address, Identity};
116}
117
118#[cfg(feature = "gatt")]
119pub mod attribute;
120#[cfg(feature = "gatt")]
121mod attribute_server;
122#[cfg(feature = "gatt")]
123pub mod gatt;
124
125#[derive(Debug, Clone, Copy, Default, Eq)]
137#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
138pub struct Address {
139 pub kind: AddrKind,
141 pub addr: BdAddr,
143}
144
145impl PartialEq for Address {
146 fn eq(&self, other: &Self) -> bool {
153 self.addr == other.addr && self.kind.as_raw() & 1 == other.kind.as_raw() & 1
154 }
155}
156
157impl Address {
158 pub const fn new(kind: AddrKind, addr: BdAddr) -> Self {
160 Self { kind, addr }
161 }
162
163 pub fn random(val: [u8; 6]) -> Self {
165 Self {
166 kind: AddrKind::RANDOM,
167 addr: BdAddr::new(val),
168 }
169 }
170
171 pub fn to_bytes(&self) -> [u8; 7] {
173 let mut bytes = [0; 7];
174 bytes[0] = self.kind.into_inner();
175 let mut addr_bytes = self.addr.into_inner();
176 addr_bytes.reverse();
177 bytes[1..].copy_from_slice(&addr_bytes);
178 bytes
179 }
180}
181
182impl core::fmt::Display for Address {
183 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
184 let a = self.addr.into_inner();
185 write!(
186 f,
187 "{:02X}:{:02X}:{:02X}:{:02X}:{:02X}:{:02X}",
188 a[5], a[4], a[3], a[2], a[1], a[0]
189 )
190 }
191}
192
193#[cfg(feature = "defmt")]
194impl defmt::Format for Address {
195 fn format(&self, fmt: defmt::Formatter) {
196 let a = self.addr.into_inner();
197 defmt::write!(
198 fmt,
199 "{:02X}:{:02X}:{:02X}:{:02X}:{:02X}:{:02X}",
200 a[5],
201 a[4],
202 a[3],
203 a[2],
204 a[1],
205 a[0]
206 )
207 }
208}
209
210#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
216#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
217pub struct Identity {
218 pub addr: Address,
220
221 #[cfg(feature = "security")]
223 pub irk: Option<IdentityResolvingKey>,
224}
225
226#[cfg(feature = "defmt")]
227impl defmt::Format for Identity {
228 fn format(&self, fmt: defmt::Formatter) {
229 defmt::write!(fmt, "Addr({}) ", self.addr);
230 #[cfg(feature = "security")]
231 defmt::write!(fmt, "Irk({:X})", self.irk);
232 }
233}
234
235impl From<Address> for Identity {
236 fn from(addr: Address) -> Self {
237 Self {
238 addr,
239 #[cfg(feature = "security")]
240 irk: None,
241 }
242 }
243}
244
245impl Identity {
246 pub fn match_address(&self, address: &Address) -> bool {
250 if self.addr == *address {
251 return true;
252 }
253 #[cfg(feature = "security")]
254 if let Some(irk) = self.irk {
255 return irk.resolve_address(&address.addr);
256 }
257 false
258 }
259
260 pub fn match_identity(&self, identity: &Identity) -> bool {
262 if self.addr == identity.addr {
263 return true;
264 }
265 #[cfg(feature = "security")]
266 {
267 if let Some(irk) = self.irk {
268 if irk.resolve_address(&identity.addr.addr) {
269 return true;
270 }
271 }
272 if let Some(irk) = identity.irk {
273 if let Some(current_irk) = self.irk {
274 if irk == current_irk {
275 return true;
276 }
277 }
278 if irk.resolve_address(&self.addr.addr) {
279 return true;
280 }
281 }
282 }
283 false
284 }
285}
286
287#[derive(Debug)]
289#[cfg_attr(feature = "defmt", derive(defmt::Format))]
290pub enum BleHostError<E> {
291 Controller(E),
293 BleHost(Error),
295}
296
297pub const MAX_INVALID_DATA_LEN: usize = 16;
299
300#[derive(Debug, Clone, PartialEq)]
302#[cfg_attr(feature = "defmt", derive(defmt::Format))]
303pub enum Error {
304 Hci(bt_hci::param::Error),
306 HciDecode(FromHciBytesError),
308 Att(AttErrorCode),
310 #[cfg(feature = "security")]
311 Security(PairingFailedReason),
313 InsufficientSpace,
315 InvalidValue,
317
318 UnexpectedDataLength {
324 expected: usize,
326 actual: usize,
328 },
329
330 CannotConstructGattValue([u8; MAX_INVALID_DATA_LEN]),
332
333 ConfigFilterAcceptListIsEmpty,
335
336 UnexpectedGattResponse,
338
339 MalformedCharacteristicDeclaration {
341 expected: usize,
343 actual: usize,
345 },
346
347 InvalidCharacteristicDeclarationData,
349
350 FailedToFinalize {
352 expected: usize,
354 actual: usize,
356 },
357
358 CodecError(codec::Error),
360
361 ExtendedAdvertisingNotSupported,
363
364 InvalidUuidLength(usize),
366
367 Advertisement(AdvertisementDataError),
369 L2capConnectError(crate::types::l2cap::LeCreditConnResultCode),
371 InvalidChannelId,
373 NoChannelAvailable,
375 NotFound,
377 InvalidState,
379 OutOfMemory,
381 NotSupported,
383 ChannelClosed,
385 Timeout,
387 Busy,
389 NoPermits,
391 Disconnected,
393 ConnectionLimitReached,
395 GattSubscriberLimitReached,
399 AlreadyInUse,
401 Other,
403}
404
405impl<E> From<Error> for BleHostError<E> {
406 fn from(value: Error) -> Self {
407 Self::BleHost(value)
408 }
409}
410
411impl From<FromHciBytesError> for Error {
412 fn from(error: FromHciBytesError) -> Self {
413 Self::HciDecode(error)
414 }
415}
416
417impl From<AttErrorCode> for Error {
418 fn from(error: AttErrorCode) -> Self {
419 Self::Att(error)
420 }
421}
422
423impl<E> From<bt_hci::cmd::Error<E>> for BleHostError<E> {
424 fn from(error: bt_hci::cmd::Error<E>) -> Self {
425 match error {
426 bt_hci::cmd::Error::Hci(p) => Self::BleHost(Error::Hci(p)),
427 bt_hci::cmd::Error::Io(p) => Self::Controller(p),
428 }
429 }
430}
431
432impl<E> From<bt_hci::param::Error> for BleHostError<E> {
433 fn from(error: bt_hci::param::Error) -> Self {
434 Self::BleHost(Error::Hci(error))
435 }
436}
437
438impl From<codec::Error> for Error {
439 fn from(error: codec::Error) -> Self {
440 match error {
441 codec::Error::InsufficientSpace => Error::InsufficientSpace,
442 codec::Error::InvalidValue => Error::CodecError(error),
443 }
444 }
445}
446
447impl<E> From<codec::Error> for BleHostError<E> {
448 fn from(error: codec::Error) -> Self {
449 match error {
450 codec::Error::InsufficientSpace => BleHostError::BleHost(Error::InsufficientSpace),
451 codec::Error::InvalidValue => BleHostError::BleHost(Error::InvalidValue),
452 }
453 }
454}
455
456use bt_hci::cmd::controller_baseband::*;
457use bt_hci::cmd::info::*;
458use bt_hci::cmd::le::*;
459use bt_hci::cmd::link_control::*;
460use bt_hci::controller::{ControllerCmdAsync, ControllerCmdSync};
461
462#[cfg(feature = "security")]
468pub trait SecurityCmds:
469 bt_hci::controller::Controller
470 + ControllerCmdSync<LeLongTermKeyRequestReply>
471 + ControllerCmdAsync<LeEnableEncryption>
472 + ControllerCmdSync<LeAddDeviceToResolvingList>
473 + ControllerCmdSync<LeRemoveDeviceFromResolvingList>
474 + ControllerCmdSync<LeClearResolvingList>
475 + ControllerCmdSync<LeSetAddrResolutionEnable>
476 + ControllerCmdSync<LeSetResolvablePrivateAddrTimeout>
477 + ControllerCmdSync<LeSetPrivacyMode>
478 + ControllerCmdSync<LeRand>
479{
480}
481
482#[cfg(feature = "security")]
483impl<
484 C: bt_hci::controller::Controller
485 + ControllerCmdSync<LeLongTermKeyRequestReply>
486 + ControllerCmdAsync<LeEnableEncryption>
487 + ControllerCmdSync<LeAddDeviceToResolvingList>
488 + ControllerCmdSync<LeRemoveDeviceFromResolvingList>
489 + ControllerCmdSync<LeClearResolvingList>
490 + ControllerCmdSync<LeSetAddrResolutionEnable>
491 + ControllerCmdSync<LeSetResolvablePrivateAddrTimeout>
492 + ControllerCmdSync<LeSetPrivacyMode>
493 + ControllerCmdSync<LeRand>,
494 > SecurityCmds for C
495{
496}
497
498#[cfg(not(feature = "security"))]
500pub trait SecurityCmds: bt_hci::controller::Controller {}
501
502#[cfg(not(feature = "security"))]
503impl<C: bt_hci::controller::Controller> SecurityCmds for C {}
504
505pub trait Controller:
509 bt_hci::controller::Controller
510 + embedded_io::ErrorType<Error: crate::fmt::Format>
511 + ControllerCmdSync<LeReadBufferSize>
512 + ControllerCmdSync<Disconnect>
513 + ControllerCmdSync<SetEventMask>
514 + ControllerCmdSync<SetEventMaskPage2>
515 + ControllerCmdSync<LeSetEventMask>
516 + ControllerCmdSync<LeSetRandomAddr>
517 + ControllerCmdSync<HostBufferSize>
518 + ControllerCmdAsync<LeConnUpdate>
519 + ControllerCmdSync<LeReadFilterAcceptListSize>
520 + ControllerCmdSync<SetControllerToHostFlowControl>
521 + ControllerCmdSync<Reset>
522 + ControllerCmdSync<ReadRssi>
523 + ControllerCmdSync<LeCreateConnCancel>
524 + ControllerCmdSync<LeSetScanEnable>
525 + ControllerCmdSync<LeSetExtScanEnable>
526 + ControllerCmdAsync<LeCreateConn>
527 + ControllerCmdSync<LeClearFilterAcceptList>
528 + ControllerCmdSync<LeAddDeviceToFilterAcceptList>
529 + for<'t> ControllerCmdSync<LeSetAdvEnable>
530 + for<'t> ControllerCmdSync<LeSetExtAdvEnable<'t>>
531 + for<'t> ControllerCmdSync<HostNumberOfCompletedPackets<'t>>
532 + ControllerCmdSync<LeReadBufferSize>
533 + for<'t> ControllerCmdSync<LeSetAdvData>
534 + ControllerCmdSync<LeSetAdvParams>
535 + for<'t> ControllerCmdSync<LeSetAdvEnable>
536 + for<'t> ControllerCmdSync<LeSetScanResponseData>
537 + ControllerCmdSync<ReadBdAddr>
538 + SecurityCmds
539{
540}
541
542impl<
543 C: bt_hci::controller::Controller
544 + embedded_io::ErrorType<Error: crate::fmt::Format>
545 + ControllerCmdSync<LeReadBufferSize>
546 + ControllerCmdSync<Disconnect>
547 + ControllerCmdSync<SetEventMask>
548 + ControllerCmdSync<SetEventMaskPage2>
549 + ControllerCmdSync<LeSetEventMask>
550 + ControllerCmdSync<LeSetRandomAddr>
551 + ControllerCmdSync<HostBufferSize>
552 + ControllerCmdAsync<LeConnUpdate>
553 + ControllerCmdSync<LeReadFilterAcceptListSize>
554 + ControllerCmdSync<LeClearFilterAcceptList>
555 + ControllerCmdSync<LeAddDeviceToFilterAcceptList>
556 + ControllerCmdSync<SetControllerToHostFlowControl>
557 + ControllerCmdSync<Reset>
558 + ControllerCmdSync<ReadRssi>
559 + ControllerCmdSync<LeSetScanEnable>
560 + ControllerCmdSync<LeSetExtScanEnable>
561 + ControllerCmdSync<LeCreateConnCancel>
562 + ControllerCmdAsync<LeCreateConn>
563 + for<'t> ControllerCmdSync<LeSetAdvEnable>
564 + for<'t> ControllerCmdSync<LeSetExtAdvEnable<'t>>
565 + for<'t> ControllerCmdSync<HostNumberOfCompletedPackets<'t>>
566 + ControllerCmdSync<LeReadBufferSize>
567 + for<'t> ControllerCmdSync<LeSetAdvData>
568 + ControllerCmdSync<LeSetAdvParams>
569 + for<'t> ControllerCmdSync<LeSetAdvEnable>
570 + for<'t> ControllerCmdSync<LeSetScanResponseData>
571 + ControllerCmdSync<ReadBdAddr>
572 + SecurityCmds,
573 > Controller for C
574{
575}
576
577pub trait Packet: Sized + AsRef<[u8]> + AsMut<[u8]> {}
580
581pub trait PacketPool: 'static {
585 type Packet: Packet;
587
588 const MTU: usize;
590
591 fn allocate() -> Option<Self::Packet>;
599
600 fn capacity() -> usize;
602}
603
604pub struct HostResources<
609 C: Controller,
610 P: PacketPool,
611 const CONNS: usize,
612 const CHANNELS: usize,
613 const ADV_SETS: usize = 1,
614 const BONDS: usize = 10,
615> {
616 host: MaybeUninit<ManuallyDrop<BleHost<'static, C, P>>>,
617 connections: MaybeUninit<RefCell<[ConnectionStorage<P::Packet>; CONNS]>>,
618 channels: MaybeUninit<RefCell<[ChannelStorage<P::Packet>; CHANNELS]>>,
619 advertise_handles: MaybeUninit<RefCell<[AdvHandleState; ADV_SETS]>>,
620 #[cfg(feature = "security")]
621 bond_storage: MaybeUninit<RefCell<Vec<BondInformation, BONDS>>>,
622}
623
624impl<
625 C: Controller,
626 P: PacketPool,
627 const CONNS: usize,
628 const CHANNELS: usize,
629 const ADV_SETS: usize,
630 const BONDS: usize,
631 > Default for HostResources<C, P, CONNS, CHANNELS, ADV_SETS, BONDS>
632{
633 fn default() -> Self {
634 Self::new()
635 }
636}
637
638impl<
639 C: Controller,
640 P: PacketPool,
641 const CONNS: usize,
642 const CHANNELS: usize,
643 const ADV_SETS: usize,
644 const BONDS: usize,
645 > HostResources<C, P, CONNS, CHANNELS, ADV_SETS, BONDS>
646{
647 pub const fn new() -> Self {
649 Self {
650 host: MaybeUninit::uninit(),
651 connections: MaybeUninit::uninit(),
652 channels: MaybeUninit::uninit(),
653 advertise_handles: MaybeUninit::uninit(),
654 #[cfg(feature = "security")]
655 bond_storage: MaybeUninit::uninit(),
656 }
657 }
658}
659
660pub fn new<
663 'resources,
664 C: Controller,
665 P: PacketPool,
666 const CONNS: usize,
667 const CHANNELS: usize,
668 const ADV_SETS: usize,
669 const BONDS: usize,
670>(
671 controller: C,
672 resources: &'resources mut HostResources<C, P, CONNS, CHANNELS, ADV_SETS, BONDS>,
673) -> StackBuilder<'resources, C, P> {
674 let connections: &'resources RefCell<[ConnectionStorage<P::Packet>]> = resources
675 .connections
676 .write(RefCell::new([const { ConnectionStorage::new() }; CONNS]));
677
678 let channels: &'resources RefCell<[ChannelStorage<P::Packet>]> = resources
679 .channels
680 .write(RefCell::new([const { ChannelStorage::new() }; CHANNELS]));
681
682 let advertise_handles: &'resources RefCell<[AdvHandleState]> = resources
683 .advertise_handles
684 .write(RefCell::new([AdvHandleState::None; ADV_SETS]));
685
686 #[cfg(feature = "security")]
687 let bond_storage: &'resources RefCell<VecView<BondInformation>> =
688 resources.bond_storage.write(RefCell::new(Vec::new()));
689
690 let host: &'resources mut MaybeUninit<ManuallyDrop<BleHost<'resources, C, P>>> =
698 unsafe { core::mem::transmute(&mut resources.host) };
699
700 let host: &'resources mut ManuallyDrop<BleHost<'resources, C, P>> = host.write(ManuallyDrop::new(BleHost::new(
701 controller,
702 connections,
703 channels,
704 advertise_handles,
705 #[cfg(feature = "security")]
706 bond_storage,
707 )));
708
709 StackBuilder { host: Some(host) }
710}
711
712pub struct Stack<'stack, C, P: PacketPool> {
714 host: &'stack mut ManuallyDrop<BleHost<'stack, C, P>>,
715 runner_taken: Cell<bool>,
716}
717
718impl<'stack, C, P: PacketPool> Drop for Stack<'stack, C, P> {
719 fn drop(&mut self) {
720 unsafe { ManuallyDrop::drop(self.host) }
725 }
726}
727
728pub struct StackBuilder<'stack, C, P: PacketPool> {
732 host: Option<&'stack mut ManuallyDrop<BleHost<'stack, C, P>>>,
733}
734
735impl<'stack, C, P: PacketPool> Drop for StackBuilder<'stack, C, P> {
736 fn drop(&mut self) {
737 if let Some(host) = &mut self.host {
738 unsafe { ManuallyDrop::drop(host) }
742 }
743 }
744}
745
746impl<'stack, C: Controller, P: PacketPool> StackBuilder<'stack, C, P> {
747 fn host(&mut self) -> &mut BleHost<'stack, C, P> {
748 self.host.as_mut().unwrap()
749 }
750
751 pub fn register_l2cap_spsm(mut self, spsm: u16) -> Self {
753 self.host().channels.register_spsm(spsm);
754 self
755 }
756
757 pub fn set_random_address(mut self, address: Address) -> Self {
759 self.host().address.replace(address);
760 #[cfg(feature = "security")]
761 self.host().connections.security_manager.set_local_address(address);
762 self
763 }
764
765 #[cfg(feature = "security")]
779 pub fn enable_privacy(mut self, irk: IdentityResolvingKey) -> Self {
780 self.host().connections.security_manager.set_local_irk(irk);
781 self
782 }
783
784 #[cfg(feature = "security")]
789 pub fn set_rpa_timeout(mut self, timeout: Duration) -> Self {
790 self.host().rpa_timeout.set(timeout);
791 self
792 }
793
794 #[cfg(feature = "security")]
798 pub fn set_io_capabilities(mut self, io_capabilities: IoCapabilities) -> Self {
799 self.host()
800 .connections
801 .security_manager
802 .set_io_capabilities(io_capabilities);
803 self
804 }
805
806 #[cfg(feature = "legacy-pairing")]
813 pub fn set_secure_connections_only(mut self, enabled: bool) -> Self {
814 self.host()
815 .connections
816 .security_manager
817 .set_secure_connections_only(enabled);
818 self
819 }
820
821 pub fn build(mut self) -> Stack<'stack, C, P> {
828 Stack {
829 host: self.host.take().unwrap(),
830 runner_taken: Cell::new(false),
831 }
832 }
833}
834
835impl<'stack, C: Controller, P: PacketPool> Stack<'stack, C, P> {
836 pub fn runner(&self) -> Runner<'_, C, P> {
840 assert!(
841 !self.runner_taken.replace(true),
842 "runner() can only be called once per Stack"
843 );
844 Runner::new(self.host)
845 }
846
847 #[cfg(feature = "central")]
852 pub fn central(&self) -> Central<'_, C, P> {
853 Central::new(self.host)
854 }
855
856 #[cfg(feature = "peripheral")]
861 pub fn peripheral(&self) -> Peripheral<'_, C, P> {
862 Peripheral::new(self.host)
863 }
864
865 #[cfg(feature = "security")]
869 pub fn set_io_capabilities(&self, io_capabilities: IoCapabilities) {
870 self.host
871 .connections
872 .security_manager
873 .set_io_capabilities(io_capabilities);
874 }
875
876 #[cfg(feature = "legacy-pairing")]
883 pub fn set_secure_connections_only(&self, enabled: bool) {
884 self.host
885 .connections
886 .security_manager
887 .set_secure_connections_only(enabled);
888 }
889
890 #[cfg(feature = "security")]
899 pub async fn set_rpa_timeout(&self, timeout: Duration) -> Result<(), BleHostError<C::Error>>
900 where
901 C: ControllerCmdSync<LeSetResolvablePrivateAddrTimeout>,
902 {
903 self.host.rpa_timeout.set(timeout);
904 if self.host.is_initialized() {
905 self.host
906 .command(LeSetResolvablePrivateAddrTimeout::new(
907 bt_hci::param::Duration::from_secs(timeout.as_secs() as u32),
908 ))
909 .await?;
910 }
911 Ok(())
912 }
913
914 pub async fn command<T>(&self, cmd: T) -> Result<T::Return, BleHostError<C::Error>>
916 where
917 T: SyncCmd,
918 C: ControllerCmdSync<T>,
919 {
920 self.host.command(cmd).await
921 }
922
923 pub async fn async_command<T>(&self, cmd: T) -> Result<(), BleHostError<C::Error>>
925 where
926 T: AsyncCmd,
927 C: ControllerCmdAsync<T>,
928 {
929 self.host.async_command(cmd).await
930 }
931
932 pub async fn read_minimum_supported_connection_interval(
934 &self,
935 ) -> Result<<LeReadMinimumSupportedConnectionInterval as SyncCmd>::Return, BleHostError<C::Error>>
936 where
937 C: ControllerCmdSync<LeReadMinimumSupportedConnectionInterval>,
938 {
939 self.host.command(LeReadMinimumSupportedConnectionInterval::new()).await
940 }
941
942 pub fn metrics<F: FnOnce(&HostMetrics) -> R, R>(&self, f: F) -> R {
944 self.host.metrics(f)
945 }
946
947 pub fn log_status(&self, verbose: bool) {
949 self.host.log_status(verbose);
950 }
951
952 #[cfg(feature = "security")]
953 pub fn get_local_oob_data(&self) -> OobData {
958 self.host.connections.security_manager.get_local_oob_data()
959 }
960
961 #[cfg(feature = "security")]
962 pub fn get_local_address(&self) -> Option<Address> {
964 self.host.connections.security_manager.get_local_address()
965 }
966
967 #[cfg(feature = "security")]
969 pub fn is_privacy_enabled(&self) -> bool {
970 self.host.is_privacy_enabled()
971 }
972
973 #[cfg(feature = "security")]
974 pub fn add_bond_information(&self, bond_information: BondInformation) -> Result<(), Error> {
981 let identity = bond_information.identity;
982 let result = self
983 .host
984 .connections
985 .security_manager
986 .add_bond_information(bond_information);
987 #[cfg(feature = "security")]
988 if result.is_ok() {
989 self.host
990 .resolving_list_state
991 .borrow_mut()
992 .push(crate::host::ResolvingListUpdate::Add(identity));
993 }
994 result
995 }
996
997 #[cfg(feature = "security")]
998 pub fn remove_bond_information(&self, identity: Identity) -> Result<(), Error> {
1005 let result = self.host.connections.security_manager.remove_bond_information(identity);
1006 #[cfg(feature = "security")]
1007 if result.is_ok() {
1008 self.host
1009 .resolving_list_state
1010 .borrow_mut()
1011 .push(crate::host::ResolvingListUpdate::Remove(identity));
1012 }
1013 result
1014 }
1015
1016 #[cfg(feature = "security")]
1017 pub fn with_bond_information<R>(&self, f: impl FnOnce(&[BondInformation]) -> R) -> R {
1019 f(&self.host.connections.security_manager.get_bond_information())
1020 }
1021
1022 pub fn get_connection_by_peer_address(&self, peer_address: Address) -> Option<Connection<'_, P>> {
1024 self.host.connections.get_connection_by_peer_address(peer_address)
1025 }
1026
1027 pub fn get_connected_handle(&self, handle: ConnHandle) -> Option<Connection<'_, P>> {
1029 self.host.connections.get_connected_handle(handle)
1030 }
1031
1032 pub fn connections(&self) -> connection_manager::ConnectedIter<'_, P> {
1034 self.host.connections.connections()
1035 }
1036}
1037
1038pub(crate) fn bt_hci_duration<const US: u32>(d: Duration) -> bt_hci::param::Duration<US> {
1039 bt_hci::param::Duration::from_micros(d.as_micros())
1040}
1041
1042pub(crate) fn bt_hci_ext_duration<const US: u16>(d: Duration) -> bt_hci::param::ExtDuration<US> {
1043 bt_hci::param::ExtDuration::from_micros(d.as_micros())
1044}
1045
1046#[doc(hidden)]
1048pub mod __export {
1049 pub use embassy_sync;
1050}