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;
15#[cfg(feature = "security")]
16use heapless::Vec;
17use rand_core::{CryptoRng, RngCore};
18
19use crate::att::AttErrorCode;
20use crate::channel_manager::ChannelStorage;
21use crate::connection_manager::ConnectionStorage;
22#[cfg(feature = "security")]
23pub use crate::security_manager::{BondInformation, IdentityResolvingKey, LongTermKey};
24
25pub(crate) const BI_COUNT: usize = 10; mod fmt;
29
30#[cfg(not(any(feature = "central", feature = "peripheral")))]
31compile_error!("Must enable at least one of the `central` or `peripheral` features");
32
33pub mod att;
34#[cfg(feature = "central")]
35pub mod central;
36mod channel_manager;
37mod codec;
38mod command;
39pub mod config;
40mod connection_manager;
41mod cursor;
42#[cfg(feature = "default-packet-pool")]
43mod packet_pool;
44mod pdu;
45#[cfg(feature = "peripheral")]
46pub mod peripheral;
47#[cfg(feature = "security")]
48mod security_manager;
49pub mod types;
50
51#[cfg(feature = "central")]
52use central::*;
53#[cfg(feature = "peripheral")]
54use peripheral::*;
55
56pub mod advertise;
57pub mod connection;
58#[cfg(feature = "gatt")]
59pub mod gap;
60pub mod l2cap;
61#[cfg(feature = "scan")]
62pub mod scan;
63
64#[cfg(test)]
65pub(crate) mod mock_controller;
66
67pub(crate) mod host;
68use host::{AdvHandleState, BleHost, HostMetrics, Runner};
69
70pub mod prelude {
71 pub use bt_hci::controller::ExternalController;
73 pub use bt_hci::param::{AddrKind, BdAddr, LeConnRole as Role, PhyKind, PhyMask};
74 pub use bt_hci::transport::SerialTransport;
75 pub use bt_hci::uuid::*;
76 #[cfg(feature = "derive")]
77 pub use heapless::String as HeaplessString;
78 #[cfg(feature = "derive")]
79 pub use trouble_host_macros::*;
80
81 pub use super::att::AttErrorCode;
82 pub use super::{BleHostError, Controller, Error, Host, HostResources, Packet, PacketPool, Stack};
83 #[cfg(feature = "peripheral")]
84 pub use crate::advertise::*;
85 #[cfg(feature = "gatt")]
86 pub use crate::attribute::*;
87 #[cfg(feature = "gatt")]
88 pub use crate::attribute_server::*;
89 #[cfg(feature = "central")]
90 pub use crate::central::*;
91 pub use crate::connection::*;
92 #[cfg(feature = "gatt")]
93 pub use crate::gap::*;
94 #[cfg(feature = "gatt")]
95 pub use crate::gatt::*;
96 pub use crate::host::{ControlRunner, EventHandler, HostMetrics, Runner, RxRunner, TxRunner};
97 pub use crate::l2cap::*;
98 #[cfg(feature = "default-packet-pool")]
99 pub use crate::packet_pool::DefaultPacketPool;
100 pub use crate::pdu::Sdu;
101 #[cfg(feature = "peripheral")]
102 pub use crate::peripheral::*;
103 #[cfg(feature = "scan")]
104 pub use crate::scan::*;
105 #[cfg(feature = "gatt")]
106 pub use crate::types::gatt_traits::{AsGatt, FixedGattValue, FromGatt};
107 pub use crate::{Address, Identity};
108}
109
110#[cfg(feature = "gatt")]
111pub mod attribute;
112#[cfg(feature = "gatt")]
113mod attribute_server;
114#[cfg(feature = "gatt")]
115pub mod gatt;
116
117#[derive(Debug, Clone, Copy, PartialEq)]
129pub struct Address {
130 pub kind: AddrKind,
132 pub addr: BdAddr,
134}
135
136impl Address {
137 pub fn random(val: [u8; 6]) -> Self {
139 Self {
140 kind: AddrKind::RANDOM,
141 addr: BdAddr::new(val),
142 }
143 }
144
145 pub fn to_bytes(&self) -> [u8; 7] {
147 let mut bytes = [0; 7];
148 bytes[0] = self.kind.into_inner();
149 let mut addr_bytes = self.addr.into_inner();
150 addr_bytes.reverse();
151 bytes[1..].copy_from_slice(&addr_bytes);
152 bytes
153 }
154}
155
156impl core::fmt::Display for Address {
157 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
158 let a = self.addr.into_inner();
159 write!(
160 f,
161 "{:02X}:{:02X}:{:02X}:{:02X}:{:02X}:{:02X}",
162 a[5], a[4], a[3], a[2], a[1], a[0]
163 )
164 }
165}
166
167#[cfg(feature = "defmt")]
168impl defmt::Format for Address {
169 fn format(&self, fmt: defmt::Formatter) {
170 let a = self.addr.into_inner();
171 defmt::write!(
172 fmt,
173 "{:02X}:{:02X}:{:02X}:{:02X}:{:02X}:{:02X}",
174 a[5],
175 a[4],
176 a[3],
177 a[2],
178 a[1],
179 a[0]
180 )
181 }
182}
183
184#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
191pub struct Identity {
192 pub bd_addr: BdAddr,
194
195 #[cfg(feature = "security")]
197 pub irk: Option<IdentityResolvingKey>,
198}
199
200#[cfg(feature = "defmt")]
201impl defmt::Format for Identity {
202 fn format(&self, fmt: defmt::Formatter) {
203 defmt::write!(fmt, "BdAddr({:X}) ", self.bd_addr);
204 #[cfg(feature = "security")]
205 defmt::write!(fmt, "Irk({:X})", self.irk);
206 }
207}
208
209impl Identity {
210 pub fn match_address(&self, address: &BdAddr) -> bool {
212 if self.bd_addr == *address {
213 return true;
214 }
215 #[cfg(feature = "security")]
216 if let Some(irk) = self.irk {
217 return irk.resolve_address(address);
218 }
219 false
220 }
221
222 pub fn match_identity(&self, identity: &Identity) -> bool {
224 if self.match_address(&identity.bd_addr) {
225 return true;
226 }
227 #[cfg(feature = "security")]
228 if let Some(irk) = identity.irk {
229 if let Some(current_irk) = self.irk {
230 return irk == current_irk;
231 } else {
232 return irk.resolve_address(&self.bd_addr);
233 }
234 }
235 false
236 }
237}
238
239#[derive(Debug)]
241#[cfg_attr(feature = "defmt", derive(defmt::Format))]
242pub enum BleHostError<E> {
243 Controller(E),
245 BleHost(Error),
247}
248
249pub const MAX_INVALID_DATA_LEN: usize = 16;
251
252#[derive(Debug, PartialEq)]
254#[cfg_attr(feature = "defmt", derive(defmt::Format))]
255pub enum Error {
256 Hci(bt_hci::param::Error),
258 HciDecode(FromHciBytesError),
260 Att(AttErrorCode),
262 #[cfg(feature = "security")]
263 Security(crate::security_manager::Reason),
265 InsufficientSpace,
267 InvalidValue,
269
270 UnexpectedDataLength {
276 expected: usize,
278 actual: usize,
280 },
281
282 CannotConstructGattValue([u8; MAX_INVALID_DATA_LEN]),
284
285 ConfigFilterAcceptListIsEmpty,
287
288 UnexpectedGattResponse,
290
291 MalformedCharacteristicDeclaration {
293 expected: usize,
295 actual: usize,
297 },
298
299 InvalidCharacteristicDeclarationData,
301
302 InvalidCccdHandleLength(usize),
304
305 FailedToFinalize {
307 expected: usize,
309 actual: usize,
311 },
312
313 CodecError(codec::Error),
315
316 ExtendedAdvertisingNotSupported,
318
319 InvalidUuidLength(usize),
321
322 Advertisement(AdvertisementDataError),
324 InvalidChannelId,
326 NoChannelAvailable,
328 NotFound,
330 InvalidState,
332 OutOfMemory,
334 NotSupported,
336 ChannelClosed,
338 Timeout,
340 Busy,
342 NoPermits,
344 Disconnected,
346 ConnectionLimitReached,
348 GattSubscriberLimitReached,
352 Other,
354}
355
356impl<E> From<Error> for BleHostError<E> {
357 fn from(value: Error) -> Self {
358 Self::BleHost(value)
359 }
360}
361
362impl From<FromHciBytesError> for Error {
363 fn from(error: FromHciBytesError) -> Self {
364 Self::HciDecode(error)
365 }
366}
367
368impl From<AttErrorCode> for Error {
369 fn from(error: AttErrorCode) -> Self {
370 Self::Att(error)
371 }
372}
373
374impl<E> From<bt_hci::cmd::Error<E>> for BleHostError<E> {
375 fn from(error: bt_hci::cmd::Error<E>) -> Self {
376 match error {
377 bt_hci::cmd::Error::Hci(p) => Self::BleHost(Error::Hci(p)),
378 bt_hci::cmd::Error::Io(p) => Self::Controller(p),
379 }
380 }
381}
382
383impl<E> From<bt_hci::param::Error> for BleHostError<E> {
384 fn from(error: bt_hci::param::Error) -> Self {
385 Self::BleHost(Error::Hci(error))
386 }
387}
388
389impl From<codec::Error> for Error {
390 fn from(error: codec::Error) -> Self {
391 match error {
392 codec::Error::InsufficientSpace => Error::InsufficientSpace,
393 codec::Error::InvalidValue => Error::CodecError(error),
394 }
395 }
396}
397
398impl<E> From<codec::Error> for BleHostError<E> {
399 fn from(error: codec::Error) -> Self {
400 match error {
401 codec::Error::InsufficientSpace => BleHostError::BleHost(Error::InsufficientSpace),
402 codec::Error::InvalidValue => BleHostError::BleHost(Error::InvalidValue),
403 }
404 }
405}
406
407use bt_hci::cmd::controller_baseband::*;
408use bt_hci::cmd::info::*;
409use bt_hci::cmd::le::*;
410use bt_hci::cmd::link_control::*;
411use bt_hci::controller::{ControllerCmdAsync, ControllerCmdSync};
412
413pub trait Controller:
417 bt_hci::controller::Controller
418 + embedded_io::ErrorType
419 + ControllerCmdSync<LeReadBufferSize>
420 + ControllerCmdSync<Disconnect>
421 + ControllerCmdSync<SetEventMask>
422 + ControllerCmdSync<SetEventMaskPage2>
423 + ControllerCmdSync<LeSetEventMask>
424 + ControllerCmdSync<LeSetRandomAddr>
425 + ControllerCmdSync<HostBufferSize>
426 + ControllerCmdAsync<LeConnUpdate>
427 + ControllerCmdSync<LeReadFilterAcceptListSize>
428 + ControllerCmdSync<SetControllerToHostFlowControl>
429 + ControllerCmdSync<Reset>
430 + ControllerCmdSync<ReadRssi>
431 + ControllerCmdSync<LeCreateConnCancel>
432 + ControllerCmdSync<LeSetScanEnable>
433 + ControllerCmdSync<LeSetExtScanEnable>
434 + ControllerCmdAsync<LeCreateConn>
435 + ControllerCmdSync<LeClearFilterAcceptList>
436 + ControllerCmdSync<LeAddDeviceToFilterAcceptList>
437 + for<'t> ControllerCmdSync<LeSetAdvEnable>
438 + for<'t> ControllerCmdSync<LeSetExtAdvEnable<'t>>
439 + for<'t> ControllerCmdSync<HostNumberOfCompletedPackets<'t>>
440 + ControllerCmdSync<LeReadBufferSize>
441 + for<'t> ControllerCmdSync<LeSetAdvData>
442 + ControllerCmdSync<LeSetAdvParams>
443 + for<'t> ControllerCmdSync<LeSetAdvEnable>
444 + for<'t> ControllerCmdSync<LeSetScanResponseData>
445 + ControllerCmdSync<LeLongTermKeyRequestReply>
446 + ControllerCmdAsync<LeEnableEncryption>
447 + ControllerCmdSync<ReadBdAddr>
448{
449}
450
451impl<
452 C: bt_hci::controller::Controller
453 + embedded_io::ErrorType
454 + ControllerCmdSync<LeReadBufferSize>
455 + ControllerCmdSync<Disconnect>
456 + ControllerCmdSync<SetEventMask>
457 + ControllerCmdSync<SetEventMaskPage2>
458 + ControllerCmdSync<LeSetEventMask>
459 + ControllerCmdSync<LeSetRandomAddr>
460 + ControllerCmdSync<HostBufferSize>
461 + ControllerCmdAsync<LeConnUpdate>
462 + ControllerCmdSync<LeReadFilterAcceptListSize>
463 + ControllerCmdSync<LeClearFilterAcceptList>
464 + ControllerCmdSync<LeAddDeviceToFilterAcceptList>
465 + ControllerCmdSync<SetControllerToHostFlowControl>
466 + ControllerCmdSync<Reset>
467 + ControllerCmdSync<ReadRssi>
468 + ControllerCmdSync<LeSetScanEnable>
469 + ControllerCmdSync<LeSetExtScanEnable>
470 + ControllerCmdSync<LeCreateConnCancel>
471 + ControllerCmdAsync<LeCreateConn>
472 + for<'t> ControllerCmdSync<LeSetAdvEnable>
473 + for<'t> ControllerCmdSync<LeSetExtAdvEnable<'t>>
474 + for<'t> ControllerCmdSync<HostNumberOfCompletedPackets<'t>>
475 + ControllerCmdSync<LeReadBufferSize>
476 + for<'t> ControllerCmdSync<LeSetAdvData>
477 + ControllerCmdSync<LeSetAdvParams>
478 + for<'t> ControllerCmdSync<LeSetAdvEnable>
479 + for<'t> ControllerCmdSync<LeSetScanResponseData>
480 + ControllerCmdSync<LeLongTermKeyRequestReply>
481 + ControllerCmdAsync<LeEnableEncryption>
482 + ControllerCmdSync<ReadBdAddr>,
483 > Controller for C
484{
485}
486
487pub trait Packet: Sized + AsRef<[u8]> + AsMut<[u8]> {}
490
491pub trait PacketPool: 'static {
495 type Packet: Packet;
497
498 const MTU: usize;
500
501 fn allocate() -> Option<Self::Packet>;
509
510 fn capacity() -> usize;
512}
513
514pub struct HostResources<P: PacketPool, const CONNS: usize, const CHANNELS: usize, const ADV_SETS: usize = 1> {
519 connections: MaybeUninit<[ConnectionStorage<P::Packet>; CONNS]>,
520 channels: MaybeUninit<[ChannelStorage<P::Packet>; CHANNELS]>,
521 advertise_handles: MaybeUninit<[AdvHandleState; ADV_SETS]>,
522}
523
524impl<P: PacketPool, const CONNS: usize, const CHANNELS: usize, const ADV_SETS: usize> Default
525 for HostResources<P, CONNS, CHANNELS, ADV_SETS>
526{
527 fn default() -> Self {
528 Self::new()
529 }
530}
531
532impl<P: PacketPool, const CONNS: usize, const CHANNELS: usize, const ADV_SETS: usize>
533 HostResources<P, CONNS, CHANNELS, ADV_SETS>
534{
535 pub const fn new() -> Self {
537 Self {
538 connections: MaybeUninit::uninit(),
539 channels: MaybeUninit::uninit(),
540 advertise_handles: MaybeUninit::uninit(),
541 }
542 }
543}
544
545pub fn new<
548 'resources,
549 C: Controller,
550 P: PacketPool,
551 const CONNS: usize,
552 const CHANNELS: usize,
553 const ADV_SETS: usize,
554>(
555 controller: C,
556 resources: &'resources mut HostResources<P, CONNS, CHANNELS, ADV_SETS>,
557) -> Stack<'resources, C, P> {
558 unsafe fn transmute_slice<T>(x: &mut [T]) -> &'static mut [T] {
559 unsafe { core::mem::transmute(x) }
560 }
561
562 let connections: &mut [ConnectionStorage<P::Packet>] =
569 &mut *resources.connections.write([const { ConnectionStorage::new() }; CONNS]);
570 let connections: &'resources mut [ConnectionStorage<P::Packet>] = unsafe { transmute_slice(connections) };
571
572 let channels = &mut *resources.channels.write([const { ChannelStorage::new() }; CHANNELS]);
573 let channels: &'static mut [ChannelStorage<P::Packet>] = unsafe { transmute_slice(channels) };
574
575 let advertise_handles = &mut *resources.advertise_handles.write([AdvHandleState::None; ADV_SETS]);
576 let advertise_handles: &'static mut [AdvHandleState] = unsafe { transmute_slice(advertise_handles) };
577 let host: BleHost<'_, C, P> = BleHost::new(controller, connections, channels, advertise_handles);
578
579 Stack { host }
580}
581
582pub struct Stack<'stack, C, P: PacketPool> {
584 host: BleHost<'stack, C, P>,
585}
586
587#[non_exhaustive]
589pub struct Host<'stack, C, P: PacketPool> {
590 #[cfg(feature = "central")]
592 pub central: Central<'stack, C, P>,
593 #[cfg(feature = "peripheral")]
595 pub peripheral: Peripheral<'stack, C, P>,
596 pub runner: Runner<'stack, C, P>,
598}
599
600impl<'stack, C: Controller, P: PacketPool> Stack<'stack, C, P> {
601 pub fn set_random_address(mut self, address: Address) -> Self {
603 self.host.address.replace(address);
604 #[cfg(feature = "security")]
605 self.host.connections.security_manager.set_local_address(address);
606 self
607 }
608 pub fn set_random_generator_seed<RNG: RngCore + CryptoRng>(self, _random_generator: &mut RNG) -> Self {
610 #[cfg(feature = "security")]
611 {
612 let mut random_seed = [0u8; 32];
613 _random_generator.fill_bytes(&mut random_seed);
614 self.host
615 .connections
616 .security_manager
617 .set_random_generator_seed(random_seed);
618 }
619 self
620 }
621
622 pub fn build(&'stack self) -> Host<'stack, C, P> {
624 #[cfg(all(feature = "security", not(feature = "dev-disable-csprng-seed-requirement")))]
625 {
626 if !self.host.connections.security_manager.get_random_generator_seeded() {
627 panic!(
628 "The security manager random number generator has not been seeded from a cryptographically secure random number generator"
629 )
630 }
631 }
632 Host {
633 #[cfg(feature = "central")]
634 central: Central::new(self),
635 #[cfg(feature = "peripheral")]
636 peripheral: Peripheral::new(self),
637 runner: Runner::new(self),
638 }
639 }
640
641 pub async fn command<T>(&self, cmd: T) -> Result<T::Return, BleHostError<C::Error>>
643 where
644 T: SyncCmd,
645 C: ControllerCmdSync<T>,
646 {
647 self.host.command(cmd).await
648 }
649
650 pub async fn async_command<T>(&self, cmd: T) -> Result<(), BleHostError<C::Error>>
652 where
653 T: AsyncCmd,
654 C: ControllerCmdAsync<T>,
655 {
656 self.host.async_command(cmd).await
657 }
658
659 pub fn metrics<F: FnOnce(&HostMetrics) -> R, R>(&self, f: F) -> R {
661 self.host.metrics(f)
662 }
663
664 pub fn log_status(&self, verbose: bool) {
666 self.host.log_status(verbose);
667 }
668
669 #[cfg(feature = "security")]
670 pub fn add_bond_information(&self, bond_information: BondInformation) -> Result<(), Error> {
672 self.host
673 .connections
674 .security_manager
675 .add_bond_information(bond_information)
676 }
677
678 #[cfg(feature = "security")]
679 pub fn remove_bond_information(&self, identity: Identity) -> Result<(), Error> {
681 self.host.connections.security_manager.remove_bond_information(identity)
682 }
683
684 #[cfg(feature = "security")]
685 pub fn get_bond_information(&self) -> Vec<BondInformation, BI_COUNT> {
687 self.host.connections.security_manager.get_bond_information()
688 }
689}