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;
13#[cfg(feature = "shorter-connection-intervals")]
14use bt_hci::cmd::le::LeSetHostFeatureV2;
15use bt_hci::cmd::status::ReadRssi;
16use bt_hci::cmd::{AsyncCmd, SyncCmd};
17use bt_hci::param::{AddrKind, BdAddr, ConnHandle};
18use bt_hci::FromHciBytesError;
19use embassy_time::Duration;
20#[cfg(feature = "security")]
21use heapless::{Vec, VecView};
22
23use crate::att::AttErrorCode;
24use crate::channel_manager::ChannelStorage;
25use crate::connection::Connection;
26use crate::connection_manager::ConnectionStorage;
27#[cfg(feature = "security")]
28pub use crate::security_manager::{
29 BondInformation, IdentityResolvingKey, LongTermKey, OobData, Reason as PairingFailedReason,
30};
31pub use crate::types::capabilities::IoCapabilities;
32
33mod fmt;
34
35#[cfg(not(any(feature = "central", feature = "peripheral")))]
36compile_error!("Must enable at least one of the `central` or `peripheral` features");
37
38pub mod att;
39#[cfg(feature = "central")]
40pub mod central;
41mod channel_manager;
42mod codec;
43mod command;
44pub mod config;
45mod connection_manager;
46mod cursor;
47#[cfg(feature = "iso")]
48pub mod iso;
49#[cfg(feature = "default-packet-pool")]
50mod packet_pool;
51mod pdu;
52#[cfg(feature = "peripheral")]
53pub mod peripheral;
54#[cfg(feature = "security")]
55mod security_manager;
56pub mod types;
57
58#[cfg(feature = "central")]
59use central::*;
60#[cfg(feature = "peripheral")]
61use peripheral::*;
62
63pub mod advertise;
64pub mod connection;
65#[cfg(feature = "gatt")]
66pub mod gap;
67pub mod l2cap;
68#[cfg(feature = "scan")]
69pub mod scan;
70
71#[cfg(test)]
72pub(crate) mod mock_controller;
73
74pub(crate) mod host;
75use host::{AdvHandleState, BleHost, HostMetrics, Runner};
76
77pub mod prelude {
78 pub use bt_hci::controller::ExternalController;
80 pub use bt_hci::param::{AddrKind, BdAddr, LeConnRole as Role, PhyKind, PhyMask};
81 pub use bt_hci::uuid::*;
82 #[cfg(feature = "derive")]
83 pub use heapless::String as HeaplessString;
84 #[cfg(feature = "derive")]
85 pub use trouble_host_macros::*;
86
87 pub use super::att::AttErrorCode;
88 pub use super::{BleHostError, Controller, Error, HostResources, Packet, PacketPool, Stack, StackBuilder};
89 #[cfg(feature = "peripheral")]
90 pub use crate::advertise::*;
91 #[cfg(feature = "gatt")]
92 pub use crate::attribute::*;
93 #[cfg(feature = "gatt")]
94 pub use crate::attribute_server::*;
95 #[cfg(feature = "central")]
96 pub use crate::central::*;
97 pub use crate::connection::{ConnectRateParams, *};
98 #[cfg(feature = "gatt")]
99 pub use crate::gap::*;
100 #[cfg(feature = "gatt")]
101 pub use crate::gatt::*;
102 pub use crate::host::{ControlRunner, EventHandler, HostMetrics, Runner, RxRunner, TxRunner};
103 #[cfg(feature = "iso")]
104 pub use crate::iso::Iso;
105 pub use crate::l2cap::*;
106 #[cfg(feature = "default-packet-pool")]
107 pub use crate::packet_pool::DefaultPacketPool;
108 pub use crate::pdu::Sdu;
109 #[cfg(feature = "peripheral")]
110 pub use crate::peripheral::*;
111 #[cfg(feature = "scan")]
112 pub use crate::scan::*;
113 #[cfg(feature = "security")]
114 pub use crate::security_manager::{
115 BondInformation, IdentityResolvingKey, LongTermKey, OobData, Reason as PairingFailedReason,
116 };
117 pub use crate::types::capabilities::IoCapabilities;
118 #[cfg(feature = "gatt")]
119 pub use crate::types::gatt_traits::{AsGatt, FixedGattValue, FromGatt};
120 pub use crate::{Address, Identity};
121}
122
123#[cfg(feature = "gatt")]
124pub mod attribute;
125#[cfg(feature = "gatt")]
126mod attribute_server;
127#[cfg(feature = "gatt")]
128pub mod gatt;
129
130#[derive(Debug, Clone, Copy, Default, Eq)]
142#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
143pub struct Address {
144 pub kind: AddrKind,
146 pub addr: BdAddr,
148}
149
150impl PartialEq for Address {
151 fn eq(&self, other: &Self) -> bool {
158 self.addr == other.addr && self.kind.as_raw() & 1 == other.kind.as_raw() & 1
159 }
160}
161
162impl Address {
163 pub const fn new(kind: AddrKind, addr: BdAddr) -> Self {
165 Self { kind, addr }
166 }
167
168 pub fn random(val: [u8; 6]) -> Self {
170 Self {
171 kind: AddrKind::RANDOM,
172 addr: BdAddr::new(val),
173 }
174 }
175
176 pub fn to_bytes(&self) -> [u8; 7] {
178 let mut bytes = [0; 7];
179 bytes[0] = self.kind.into_inner();
180 let mut addr_bytes = self.addr.into_inner();
181 addr_bytes.reverse();
182 bytes[1..].copy_from_slice(&addr_bytes);
183 bytes
184 }
185}
186
187impl core::fmt::Display for Address {
188 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
189 let a = self.addr.into_inner();
190 write!(
191 f,
192 "{:02X}:{:02X}:{:02X}:{:02X}:{:02X}:{:02X}",
193 a[5], a[4], a[3], a[2], a[1], a[0]
194 )
195 }
196}
197
198#[cfg(feature = "defmt")]
199impl defmt::Format for Address {
200 fn format(&self, fmt: defmt::Formatter) {
201 let a = self.addr.into_inner();
202 defmt::write!(
203 fmt,
204 "{:02X}:{:02X}:{:02X}:{:02X}:{:02X}:{:02X}",
205 a[5],
206 a[4],
207 a[3],
208 a[2],
209 a[1],
210 a[0]
211 )
212 }
213}
214
215#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
221#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
222pub struct Identity {
223 pub addr: Address,
225
226 #[cfg(feature = "security")]
228 pub irk: Option<IdentityResolvingKey>,
229}
230
231#[cfg(feature = "defmt")]
232impl defmt::Format for Identity {
233 fn format(&self, fmt: defmt::Formatter) {
234 defmt::write!(fmt, "Addr({}) ", self.addr);
235 #[cfg(feature = "security")]
236 defmt::write!(fmt, "Irk({:X})", self.irk);
237 }
238}
239
240impl From<Address> for Identity {
241 fn from(addr: Address) -> Self {
242 Self {
243 addr,
244 #[cfg(feature = "security")]
245 irk: None,
246 }
247 }
248}
249
250impl Identity {
251 pub fn match_address(&self, address: &Address) -> bool {
255 if self.addr == *address {
256 return true;
257 }
258 #[cfg(feature = "security")]
259 if let Some(irk) = self.irk {
260 return irk.resolve_address(&address.addr);
261 }
262 false
263 }
264
265 pub fn match_identity(&self, identity: &Identity) -> bool {
267 if self.addr == identity.addr {
268 return true;
269 }
270 #[cfg(feature = "security")]
271 {
272 if let Some(irk) = self.irk {
273 if irk.resolve_address(&identity.addr.addr) {
274 return true;
275 }
276 }
277 if let Some(irk) = identity.irk {
278 if let Some(current_irk) = self.irk {
279 if irk == current_irk {
280 return true;
281 }
282 }
283 if irk.resolve_address(&self.addr.addr) {
284 return true;
285 }
286 }
287 }
288 false
289 }
290}
291
292#[derive(Debug)]
294#[cfg_attr(feature = "defmt", derive(defmt::Format))]
295pub enum BleHostError<E> {
296 Controller(E),
298 BleHost(Error),
300}
301
302pub const MAX_INVALID_DATA_LEN: usize = 16;
304
305#[derive(Debug, Clone, PartialEq)]
307#[cfg_attr(feature = "defmt", derive(defmt::Format))]
308pub enum Error {
309 Hci(bt_hci::param::Error),
311 HciDecode(FromHciBytesError),
313 Att(AttErrorCode),
315 #[cfg(feature = "security")]
316 Security(PairingFailedReason),
318 InsufficientSpace,
320 InvalidValue,
322
323 UnexpectedDataLength {
329 expected: usize,
331 actual: usize,
333 },
334
335 CannotConstructGattValue([u8; MAX_INVALID_DATA_LEN]),
337
338 ConfigFilterAcceptListIsEmpty,
340
341 UnexpectedGattResponse,
343
344 MalformedCharacteristicDeclaration {
346 expected: usize,
348 actual: usize,
350 },
351
352 InvalidCharacteristicDeclarationData,
354
355 FailedToFinalize {
357 expected: usize,
359 actual: usize,
361 },
362
363 CodecError(codec::Error),
365
366 ExtendedAdvertisingNotSupported,
368
369 InvalidUuidLength(usize),
371
372 Advertisement(AdvertisementDataError),
374 L2capConnectError(crate::types::l2cap::LeCreditConnResultCode),
376 InvalidChannelId,
378 NoChannelAvailable,
380 NotFound,
382 InvalidState,
384 OutOfMemory,
386 NotSupported,
388 ChannelClosed,
390 Timeout,
392 Busy,
394 NoPermits,
396 Disconnected,
398 ConnectionLimitReached,
400 GattSubscriberLimitReached,
404 AlreadyInUse,
406 Other,
408}
409
410impl<E> From<Error> for BleHostError<E> {
411 fn from(value: Error) -> Self {
412 Self::BleHost(value)
413 }
414}
415
416impl From<FromHciBytesError> for Error {
417 fn from(error: FromHciBytesError) -> Self {
418 Self::HciDecode(error)
419 }
420}
421
422impl From<AttErrorCode> for Error {
423 fn from(error: AttErrorCode) -> Self {
424 Self::Att(error)
425 }
426}
427
428impl<E> From<bt_hci::cmd::Error<E>> for BleHostError<E> {
429 fn from(error: bt_hci::cmd::Error<E>) -> Self {
430 match error {
431 bt_hci::cmd::Error::Hci(p) => Self::BleHost(Error::Hci(p)),
432 bt_hci::cmd::Error::Io(p) => Self::Controller(p),
433 }
434 }
435}
436
437impl<E> From<bt_hci::param::Error> for BleHostError<E> {
438 fn from(error: bt_hci::param::Error) -> Self {
439 Self::BleHost(Error::Hci(error))
440 }
441}
442
443impl From<codec::Error> for Error {
444 fn from(error: codec::Error) -> Self {
445 match error {
446 codec::Error::InsufficientSpace => Error::InsufficientSpace,
447 codec::Error::InvalidValue => Error::CodecError(error),
448 }
449 }
450}
451
452impl<E> From<codec::Error> for BleHostError<E> {
453 fn from(error: codec::Error) -> Self {
454 match error {
455 codec::Error::InsufficientSpace => BleHostError::BleHost(Error::InsufficientSpace),
456 codec::Error::InvalidValue => BleHostError::BleHost(Error::InvalidValue),
457 }
458 }
459}
460
461use bt_hci::cmd::controller_baseband::*;
462use bt_hci::cmd::info::*;
463use bt_hci::cmd::le::*;
464use bt_hci::cmd::link_control::*;
465use bt_hci::controller::{ControllerCmdAsync, ControllerCmdSync};
466
467#[cfg(feature = "security")]
473pub trait SecurityCmds:
474 bt_hci::controller::Controller
475 + ControllerCmdSync<LeLongTermKeyRequestReply>
476 + ControllerCmdAsync<LeEnableEncryption>
477 + ControllerCmdSync<LeAddDeviceToResolvingList>
478 + ControllerCmdSync<LeRemoveDeviceFromResolvingList>
479 + ControllerCmdSync<LeClearResolvingList>
480 + ControllerCmdSync<LeSetAddrResolutionEnable>
481 + ControllerCmdSync<LeSetResolvablePrivateAddrTimeout>
482 + ControllerCmdSync<LeSetPrivacyMode>
483 + ControllerCmdSync<LeRand>
484{
485}
486
487#[cfg(feature = "security")]
488impl<
489 C: bt_hci::controller::Controller
490 + ControllerCmdSync<LeLongTermKeyRequestReply>
491 + ControllerCmdAsync<LeEnableEncryption>
492 + ControllerCmdSync<LeAddDeviceToResolvingList>
493 + ControllerCmdSync<LeRemoveDeviceFromResolvingList>
494 + ControllerCmdSync<LeClearResolvingList>
495 + ControllerCmdSync<LeSetAddrResolutionEnable>
496 + ControllerCmdSync<LeSetResolvablePrivateAddrTimeout>
497 + ControllerCmdSync<LeSetPrivacyMode>
498 + ControllerCmdSync<LeRand>,
499 > SecurityCmds for C
500{
501}
502
503#[cfg(not(feature = "security"))]
505pub trait SecurityCmds: bt_hci::controller::Controller {}
506
507#[cfg(not(feature = "security"))]
508impl<C: bt_hci::controller::Controller> SecurityCmds for C {}
509
510#[cfg(feature = "iso")]
512pub trait IsoStreamCmds: bt_hci::controller::Controller + ControllerCmdSync<LeSetHostFeature> {}
513
514#[cfg(feature = "iso")]
515impl<C: bt_hci::controller::Controller + ControllerCmdSync<LeSetHostFeature>> IsoStreamCmds for C {}
516
517#[cfg(not(feature = "iso"))]
519pub trait IsoStreamCmds: bt_hci::controller::Controller {}
520
521#[cfg(not(feature = "iso"))]
522impl<C: bt_hci::controller::Controller> IsoStreamCmds for C {}
523
524#[cfg(feature = "subrating")]
526pub trait SubratingCmds: bt_hci::controller::Controller + ControllerCmdSync<LeSetHostFeature> {}
527
528#[cfg(feature = "subrating")]
529impl<C: bt_hci::controller::Controller + ControllerCmdSync<LeSetHostFeature>> SubratingCmds for C {}
530
531#[cfg(not(feature = "subrating"))]
533pub trait SubratingCmds: bt_hci::controller::Controller {}
534
535#[cfg(not(feature = "subrating"))]
536impl<C: bt_hci::controller::Controller> SubratingCmds for C {}
537
538#[cfg(feature = "shorter-connection-intervals")]
540pub trait ShortConnIntervalCmds: bt_hci::controller::Controller + ControllerCmdSync<LeSetHostFeatureV2> {}
541
542#[cfg(feature = "shorter-connection-intervals")]
543impl<C: bt_hci::controller::Controller + ControllerCmdSync<LeSetHostFeatureV2>> ShortConnIntervalCmds for C {}
544
545#[cfg(not(feature = "shorter-connection-intervals"))]
547pub trait ShortConnIntervalCmds: bt_hci::controller::Controller {}
548
549#[cfg(not(feature = "shorter-connection-intervals"))]
550impl<C: bt_hci::controller::Controller> ShortConnIntervalCmds for C {}
551
552pub trait Controller:
556 bt_hci::controller::Controller
557 + embedded_io::ErrorType<Error: crate::fmt::Format>
558 + ControllerCmdSync<LeReadBufferSize>
559 + ControllerCmdSync<Disconnect>
560 + ControllerCmdSync<SetEventMask>
561 + ControllerCmdSync<SetEventMaskPage2>
562 + ControllerCmdSync<LeSetEventMask>
563 + ControllerCmdSync<LeSetRandomAddr>
564 + ControllerCmdSync<HostBufferSize>
565 + ControllerCmdAsync<LeConnUpdate>
566 + ControllerCmdSync<LeReadFilterAcceptListSize>
567 + ControllerCmdSync<SetControllerToHostFlowControl>
568 + ControllerCmdSync<Reset>
569 + ControllerCmdSync<ReadRssi>
570 + ControllerCmdSync<LeCreateConnCancel>
571 + ControllerCmdSync<LeSetScanEnable>
572 + ControllerCmdSync<LeSetExtScanEnable>
573 + ControllerCmdAsync<LeCreateConn>
574 + ControllerCmdSync<LeClearFilterAcceptList>
575 + ControllerCmdSync<LeAddDeviceToFilterAcceptList>
576 + for<'t> ControllerCmdSync<LeSetAdvEnable>
577 + for<'t> ControllerCmdSync<LeSetExtAdvEnable<'t>>
578 + for<'t> ControllerCmdSync<HostNumberOfCompletedPackets<'t>>
579 + ControllerCmdSync<LeReadBufferSize>
580 + for<'t> ControllerCmdSync<LeSetAdvData>
581 + ControllerCmdSync<LeSetAdvParams>
582 + for<'t> ControllerCmdSync<LeSetAdvEnable>
583 + for<'t> ControllerCmdSync<LeSetScanResponseData>
584 + ControllerCmdSync<ReadBdAddr>
585 + SecurityCmds
586 + SubratingCmds
587 + IsoStreamCmds
588 + ShortConnIntervalCmds
589{
590}
591
592impl<
593 C: bt_hci::controller::Controller
594 + embedded_io::ErrorType<Error: crate::fmt::Format>
595 + ControllerCmdSync<LeReadBufferSize>
596 + ControllerCmdSync<Disconnect>
597 + ControllerCmdSync<SetEventMask>
598 + ControllerCmdSync<SetEventMaskPage2>
599 + ControllerCmdSync<LeSetEventMask>
600 + ControllerCmdSync<LeSetRandomAddr>
601 + ControllerCmdSync<HostBufferSize>
602 + ControllerCmdAsync<LeConnUpdate>
603 + ControllerCmdSync<LeReadFilterAcceptListSize>
604 + ControllerCmdSync<LeClearFilterAcceptList>
605 + ControllerCmdSync<LeAddDeviceToFilterAcceptList>
606 + ControllerCmdSync<SetControllerToHostFlowControl>
607 + ControllerCmdSync<Reset>
608 + ControllerCmdSync<ReadRssi>
609 + ControllerCmdSync<LeSetScanEnable>
610 + ControllerCmdSync<LeSetExtScanEnable>
611 + ControllerCmdSync<LeCreateConnCancel>
612 + ControllerCmdAsync<LeCreateConn>
613 + for<'t> ControllerCmdSync<LeSetAdvEnable>
614 + for<'t> ControllerCmdSync<LeSetExtAdvEnable<'t>>
615 + for<'t> ControllerCmdSync<HostNumberOfCompletedPackets<'t>>
616 + ControllerCmdSync<LeReadBufferSize>
617 + for<'t> ControllerCmdSync<LeSetAdvData>
618 + ControllerCmdSync<LeSetAdvParams>
619 + for<'t> ControllerCmdSync<LeSetAdvEnable>
620 + for<'t> ControllerCmdSync<LeSetScanResponseData>
621 + ControllerCmdSync<ReadBdAddr>
622 + SecurityCmds
623 + SubratingCmds
624 + IsoStreamCmds
625 + ShortConnIntervalCmds,
626 > Controller for C
627{
628}
629
630pub trait Packet: Sized + AsRef<[u8]> + AsMut<[u8]> {}
633
634pub trait PacketPool: 'static {
638 type Packet: Packet;
640
641 const MTU: usize;
643
644 fn allocate() -> Option<Self::Packet>;
652
653 fn capacity() -> usize;
655}
656
657pub struct HostResources<
662 P: PacketPool,
663 const CONNS: usize,
664 const CHANNELS: usize,
665 const ADV_SETS: usize = 1,
666 const BONDS: usize = 10,
667> {
668 state: MaybeUninit<ManuallyDrop<host::HostState<'static, P>>>,
669 connections: MaybeUninit<RefCell<[ConnectionStorage<P::Packet>; CONNS]>>,
670 channels: MaybeUninit<RefCell<[ChannelStorage<P::Packet>; CHANNELS]>>,
671 advertise_handles: MaybeUninit<RefCell<[AdvHandleState; ADV_SETS]>>,
672 #[cfg(feature = "security")]
673 bond_storage: MaybeUninit<RefCell<Vec<BondInformation, BONDS>>>,
674}
675
676impl<P: PacketPool, const CONNS: usize, const CHANNELS: usize, const ADV_SETS: usize, const BONDS: usize> Default
677 for HostResources<P, CONNS, CHANNELS, ADV_SETS, BONDS>
678{
679 fn default() -> Self {
680 Self::new()
681 }
682}
683
684impl<P: PacketPool, const CONNS: usize, const CHANNELS: usize, const ADV_SETS: usize, const BONDS: usize>
685 HostResources<P, CONNS, CHANNELS, ADV_SETS, BONDS>
686{
687 pub const fn new() -> Self {
689 Self {
690 state: MaybeUninit::uninit(),
691 connections: MaybeUninit::uninit(),
692 channels: MaybeUninit::uninit(),
693 advertise_handles: MaybeUninit::uninit(),
694 #[cfg(feature = "security")]
695 bond_storage: MaybeUninit::uninit(),
696 }
697 }
698}
699
700pub fn new<
703 'resources,
704 C: Controller,
705 P: PacketPool,
706 const CONNS: usize,
707 const CHANNELS: usize,
708 const ADV_SETS: usize,
709 const BONDS: usize,
710>(
711 controller: C,
712 resources: &'resources mut HostResources<P, CONNS, CHANNELS, ADV_SETS, BONDS>,
713) -> StackBuilder<'resources, C, P> {
714 let connections: &'resources RefCell<[ConnectionStorage<P::Packet>]> = resources
715 .connections
716 .write(RefCell::new([const { ConnectionStorage::new() }; CONNS]));
717
718 let channels: &'resources RefCell<[ChannelStorage<P::Packet>]> = resources
719 .channels
720 .write(RefCell::new([const { ChannelStorage::new() }; CHANNELS]));
721
722 let advertise_handles: &'resources RefCell<[AdvHandleState]> = resources
723 .advertise_handles
724 .write(RefCell::new([AdvHandleState::None; ADV_SETS]));
725
726 #[cfg(feature = "security")]
727 let bond_storage: &'resources RefCell<VecView<BondInformation>> =
728 resources.bond_storage.write(RefCell::new(Vec::new()));
729
730 let host_state: &'resources mut MaybeUninit<ManuallyDrop<host::HostState<'resources, P>>> =
738 unsafe { core::mem::transmute(&mut resources.state) };
739
740 let host_state: &'resources mut ManuallyDrop<host::HostState<'resources, P>> =
741 host_state.write(ManuallyDrop::new(host::HostState::new(
742 connections,
743 channels,
744 advertise_handles,
745 #[cfg(feature = "security")]
746 bond_storage,
747 )));
748
749 StackBuilder {
750 host_state: Some(host_state),
751 controller: Some(controller),
752 }
753}
754
755pub struct Stack<'stack, C, P: PacketPool> {
757 host_state: &'stack mut ManuallyDrop<host::HostState<'stack, P>>,
758 controller: C,
759 runner_taken: Cell<bool>,
760}
761
762impl<'stack, C, P: PacketPool> Drop for Stack<'stack, C, P> {
763 fn drop(&mut self) {
764 unsafe { ManuallyDrop::drop(self.host_state) }
769 }
770}
771
772pub struct StackBuilder<'stack, C, P: PacketPool> {
776 pub(crate) host_state: Option<&'stack mut ManuallyDrop<host::HostState<'stack, P>>>,
777 controller: Option<C>,
778}
779
780impl<'stack, C, P: PacketPool> Drop for StackBuilder<'stack, C, P> {
781 fn drop(&mut self) {
782 if let Some(host_state) = &mut self.host_state {
783 unsafe { ManuallyDrop::drop(host_state) }
787 }
788 }
789}
790
791impl<'stack, C: Controller, P: PacketPool> StackBuilder<'stack, C, P> {
792 fn host_state(&mut self) -> &mut host::HostState<'stack, P> {
793 self.host_state.as_mut().unwrap()
794 }
795
796 pub fn register_l2cap_spsm(mut self, spsm: u16) -> Self {
798 self.host_state().channels.register_spsm(spsm);
799 self
800 }
801
802 pub fn set_random_address(mut self, address: Address) -> Self {
804 self.host_state().address.replace(address);
805 #[cfg(feature = "security")]
806 self.host_state()
807 .connections
808 .security_manager
809 .set_local_address(address);
810 self
811 }
812
813 #[cfg(feature = "security")]
827 pub fn enable_privacy(mut self, irk: IdentityResolvingKey) -> Self {
828 self.host_state().connections.security_manager.set_local_irk(irk);
829 self
830 }
831
832 #[cfg(feature = "security")]
840 pub fn set_rpa_timeout(mut self, timeout: Duration) -> Self {
841 self.host_state().rpa_timeout.set(timeout);
842 self
843 }
844
845 #[cfg(feature = "security")]
849 pub fn set_io_capabilities(mut self, io_capabilities: IoCapabilities) -> Self {
850 self.host_state()
851 .connections
852 .security_manager
853 .set_io_capabilities(io_capabilities);
854 self
855 }
856
857 #[cfg(feature = "security")]
863 pub fn set_passkey(mut self, passkey: Option<u32>) -> Self {
864 self.host_state().connections.security_manager.set_passkey(passkey);
865 self
866 }
867
868 #[cfg(feature = "legacy-pairing")]
875 pub fn set_secure_connections_only(mut self, enabled: bool) -> Self {
876 self.host_state()
877 .connections
878 .security_manager
879 .set_secure_connections_only(enabled);
880 self
881 }
882
883 pub fn build(mut self) -> Stack<'stack, C, P> {
890 Stack {
891 host_state: self.host_state.take().unwrap(),
892 controller: self.controller.take().unwrap(),
893 runner_taken: Cell::new(false),
894 }
895 }
896}
897
898impl<'stack, C, P: PacketPool> Stack<'stack, C, P> {
899 fn host(&self) -> BleHost<'_, C, P> {
900 BleHost::new(&self.controller, self.host_state)
901 }
902}
903
904impl<'stack, C: Controller, P: PacketPool> Stack<'stack, C, P> {
905 pub fn runner(&self) -> Runner<'_, C, P> {
909 assert!(
910 !self.runner_taken.replace(true),
911 "runner() can only be called once per Stack"
912 );
913 Runner::new(self.host())
914 }
915
916 #[cfg(feature = "central")]
921 pub fn central(&self) -> Central<'_, C, P> {
922 Central::new(self.host())
923 }
924
925 #[cfg(feature = "peripheral")]
930 pub fn peripheral(&self) -> Peripheral<'_, C, P> {
931 Peripheral::new(self.host())
932 }
933
934 #[cfg(feature = "iso")]
938 pub fn iso(&self) -> iso::Iso<'_, C, P> {
939 iso::Iso::new(self.host())
940 }
941
942 #[cfg(feature = "security")]
946 pub fn set_io_capabilities(&self, io_capabilities: IoCapabilities) {
947 self.host_state
948 .connections
949 .security_manager
950 .set_io_capabilities(io_capabilities);
951 }
952
953 #[cfg(feature = "security")]
959 pub fn set_passkey(&self, passkey: Option<u32>) {
960 self.host_state.connections.security_manager.set_passkey(passkey);
961 }
962
963 #[cfg(feature = "legacy-pairing")]
970 pub fn set_secure_connections_only(&self, enabled: bool) {
971 self.host_state
972 .connections
973 .security_manager
974 .set_secure_connections_only(enabled);
975 }
976
977 #[cfg(feature = "security")]
986 pub async fn set_rpa_timeout(&self, timeout: Duration) -> Result<(), BleHostError<C::Error>>
987 where
988 C: ControllerCmdSync<LeSetResolvablePrivateAddrTimeout>,
989 {
990 self.host().rpa_timeout().set(timeout);
991 if self.host().is_initialized() {
992 self.host()
993 .command(LeSetResolvablePrivateAddrTimeout::new(
994 bt_hci::param::Duration::from_secs(timeout.as_secs() as u32),
995 ))
996 .await?;
997 }
998 Ok(())
999 }
1000
1001 pub async fn command<T>(&self, cmd: T) -> Result<T::Return, BleHostError<C::Error>>
1003 where
1004 T: SyncCmd,
1005 C: ControllerCmdSync<T>,
1006 {
1007 self.host().command(cmd).await
1008 }
1009
1010 pub async fn async_command<T>(&self, cmd: T) -> Result<(), BleHostError<C::Error>>
1012 where
1013 T: AsyncCmd,
1014 C: ControllerCmdAsync<T>,
1015 {
1016 self.host().async_command(cmd).await
1017 }
1018
1019 pub async fn read_minimum_supported_connection_interval(
1021 &self,
1022 ) -> Result<<LeReadMinimumSupportedConnectionInterval as SyncCmd>::Return, BleHostError<C::Error>>
1023 where
1024 C: ControllerCmdSync<LeReadMinimumSupportedConnectionInterval>,
1025 {
1026 self.host()
1027 .command(LeReadMinimumSupportedConnectionInterval::new())
1028 .await
1029 }
1030
1031 pub fn metrics<F: FnOnce(&HostMetrics) -> R, R>(&self, f: F) -> R {
1033 self.host().metrics(f)
1034 }
1035
1036 pub fn log_status(&self, verbose: bool) {
1038 self.host().log_status(verbose);
1039 }
1040
1041 #[cfg(feature = "security")]
1042 pub fn get_local_oob_data(&self) -> OobData {
1047 self.host_state.connections.security_manager.get_local_oob_data()
1048 }
1049
1050 #[cfg(feature = "security")]
1051 pub fn get_local_address(&self) -> Option<Address> {
1053 self.host_state.connections.security_manager.get_local_address()
1054 }
1055
1056 #[cfg(feature = "security")]
1058 pub fn is_privacy_enabled(&self) -> bool {
1059 self.host().is_privacy_enabled()
1060 }
1061
1062 #[cfg(feature = "security")]
1063 pub fn add_bond_information(&self, bond_information: BondInformation) -> Result<(), Error> {
1070 let identity = bond_information.identity;
1071 let result = self
1072 .host()
1073 .connections()
1074 .security_manager
1075 .add_bond_information(bond_information);
1076 #[cfg(feature = "security")]
1077 if result.is_ok() {
1078 self.host()
1079 .resolving_list_state()
1080 .borrow_mut()
1081 .push(crate::host::ResolvingListUpdate::Add(identity));
1082 }
1083 result
1084 }
1085
1086 #[cfg(feature = "security")]
1087 pub fn remove_bond_information(&self, identity: Identity) -> Result<(), Error> {
1094 let result = self
1095 .host()
1096 .connections()
1097 .security_manager
1098 .remove_bond_information(identity);
1099 #[cfg(feature = "security")]
1100 if result.is_ok() {
1101 self.host()
1102 .resolving_list_state()
1103 .borrow_mut()
1104 .push(crate::host::ResolvingListUpdate::Remove(identity));
1105 }
1106 result
1107 }
1108
1109 #[cfg(feature = "security")]
1110 pub fn with_bond_information<R>(&self, f: impl FnOnce(&[BondInformation]) -> R) -> R {
1112 f(&self.host_state.connections.security_manager.get_bond_information())
1113 }
1114
1115 pub fn get_connection_by_peer_address(&self, peer_address: Address) -> Option<Connection<'_, P>> {
1117 self.host_state.connections.get_connection_by_peer_address(peer_address)
1118 }
1119
1120 pub fn get_connected_handle(&self, handle: ConnHandle) -> Option<Connection<'_, P>> {
1122 self.host_state.connections.get_connected_handle(handle)
1123 }
1124
1125 pub fn connections(&self) -> connection_manager::ConnectedIter<'_, P> {
1127 self.host_state.connections.connections()
1128 }
1129}
1130
1131pub(crate) fn bt_hci_duration<const US: u32>(d: Duration) -> bt_hci::param::Duration<US> {
1132 bt_hci::param::Duration::from_micros(d.as_micros())
1133}
1134
1135pub(crate) fn bt_hci_ext_duration<const US: u16>(d: Duration) -> bt_hci::param::ExtDuration<US> {
1136 bt_hci::param::ExtDuration::from_micros(d.as_micros())
1137}
1138
1139#[doc(hidden)]
1141pub mod __export {
1142 pub use embassy_sync;
1143}