1use core::iter::FusedIterator;
2
3use super::{param, param_slice, BdAddr, ConnHandle, Duration, RemainingBytes};
4use crate::{ByteAlignedValue, FixedSizeValue, FromHciBytes, FromHciBytesError, WriteHci};
5
6param!(struct AddrKind(u8));
7
8#[allow(missing_docs)]
9impl AddrKind {
10 pub const PUBLIC: AddrKind = AddrKind(0);
11 pub const RANDOM: AddrKind = AddrKind(1);
12 pub const RESOLVABLE_PRIVATE_OR_PUBLIC: AddrKind = AddrKind(2);
13 pub const RESOLVABLE_PRIVATE_OR_RANDOM: AddrKind = AddrKind(3);
14 pub const ANONYMOUS_ADV: AddrKind = AddrKind(0xff);
15
16 pub const fn new(v: u8) -> Self {
18 Self(v)
19 }
20
21 pub fn as_raw(&self) -> u8 {
23 self.0
24 }
25}
26
27unsafe impl ByteAlignedValue for AddrKind {}
28
29impl<'de> crate::FromHciBytes<'de> for &'de AddrKind {
30 #[inline(always)]
31 fn from_hci_bytes(data: &'de [u8]) -> Result<(Self, &'de [u8]), crate::FromHciBytesError> {
32 <AddrKind as crate::ByteAlignedValue>::ref_from_hci_bytes(data)
33 }
34}
35
36param! {
37 bitfield AdvChannelMap[1] {
38 (0, is_channel_37_enabled, enable_channel_37);
39 (1, is_channel_38_enabled, enable_channel_38);
40 (2, is_channel_39_enabled, enable_channel_39);
41 }
42}
43
44#[allow(missing_docs)]
45impl AdvChannelMap {
46 pub const ALL: AdvChannelMap = AdvChannelMap(0x07);
47 pub const CHANNEL_37: AdvChannelMap = AdvChannelMap(0x01);
48 pub const CHANNEL_38: AdvChannelMap = AdvChannelMap(0x02);
49 pub const CHANNEL_39: AdvChannelMap = AdvChannelMap(0x04);
50}
51
52param!(struct ChannelMap([u8; 5]));
53
54impl ChannelMap {
55 pub fn new() -> Self {
57 Self([0xff, 0xff, 0xff, 0xff, 0x1f])
58 }
59
60 pub fn is_channel_bad(&self, channel: u8) -> bool {
62 let byte = usize::from(channel / 8);
63 let bit = channel % 8;
64 (self.0[byte] & (1 << bit)) == 0
65 }
66
67 pub fn set_channel_bad(&mut self, channel: u8, bad: bool) {
69 let byte = usize::from(channel / 8);
70 let bit = channel % 8;
71 self.0[byte] = (self.0[byte] & !(1 << bit)) | (u8::from(!bad) << bit);
72 }
73}
74
75unsafe impl ByteAlignedValue for ChannelMap {}
76
77impl<'de> crate::FromHciBytes<'de> for &'de ChannelMap {
78 #[inline(always)]
79 fn from_hci_bytes(data: &'de [u8]) -> Result<(Self, &'de [u8]), crate::FromHciBytesError> {
80 <ChannelMap as crate::ByteAlignedValue>::ref_from_hci_bytes(data)
81 }
82}
83
84param! {
85 #[derive(Default)]
86 enum AdvKind {
87 #[default]
88 AdvInd = 0,
89 AdvDirectIndHigh = 1,
90 AdvScanInd = 2,
91 AdvNonconnInd = 3,
92 AdvDirectIndLow = 4,
93 }
94}
95
96param! {
97 #[derive(Default)]
98 enum AdvFilterPolicy {
99 #[default]
100 Unfiltered = 0,
101 FilterScan = 1,
102 FilterConn = 2,
103 FilterConnAndScan = 3,
104 }
105}
106
107param! {
108 #[derive(Default)]
109 enum LeScanKind {
110 #[default]
111 Passive = 0,
112 Active = 1,
113 }
114}
115
116param! {
117 #[derive(Default)]
118 enum ScanningFilterPolicy {
119 #[default]
120 BasicUnfiltered = 0,
121 BasicFiltered = 1,
122 ExtUnfiltered = 2,
123 ExtFiltered = 3,
124 }
125}
126
127param! {
128 #[derive(Default)]
129 enum PhyKind {
130 #[default]
131 Le1M = 1,
132 Le2M = 2,
133 LeCoded = 3,
134 LeCodedS2 = 4,
135 }
136}
137
138param! {
139 bitfield SpacingTypes[2] {
140 (0, has_t_ifs_acl_cp, set_t_ifs_acl_cp);
141 (1, has_t_ifs_acl_pc, set_t_ifs_acl_pc);
142 (2, has_t_mces, set_t_mces);
143 (3, has_t_ifs_cis, set_t_ifs_cis);
144 (4, has_t_mss_cis, set_t_mss_cis);
145 }
146}
147
148param! {
149 enum FrameSpaceInitiator {
150 LocalHostInitiated = 0x00,
151 LocalControllerInitiated = 0x01,
152 PeerInitiated = 0x02,
153 }
154}
155
156param! {
157 bitfield AllPhys[1] {
158 (0, has_no_tx_phy_preference, set_has_no_tx_phy_preference);
159 (1, has_no_rx_phy_preference, set_has_no_rx_phy_preference);
160 }
161}
162
163param! {
164 bitfield PhyMask[1] {
165 (0, has_le_1m_phy, set_le_1m_phy);
166 (1, has_le_2m_phy, set_le_2m_phy);
167 (2, has_le_coded_phy, set_le_coded_phy);
168 }
169}
170
171#[derive(Default)]
173#[repr(u16, align(1))]
174#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
175#[cfg_attr(feature = "defmt", derive(defmt::Format))]
176#[allow(missing_docs)]
177pub enum PhyOptions {
178 #[default]
179 NoPreferredCoding = 0,
180 S2CodingPreferred = 1,
181 S8CodingPreferred = 2,
182}
183
184unsafe impl FixedSizeValue for PhyOptions {
185 #[inline(always)]
186 fn is_valid(data: &[u8]) -> bool {
187 data[0] == 0 || data[0] == 1 || data[0] == 2
188 }
189}
190
191unsafe impl ByteAlignedValue for PhyOptions {}
192
193impl<'de> FromHciBytes<'de> for &'de PhyOptions {
194 #[inline(always)]
195 fn from_hci_bytes(data: &'de [u8]) -> Result<(Self, &'de [u8]), FromHciBytesError> {
196 <PhyOptions as ByteAlignedValue>::ref_from_hci_bytes(data)
197 }
198}
199
200#[derive(Default)]
202#[repr(u16, align(1))]
203#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
204#[cfg_attr(feature = "defmt", derive(defmt::Format))]
205#[allow(missing_docs)]
206pub enum AdvPhyOptions {
207 #[default]
208 NoPreferredCoding = 0,
209 S2CodingPreferred = 1,
210 S8CodingPreferred = 2,
211 S2CodingRequired = 3,
212 S8CodingRequired = 4,
213}
214
215unsafe impl FixedSizeValue for AdvPhyOptions {
216 #[inline(always)]
217 fn is_valid(data: &[u8]) -> bool {
218 data[0] == 0 || data[0] == 1 || data[0] == 2 || data[0] == 3 || data[0] == 4
219 }
220}
221
222unsafe impl ByteAlignedValue for AdvPhyOptions {}
223
224impl<'de> FromHciBytes<'de> for &'de AdvPhyOptions {
225 #[inline(always)]
226 fn from_hci_bytes(data: &'de [u8]) -> Result<(Self, &'de [u8]), FromHciBytesError> {
227 <AdvPhyOptions as ByteAlignedValue>::ref_from_hci_bytes(data)
228 }
229}
230
231param! {
232 struct ScanningPhy {
233 active_scan: bool,
234 scan_interval: Duration<625>,
235 scan_window: Duration<625>,
236 }
237}
238
239param! {
240 struct InitiatingPhy {
241 scan_interval: Duration<625>,
242 scan_window: Duration<625>,
243 conn_interval_min: Duration<1_250>,
244 conn_interval_max: Duration<1_250>,
245 max_latency: u16,
246 supervision_timeout: Duration<10_000>,
247 min_ce_len: Duration<625>,
248 max_ce_len: Duration<625>,
249 }
250}
251
252param! {
253 struct ConnIntervalGroup {
254 min: Duration<125>,
255 max: Duration<125>,
256 stride: Duration<125>,
257 }
258}
259
260#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
262#[cfg_attr(feature = "defmt", derive(defmt::Format))]
263pub struct PhyParams<T> {
264 pub le_1m_phy: Option<T>,
266 pub le_2m_phy: Option<T>,
268 pub le_coded_phy: Option<T>,
270}
271
272impl<T> PhyParams<T> {
273 pub fn scanning_phys(&self) -> PhyMask {
275 PhyMask::new()
276 .set_le_1m_phy(self.le_1m_phy.is_some())
277 .set_le_2m_phy(self.le_2m_phy.is_some())
278 .set_le_coded_phy(self.le_coded_phy.is_some())
279 }
280}
281
282impl<T: WriteHci> WriteHci for PhyParams<T> {
283 #[inline(always)]
284 fn size(&self) -> usize {
285 1 + self.le_1m_phy.size() + self.le_2m_phy.size() + self.le_coded_phy.size()
286 }
287
288 #[inline(always)]
289 fn write_hci<W: embedded_io::Write>(&self, mut writer: W) -> Result<(), W::Error> {
290 self.scanning_phys().write_hci(&mut writer)?;
291 self.le_1m_phy.write_hci(&mut writer)?;
292 self.le_2m_phy.write_hci(&mut writer)?;
293 self.le_coded_phy.write_hci(&mut writer)?;
294 Ok(())
295 }
296
297 #[inline(always)]
298 async fn write_hci_async<W: ::embedded_io_async::Write>(&self, mut writer: W) -> Result<(), W::Error> {
299 self.scanning_phys().write_hci_async(&mut writer).await?;
300 self.le_1m_phy.write_hci_async(&mut writer).await?;
301 self.le_2m_phy.write_hci_async(&mut writer).await?;
302 self.le_coded_phy.write_hci_async(&mut writer).await?;
303 Ok(())
304 }
305}
306
307param!(struct AdvHandle(u8));
308
309impl AdvHandle {
310 pub const fn new(v: u8) -> Self {
312 Self(v)
313 }
314
315 pub fn as_raw(&self) -> u8 {
317 self.0
318 }
319}
320
321unsafe impl ByteAlignedValue for AdvHandle {}
322
323impl<'de> crate::FromHciBytes<'de> for &'de AdvHandle {
324 #[inline(always)]
325 fn from_hci_bytes(data: &'de [u8]) -> Result<(Self, &'de [u8]), crate::FromHciBytesError> {
326 <AdvHandle as crate::ByteAlignedValue>::ref_from_hci_bytes(data)
327 }
328}
329
330param! {
331 bitfield AdvEventProps[2] {
332 (0, connectable_adv, set_connectable_adv);
333 (1, scannable_adv, set_scannable_adv);
334 (2, directed_adv, set_directed_adv);
335 (3, high_duty_cycle_directed_connectable_adv, set_high_duty_cycle_directed_connectable_adv);
336 (4, legacy_adv, set_legacy_adv);
337 (5, anonymous_adv, set_anonymous_adv);
338 (6, include_tx_power, set_include_tx_power);
339 }
340}
341
342param! {
343 #[derive(Default)]
344 enum Operation {
345 #[default]
346 IntermediateFragment = 0,
347 FirstFragment = 1,
348 LastFragment = 2,
349 Complete = 3,
350 Unchanged = 4,
351 }
352}
353
354param! {
355 struct AdvSet {
356 adv_handle: AdvHandle,
357 duration: Duration<10_000>,
358 max_ext_adv_events: u8,
359 }
360}
361
362param_slice!(&'a [AdvSet]);
363
364param! {
365 bitfield PeriodicAdvProps[2] {
366 (6, is_tx_power_included, include_tx_power);
367 }
368}
369
370param! {
371 #[derive(Default)]
372 enum FilterDuplicates {
373 #[default]
374 Disabled = 0,
375 Enabled = 1,
376 EnabledPerScanPeriod = 2,
377 }
378}
379
380param! {
381 bitfield LePeriodicAdvCreateSyncOptions[1] {
382 (0, is_using_periodic_adv_list, use_periodic_adv_list);
383 (1, is_reporting_initially_disabled, disable_initial_reporting);
384 (2, is_duplicate_filtering_enabled, enable_duplicate_filtering);
385 }
386}
387
388param! {
389 bitfield CteMask[1] {
390 (0, is_aoa_cte, set_aoa_cte);
391 (1, is_aod_1us_cte, set_aod_1us_cte);
392 (2, is_aod_2us_cte, set_aod_2us_cte);
393 (3, is_type_3_cte, set_type_3_cte);
394 (4, is_non_cte, set_non_cte);
395 }
396}
397
398param!(struct SyncHandle(u16));
399
400param!(struct BigHandle(u16));
401
402param! {
403 #[derive(Default)]
404 enum PrivacyMode {
405 #[default]
406 Network = 0,
407 Device = 1,
408 }
409}
410
411param! {
412 #[derive(Default)]
413 enum CteKind {
414 #[default]
415 AoA = 0,
416 AoD1Us = 1,
417 AoD2Us = 2,
418 NoCte = 0xff,
419 }
420}
421
422param! {
423 bitfield SwitchingSamplingRates[1] {
424 (0, is_1us_aod_tx, set_1us_aod_tx);
425 (1, is_1us_aod_rx, set_1us_aod_rx);
426 (2, is_1us_aoa_rx, set_1us_aoa_rx);
427 }
428}
429
430param! {
431 bitfield LePeriodicAdvReceiveEnable[1] {
432 (0, is_reporting, set_reporting);
433 (1, is_duplicate_filtering, set_duplicate_filtering);
434 }
435}
436
437param! {
438 #[derive(Default)]
439 enum LePeriodicAdvSyncTransferMode {
440 #[default]
441 NoSync = 0,
442 SyncRx = 1,
443 SyncRxReport = 2,
444 SyncRxReportFilterDuplicates = 3,
445 }
446}
447
448param! {
449 bitfield LeDataRelatedAddrChangeReasons[1] {
450 (0, change_on_adv_data_change, set_change_addr_on_adv_data_changes);
451 (1, change_on_scan_response_data_change, set_change_addr_on_scan_response_data_changes);
452 }
453}
454
455param! {
456 #[derive(Default)]
457 enum LeConnRole {
458 #[default]
459 Central = 0,
460 Peripheral = 1,
461 }
462}
463
464param! {
465 #[derive(Default)]
466 enum ClockAccuracy {
467 #[default]
468 Ppm500 = 0,
469 Ppm250 = 1,
470 Ppm150 = 2,
471 Ppm100 = 3,
472 Ppm75 = 4,
473 Ppm50 = 5,
474 Ppm30 = 6,
475 Ppm20 = 7,
476 }
477}
478
479param! {
480 struct LeAdvertisingReportParam<'a> {
481 event_type: u8,
482 addr_kind: AddrKind,
483 addr: BdAddr,
484 data: &'a [u8],
485 rssi: i8,
486 }
487}
488
489param_slice! {
490 [LeDirectedAdvertisingReportParam; 16] {
491 event_type[0]: u8,
492 addr_kind[1]: AddrKind,
493 addr[2]: BdAddr,
494 direct_addr_kind[8]: AddrKind,
495 direct_addr[9]: BdAddr,
496 rssi[15]: i8,
497 }
498}
499
500param_slice! {
501 [LeIQSample; 2] {
502 i_sample[0]: i8,
503 q_sample[1]: i8,
504 }
505}
506
507param_slice! {
508 [BisConnHandle; 2] {
509 handle[0]: ConnHandle,
510 }
511}
512
513param! {
514 #[derive(Default)]
515 enum DataStatus {
516 #[default]
517 Complete = 0,
518 Incomplete = 1,
519 Failed = 0xff,
520 }
521}
522
523param! {
524 #[derive(Default)]
525 enum PacketStatus {
526 #[default]
527 CrcCorrect = 0,
528 CrcIncorrectUsedLength = 1,
529 CrcIncorrectUsedOther = 2,
530 InsufficientResources = 0xff,
531 }
532}
533
534param! {
535 #[derive(Default)]
536 enum TxStatus {
537 #[default]
538 Transmitted = 0,
539 NotTransmitted = 1,
540 }
541}
542
543param! {
544 #[derive(Default)]
545 enum ZoneEntered {
546 #[default]
547 Low = 0,
548 Middle = 1,
549 High = 2,
550 }
551}
552
553param! {
554 #[derive(Default)]
555 enum LeTxPowerReportingReason {
556 #[default]
557 LocalTxPowerChanged = 0,
558 RemoteTxPowerChanged = 1,
559 LeReadRemoteTxPowerLevelCompleted = 2,
560 }
561}
562
563param! {
564 #[derive(Default)]
565 enum LeAdvEventKind {
566 #[default]
567 AdvInd = 0,
568 AdvDirectInd = 1,
569 AdvScanInd = 2,
570 AdvNonconnInd = 3,
571 ScanRsp = 4,
572 }
573}
574
575param! {
576 bitfield LeExtAdvEventKind[2] {
577 (0, connectable, set_connectable);
578 (1, scannable, set_scannable);
579 (2, directed, set_directed);
580 (3, scan_response, set_scan_response);
581 (4, legacy, set_legacy);
582 }
583}
584
585#[allow(missing_docs)]
587pub enum LeExtAdvDataStatus {
588 Complete,
589 IncompleteMoreExpected,
590 IncompleteTruncated,
591 Reserved,
592}
593
594impl LeExtAdvEventKind {
595 pub fn data_status(&self) -> LeExtAdvDataStatus {
597 let data_status = (self.0[0] >> 5) & 0x03;
598 match data_status {
599 0 => LeExtAdvDataStatus::Complete,
600 1 => LeExtAdvDataStatus::IncompleteMoreExpected,
601 2 => LeExtAdvDataStatus::IncompleteTruncated,
602 _ => LeExtAdvDataStatus::Reserved,
603 }
604 }
605
606 pub fn set_data_status(mut self, status: LeExtAdvDataStatus) -> Self {
608 let value = match status {
609 LeExtAdvDataStatus::Complete => 0,
610 LeExtAdvDataStatus::IncompleteMoreExpected => 1,
611 LeExtAdvDataStatus::IncompleteTruncated => 2,
612 LeExtAdvDataStatus::Reserved => 3,
613 };
614 self.0[0] &= !(0x03 << 5);
615 self.0[0] |= value << 5;
616 self
617 }
618}
619
620param! {
621 struct LeAdvReport<'a> {
622 event_kind: LeAdvEventKind,
623 addr_kind: AddrKind,
624 addr: BdAddr,
625 data: &'a [u8],
626 rssi: i8,
627 }
628}
629
630param! {
631 struct LeAdvReports<'a> {
632 num_reports: u8,
633 bytes: RemainingBytes<'a>,
634 }
635}
636
637impl LeAdvReports<'_> {
638 pub fn is_empty(&self) -> bool {
640 self.num_reports == 0
641 }
642
643 pub fn len(&self) -> usize {
645 usize::from(self.num_reports)
646 }
647
648 pub fn iter(&self) -> LeAdvReportsIter<'_> {
650 LeAdvReportsIter {
651 len: self.len(),
652 bytes: &self.bytes,
653 }
654 }
655}
656
657pub struct LeAdvReportsIter<'a> {
659 len: usize,
660 bytes: &'a [u8],
661}
662
663impl<'a> Iterator for LeAdvReportsIter<'a> {
664 type Item = Result<LeAdvReport<'a>, FromHciBytesError>;
665
666 fn next(&mut self) -> Option<Self::Item> {
667 if self.len == 0 {
668 None
669 } else {
670 match LeAdvReport::from_hci_bytes(self.bytes) {
671 Ok((report, rest)) => {
672 self.bytes = rest;
673 self.len -= 1;
674 Some(Ok(report))
675 }
676 Err(err) => {
677 self.len = 0;
678 Some(Err(err))
679 }
680 }
681 }
682 }
683
684 fn size_hint(&self) -> (usize, Option<usize>) {
685 (self.len, Some(self.len))
686 }
687}
688
689impl ExactSizeIterator for LeAdvReportsIter<'_> {
690 fn len(&self) -> usize {
691 self.len
692 }
693}
694
695impl FusedIterator for LeAdvReportsIter<'_> {}
696
697#[derive(Default, Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
698#[cfg_attr(feature = "defmt", derive(defmt::Format))]
699#[allow(missing_docs)]
700pub struct LeExtAdvReport<'a> {
701 pub event_kind: LeExtAdvEventKind,
702 pub addr_kind: AddrKind,
703 pub addr: BdAddr,
704 pub primary_adv_phy: PhyKind,
705 pub secondary_adv_phy: Option<PhyKind>,
706 pub adv_sid: u8,
707 pub tx_power: i8,
708 pub rssi: i8,
709 pub adv_interval: Duration<1_250>,
710 pub direct_addr_kind: AddrKind,
711 pub direct_addr: BdAddr,
712 pub data: &'a [u8],
713}
714
715impl WriteHci for LeExtAdvReport<'_> {
716 #[inline(always)]
717 fn size(&self) -> usize {
718 WriteHci::size(&self.event_kind)
719 + WriteHci::size(&self.addr_kind)
720 + WriteHci::size(&self.addr)
721 + WriteHci::size(&self.primary_adv_phy)
722 + 1 + WriteHci::size(&self.adv_sid)
724 + WriteHci::size(&self.tx_power)
725 + WriteHci::size(&self.rssi)
726 + WriteHci::size(&self.adv_interval)
727 + WriteHci::size(&self.direct_addr_kind)
728 + WriteHci::size(&self.direct_addr)
729 + WriteHci::size(&self.data)
730 }
731 #[inline(always)]
732 fn write_hci<W: ::embedded_io::Write>(&self, mut writer: W) -> Result<(), W::Error> {
733 self.event_kind.write_hci(&mut writer)?;
734 self.addr_kind.write_hci(&mut writer)?;
735 self.addr.write_hci(&mut writer)?;
736 self.primary_adv_phy.write_hci(&mut writer)?;
737 match self.secondary_adv_phy {
738 None => 0u8.write_hci(&mut writer)?,
739 Some(val) => val.write_hci(&mut writer)?,
740 };
741 self.adv_sid.write_hci(&mut writer)?;
742 self.tx_power.write_hci(&mut writer)?;
743 self.rssi.write_hci(&mut writer)?;
744 self.adv_interval.write_hci(&mut writer)?;
745 self.direct_addr_kind.write_hci(&mut writer)?;
746 self.direct_addr.write_hci(&mut writer)?;
747 self.data.write_hci(&mut writer)?;
748 Ok(())
749 }
750 #[inline(always)]
751 async fn write_hci_async<W: ::embedded_io_async::Write>(&self, mut writer: W) -> Result<(), W::Error> {
752 self.event_kind.write_hci_async(&mut writer).await?;
753 self.addr_kind.write_hci_async(&mut writer).await?;
754 self.addr.write_hci_async(&mut writer).await?;
755 self.primary_adv_phy.write_hci_async(&mut writer).await?;
756 match self.secondary_adv_phy {
757 None => 0u8.write_hci_async(&mut writer).await?,
758 Some(val) => val.write_hci_async(&mut writer).await?,
759 };
760 self.adv_sid.write_hci_async(&mut writer).await?;
761 self.tx_power.write_hci_async(&mut writer).await?;
762 self.rssi.write_hci_async(&mut writer).await?;
763 self.adv_interval.write_hci_async(&mut writer).await?;
764 self.direct_addr_kind.write_hci_async(&mut writer).await?;
765 self.direct_addr.write_hci_async(&mut writer).await?;
766 self.data.write_hci_async(&mut writer).await?;
767 Ok(())
768 }
769}
770
771impl<'de> crate::FromHciBytes<'de> for LeExtAdvReport<'de> {
772 #[allow(unused_variables)]
773 fn from_hci_bytes(data: &'de [u8]) -> Result<(Self, &'de [u8]), crate::FromHciBytesError> {
774 let (event_kind, data) = <LeExtAdvEventKind as crate::FromHciBytes>::from_hci_bytes(data)?;
775 let (addr_kind, data) = <AddrKind as crate::FromHciBytes>::from_hci_bytes(data)?;
776 let (addr, data) = <BdAddr as crate::FromHciBytes>::from_hci_bytes(data)?;
777 let (primary_adv_phy, data) = <PhyKind as crate::FromHciBytes>::from_hci_bytes(data)?;
778 let (secondary_adv_phy, data) = if data[0] == 0 {
779 (None, &data[1..])
780 } else {
781 let (ret, rest) = <PhyKind as crate::FromHciBytes>::from_hci_bytes(data)?;
782 (Some(ret), rest)
783 };
784 let (adv_sid, data) = <u8 as crate::FromHciBytes>::from_hci_bytes(data)?;
785 let (tx_power, data) = <i8 as crate::FromHciBytes>::from_hci_bytes(data)?;
786 let (rssi, data) = <i8 as crate::FromHciBytes>::from_hci_bytes(data)?;
787 let (adv_interval, data) = <Duration<1_250> as crate::FromHciBytes>::from_hci_bytes(data)?;
788 let (direct_addr_kind, data) = <AddrKind as crate::FromHciBytes>::from_hci_bytes(data)?;
789 let (direct_addr, data) = <BdAddr as crate::FromHciBytes>::from_hci_bytes(data)?;
790 let (data, rest) = <&'de [u8] as crate::FromHciBytes>::from_hci_bytes(data)?;
791 Ok((
792 Self {
793 event_kind,
794 addr_kind,
795 addr,
796 primary_adv_phy,
797 secondary_adv_phy,
798 adv_sid,
799 tx_power,
800 rssi,
801 adv_interval,
802 direct_addr_kind,
803 direct_addr,
804 data,
805 },
806 rest,
807 ))
808 }
809}
810
811param! {
812 struct LeExtAdvReports<'a> {
813 num_reports: u8,
814 bytes: RemainingBytes<'a>,
815 }
816}
817
818impl LeExtAdvReports<'_> {
819 pub fn is_empty(&self) -> bool {
821 self.num_reports == 0
822 }
823
824 pub fn len(&self) -> usize {
826 usize::from(self.num_reports)
827 }
828
829 pub fn iter(&self) -> LeExtAdvReportsIter<'_> {
831 LeExtAdvReportsIter {
832 len: self.len(),
833 bytes: &self.bytes,
834 }
835 }
836}
837
838pub struct LeExtAdvReportsIter<'a> {
840 len: usize,
841 bytes: &'a [u8],
842}
843
844impl<'a> Iterator for LeExtAdvReportsIter<'a> {
845 type Item = Result<LeExtAdvReport<'a>, FromHciBytesError>;
846
847 fn next(&mut self) -> Option<Self::Item> {
848 if self.len == 0 {
849 None
850 } else {
851 match LeExtAdvReport::from_hci_bytes(self.bytes) {
852 Ok((report, rest)) => {
853 self.bytes = rest;
854 self.len -= 1;
855 Some(Ok(report))
856 }
857 Err(err) => {
858 self.len = 0;
859 Some(Err(err))
860 }
861 }
862 }
863 }
864
865 fn size_hint(&self) -> (usize, Option<usize>) {
866 (self.len, Some(self.len))
867 }
868}
869
870impl ExactSizeIterator for LeExtAdvReportsIter<'_> {
871 fn len(&self) -> usize {
872 self.len
873 }
874}
875
876impl FusedIterator for LeExtAdvReportsIter<'_> {}
877
878param! {
879 struct LePeriodicAdvSubeventData<'a> {
880 subevent: u8,
881 response_slot_start: u8,
882 response_slot_count: u8,
883 subevent_data: &'a [u8],
884 }
885}
886
887impl<'a, 'b: 'a> WriteHci for &'a [LePeriodicAdvSubeventData<'b>] {
888 #[inline(always)]
889 fn size(&self) -> usize {
890 1 + self.iter().map(WriteHci::size).sum::<usize>()
891 }
892 #[inline(always)]
893 fn write_hci<W: ::embedded_io::Write>(&self, mut writer: W) -> Result<(), W::Error> {
894 writer.write_all(&[self.len() as u8])?;
895 for x in self.iter() {
896 <LePeriodicAdvSubeventData as WriteHci>::write_hci(x, &mut writer)?;
897 }
898 Ok(())
899 }
900 #[inline(always)]
901 async fn write_hci_async<W: ::embedded_io_async::Write>(&self, mut writer: W) -> Result<(), W::Error> {
902 writer.write_all(&[self.len() as u8]).await?;
903 for x in self.iter() {
904 <LePeriodicAdvSubeventData as WriteHci>::write_hci_async(x, &mut writer).await?;
905 }
906 Ok(())
907 }
908}
909
910#[allow(missing_docs)]
911fn read_n<T: ByteAlignedValue>(data: &[u8], n: usize) -> Result<(&[T], &[u8]), FromHciBytesError> {
912 let size = n * core::mem::size_of::<T>();
913 if data.len() < size {
914 return Err(FromHciBytesError::InvalidSize);
915 }
916 let (bytes, rest) = data.split_at(size);
917 let slice = unsafe { core::slice::from_raw_parts(bytes.as_ptr() as *const T, n) };
918 Ok((slice, rest))
919}
920
921param! {
922 struct LePeriodicAdvertisingResponseReport<'a> {
923 tx_power: i8,
924 rssi: i8,
925 cte_type: CteKind,
926 response_slot: u8,
927 data_status: DataStatus,
928 data_length: u8,
929 data: &'a [u8],
930 }
931}
932
933#[derive(Debug, Clone, Hash)]
935#[cfg_attr(feature = "defmt", derive(defmt::Format))]
936pub struct LePeriodicAdvertisingResponseReports<'a> {
937 num_responses: u8,
938 tx_power: &'a [i8],
939 rssi: &'a [i8],
940 cte_type: &'a [CteKind],
941 response_slot: &'a [u8],
942 data_status: &'a [DataStatus],
943 data_length: &'a [u8],
944 data: &'a [u8],
945}
946
947impl<'a> LePeriodicAdvertisingResponseReports<'a> {
948 pub fn is_empty(&self) -> bool {
950 self.num_responses == 0
951 }
952
953 pub fn len(&self) -> usize {
955 usize::from(self.num_responses)
956 }
957
958 pub fn get(&self, index: usize) -> Option<LePeriodicAdvertisingResponseReport<'a>> {
960 if index >= self.len() {
961 return None;
962 }
963 let data_offset: usize = self.data_length[..index].iter().map(|&l| l as usize).sum();
964 let data_len = self.data_length[index] as usize;
965 Some(LePeriodicAdvertisingResponseReport {
966 tx_power: self.tx_power[index],
967 rssi: self.rssi[index],
968 cte_type: self.cte_type[index],
969 response_slot: self.response_slot[index],
970 data_status: self.data_status[index],
971 data_length: self.data_length[index],
972 data: &self.data[data_offset..data_offset + data_len],
973 })
974 }
975
976 pub fn iter(&self) -> LePeriodicAdvertisingResponseReportsIter<'_> {
978 LePeriodicAdvertisingResponseReportsIter {
979 reports: self,
980 index: 0,
981 }
982 }
983}
984
985impl<'de> FromHciBytes<'de> for LePeriodicAdvertisingResponseReports<'de> {
986 fn from_hci_bytes(data: &'de [u8]) -> Result<(Self, &'de [u8]), FromHciBytesError> {
987 let (num_responses, data) = u8::from_hci_bytes(data)?;
988 let n = num_responses as usize;
989
990 let (tx_power, data) = read_n::<i8>(data, n)?;
991 let (rssi, data) = read_n::<i8>(data, n)?;
992 let (cte_type, data) = read_n::<CteKind>(data, n)?;
993 let (response_slot, data) = read_n::<u8>(data, n)?;
994 let (data_status, data) = read_n::<DataStatus>(data, n)?;
995 let (data_length, data) = read_n::<u8>(data, n)?;
996
997 Ok((
998 Self {
999 num_responses,
1000 tx_power,
1001 rssi,
1002 cte_type,
1003 response_slot,
1004 data_status,
1005 data_length,
1006 data,
1007 },
1008 &[],
1009 ))
1010 }
1011}
1012
1013pub struct LePeriodicAdvertisingResponseReportsIter<'a> {
1015 reports: &'a LePeriodicAdvertisingResponseReports<'a>,
1016 index: usize,
1017}
1018
1019impl<'a> Iterator for LePeriodicAdvertisingResponseReportsIter<'a> {
1020 type Item = LePeriodicAdvertisingResponseReport<'a>;
1021
1022 fn next(&mut self) -> Option<Self::Item> {
1023 let entry = self.reports.get(self.index)?;
1024 self.index += 1;
1025 Some(entry)
1026 }
1027
1028 fn size_hint(&self) -> (usize, Option<usize>) {
1029 let remaining = self.reports.len() - self.index;
1030 (remaining, Some(remaining))
1031 }
1032}
1033
1034impl ExactSizeIterator for LePeriodicAdvertisingResponseReportsIter<'_> {
1035 fn len(&self) -> usize {
1036 self.reports.len() - self.index
1037 }
1038}
1039
1040impl FusedIterator for LePeriodicAdvertisingResponseReportsIter<'_> {}
1041
1042param! {
1043 struct LeCsSubeventStepEntry<'a> {
1044 step_mode: u8,
1045 step_channel: u8,
1046 step_data_length: u8,
1047 step_data: &'a [u8],
1048 }
1049}
1050
1051#[derive(Debug, Clone, Hash)]
1059#[cfg_attr(feature = "defmt", derive(defmt::Format))]
1060pub struct LeCsSubeventStepData<'a> {
1061 num_steps_reported: u8,
1062 step_mode: &'a [u8],
1063 step_channel: &'a [u8],
1064 step_data_length: &'a [u8],
1065 step_data: &'a [u8],
1066}
1067
1068impl<'a> LeCsSubeventStepData<'a> {
1069 pub fn is_empty(&self) -> bool {
1071 self.num_steps_reported == 0
1072 }
1073
1074 pub fn len(&self) -> usize {
1076 usize::from(self.num_steps_reported)
1077 }
1078
1079 pub fn get(&self, index: usize) -> Option<LeCsSubeventStepEntry<'a>> {
1081 if index >= self.len() {
1082 return None;
1083 }
1084 let data_offset: usize = self.step_data_length[..index].iter().map(|&l| l as usize).sum();
1085 let data_len = self.step_data_length[index] as usize;
1086 Some(LeCsSubeventStepEntry {
1087 step_mode: self.step_mode[index],
1088 step_channel: self.step_channel[index],
1089 step_data_length: self.step_data_length[index],
1090 step_data: &self.step_data[data_offset..data_offset + data_len],
1091 })
1092 }
1093
1094 pub fn iter(&self) -> LeCsSubeventStepDataIter<'_> {
1096 LeCsSubeventStepDataIter { data: self, index: 0 }
1097 }
1098}
1099
1100impl<'de> FromHciBytes<'de> for LeCsSubeventStepData<'de> {
1101 fn from_hci_bytes(data: &'de [u8]) -> Result<(Self, &'de [u8]), FromHciBytesError> {
1102 let (num_steps_reported, data) = u8::from_hci_bytes(data)?;
1103 let n = num_steps_reported as usize;
1104
1105 let (step_mode, data) = read_n::<u8>(data, n)?;
1106 let (step_channel, data) = read_n::<u8>(data, n)?;
1107 let (step_data_length, data) = read_n::<u8>(data, n)?;
1108
1109 Ok((
1110 Self {
1111 num_steps_reported,
1112 step_mode,
1113 step_channel,
1114 step_data_length,
1115 step_data: data,
1116 },
1117 &[],
1118 ))
1119 }
1120}
1121
1122pub struct LeCsSubeventStepDataIter<'a> {
1124 data: &'a LeCsSubeventStepData<'a>,
1125 index: usize,
1126}
1127
1128impl<'a> Iterator for LeCsSubeventStepDataIter<'a> {
1129 type Item = LeCsSubeventStepEntry<'a>;
1130
1131 fn next(&mut self) -> Option<Self::Item> {
1132 let entry = self.data.get(self.index)?;
1133 self.index += 1;
1134 Some(entry)
1135 }
1136
1137 fn size_hint(&self) -> (usize, Option<usize>) {
1138 let remaining = self.data.len() - self.index;
1139 (remaining, Some(remaining))
1140 }
1141}
1142
1143impl ExactSizeIterator for LeCsSubeventStepDataIter<'_> {
1144 fn len(&self) -> usize {
1145 self.data.len() - self.index
1146 }
1147}
1148
1149impl FusedIterator for LeCsSubeventStepDataIter<'_> {}
1150
1151param! {
1152 #[derive(Default)]
1153 enum DoneStatus {
1154 #[default]
1155 Complete = 0,
1156 Partial = 1,
1157 Aborted = 0xf,
1158 }
1159}
1160
1161#[repr(u8)]
1163#[derive(Default, Debug, Clone, Copy, PartialEq, Eq, Hash)]
1164#[cfg_attr(feature = "defmt", derive(defmt::Format))]
1165pub enum ProcedureAbortReason {
1166 #[default]
1167 NoAbort = 0x0,
1169 HostRequest = 0x1,
1171 FilteredChannelMap = 0x2,
1173 ChannelMapInstantPassed = 0x3,
1175 Unspecified = 0xf,
1177}
1178
1179impl From<u8> for ProcedureAbortReason {
1180 fn from(v: u8) -> Self {
1181 match v {
1182 0x0 => Self::NoAbort,
1183 0x1 => Self::HostRequest,
1184 0x2 => Self::FilteredChannelMap,
1185 0x3 => Self::ChannelMapInstantPassed,
1186 _ => Self::Unspecified,
1187 }
1188 }
1189}
1190
1191#[repr(u8)]
1193#[derive(Default, Debug, Clone, Copy, PartialEq, Eq, Hash)]
1194#[cfg_attr(feature = "defmt", derive(defmt::Format))]
1195pub enum SubeventAbortReason {
1196 #[default]
1197 NoAbort = 0x0,
1199 HostRequest = 0x1,
1201 NoCsSync = 0x2,
1203 SchedulingConflict = 0x3,
1205 Unspecified = 0xf,
1207}
1208
1209impl From<u8> for SubeventAbortReason {
1210 fn from(v: u8) -> Self {
1211 match v {
1212 0x0 => Self::NoAbort,
1213 0x1 => Self::HostRequest,
1214 0x2 => Self::NoCsSync,
1215 0x3 => Self::SchedulingConflict,
1216 _ => Self::Unspecified,
1217 }
1218 }
1219}
1220
1221#[repr(transparent)]
1226#[derive(Default, Debug, Clone, Copy, PartialEq, Eq, Hash)]
1227#[cfg_attr(feature = "defmt", derive(defmt::Format))]
1228pub struct PackedAbortReasons(u8);
1229
1230impl PackedAbortReasons {
1231 pub fn procedure_reason(&self) -> ProcedureAbortReason {
1233 ProcedureAbortReason::from(self.0 & 0x0f)
1234 }
1235
1236 pub fn subevent_reason(&self) -> SubeventAbortReason {
1238 SubeventAbortReason::from((self.0 >> 4) & 0x0f)
1239 }
1240}
1241
1242unsafe impl FixedSizeValue for PackedAbortReasons {
1243 fn is_valid(_data: &[u8]) -> bool {
1244 true
1245 }
1246}
1247
1248#[repr(transparent)]
1250#[derive(Default, Debug, Clone, Copy, PartialEq, Eq, Hash)]
1251#[cfg_attr(feature = "defmt", derive(defmt::Format))]
1252pub struct FrequencyCompensation(u16);
1253
1254impl FrequencyCompensation {
1255 pub fn as_raw(&self) -> u16 {
1257 self.0
1258 }
1259
1260 pub fn is_available(&self) -> bool {
1262 self.0 != 0xC000
1263 }
1264
1265 pub fn as_ppm_x100(&self) -> Option<i16> {
1267 if !self.is_available() {
1268 return None;
1269 }
1270 let val = self.0 & 0x7FFF;
1271 Some(((val << 1) as i16) >> 1)
1272 }
1273}
1274
1275unsafe impl FixedSizeValue for FrequencyCompensation {
1276 fn is_valid(_data: &[u8]) -> bool {
1277 true
1278 }
1279}
1280
1281param!(
1286 struct CigId(u8)
1288);
1289
1290#[allow(missing_docs)]
1291impl CigId {
1292 pub const fn new(v: u8) -> Self {
1294 Self(v)
1295 }
1296
1297 pub fn as_raw(&self) -> u8 {
1299 self.0
1300 }
1301}
1302
1303unsafe impl ByteAlignedValue for CigId {}
1304
1305impl<'de> crate::FromHciBytes<'de> for &'de CigId {
1306 #[inline(always)]
1307 fn from_hci_bytes(data: &'de [u8]) -> Result<(Self, &'de [u8]), crate::FromHciBytesError> {
1308 <CigId as crate::ByteAlignedValue>::ref_from_hci_bytes(data)
1309 }
1310}
1311
1312param!(
1313 struct CisId(u8)
1315);
1316
1317#[allow(missing_docs)]
1318impl CisId {
1319 pub const fn new(v: u8) -> Self {
1321 Self(v)
1322 }
1323
1324 pub fn as_raw(&self) -> u8 {
1326 self.0
1327 }
1328}
1329
1330unsafe impl ByteAlignedValue for CisId {}
1331
1332impl<'de> crate::FromHciBytes<'de> for &'de CisId {
1333 #[inline(always)]
1334 fn from_hci_bytes(data: &'de [u8]) -> Result<(Self, &'de [u8]), crate::FromHciBytesError> {
1335 <CisId as crate::ByteAlignedValue>::ref_from_hci_bytes(data)
1336 }
1337}
1338
1339param! {
1340 struct CisConfig {
1342 cis_id: CisId,
1343 max_sdu_c_to_p: u16,
1344 max_sdu_p_to_c: u16,
1345 phy_c_to_p: PhyMask,
1346 phy_p_to_c: PhyMask,
1347 rtn_c_to_p: u8,
1348 rtn_p_to_c: u8,
1349 }
1350}
1351
1352param_slice!(&'a [CisConfig]);
1353
1354param! {
1355 struct CisConfigTest {
1357 cis_id: CisId,
1358 max_sdu_c_to_p: u16,
1359 max_sdu_p_to_c: u16,
1360 max_pdu_c_to_p: u16,
1361 max_pdu_p_to_c: u16,
1362 phy_c_to_p: PhyMask,
1363 phy_p_to_c: PhyMask,
1364 bn_c_to_p: u8,
1365 bn_p_to_c: u8,
1366 }
1367}
1368
1369param_slice!(&'a [CisConfigTest]);
1370
1371param! {
1372 struct CisConnConfig {
1374 cis_handle: ConnHandle,
1375 acl_handle: ConnHandle,
1376 }
1377}
1378
1379param_slice!(&'a [CisConnConfig]);
1380
1381param! {
1382 #[derive(Default)]
1384 enum DataPathDirection {
1385 #[default]
1386 Input = 0,
1387 Output = 1,
1388 }
1389}
1390
1391param!(
1392 struct DataPathId(u8)
1398);
1399
1400#[allow(missing_docs)]
1401impl DataPathId {
1402 pub const HCI: DataPathId = DataPathId(0x00);
1404 pub const AUDIO_TEST_MODE: DataPathId = DataPathId(0xFF);
1406
1407 pub const fn new(v: u8) -> Self {
1409 Self(v)
1410 }
1411
1412 pub fn as_raw(&self) -> u8 {
1414 self.0
1415 }
1416}
1417
1418unsafe impl ByteAlignedValue for DataPathId {}
1419
1420impl<'de> crate::FromHciBytes<'de> for &'de DataPathId {
1421 #[inline(always)]
1422 fn from_hci_bytes(data: &'de [u8]) -> Result<(Self, &'de [u8]), crate::FromHciBytesError> {
1423 <DataPathId as crate::ByteAlignedValue>::ref_from_hci_bytes(data)
1424 }
1425}
1426
1427param! {
1428 struct CodecId {
1430 coding_format: u8,
1431 company_id: u16,
1432 vendor_specific_codec_id: u16,
1433 }
1434}
1435
1436param!(
1437 struct BroadcastCode([u8; 16])
1439);
1440
1441#[allow(missing_docs)]
1442impl BroadcastCode {
1443 pub const fn new(v: [u8; 16]) -> Self {
1445 Self(v)
1446 }
1447
1448 pub fn raw(&self) -> &[u8] {
1450 &self.0[..]
1451 }
1452}
1453
1454unsafe impl ByteAlignedValue for BroadcastCode {}
1455
1456impl<'de> crate::FromHciBytes<'de> for &'de BroadcastCode {
1457 #[inline(always)]
1458 fn from_hci_bytes(data: &'de [u8]) -> Result<(Self, &'de [u8]), crate::FromHciBytesError> {
1459 <BroadcastCode as crate::ByteAlignedValue>::ref_from_hci_bytes(data)
1460 }
1461}
1462
1463param! {
1464 #[derive(Default)]
1466 enum EncryptionMode {
1467 #[default]
1468 Unencrypted = 0,
1469 Encrypted = 1,
1470 }
1471}
1472
1473param! {
1474 #[derive(Default)]
1476 enum Packing {
1477 #[default]
1478 Sequential = 0,
1479 Interleaved = 1,
1480 }
1481}
1482
1483param! {
1484 #[derive(Default)]
1486 enum Framing {
1487 #[default]
1488 Unframed = 0,
1489 Framed = 1,
1490 }
1491}
1492
1493param! {
1494 #[derive(Default)]
1496 enum PayloadType {
1497 #[default]
1498 ZeroLength = 0,
1499 VariableLength = 1,
1500 MaximumLength = 2,
1501 }
1502}
1503
1504#[cfg(test)]
1505mod tests {
1506 use super::*;
1507
1508 #[test]
1509 fn test_ext_adv_event_kind() {
1510 let k = LeExtAdvEventKind::new().set_connectable(true);
1511 assert_eq!(k.0[0], 0b0000001);
1512 let k = k.set_data_status(LeExtAdvDataStatus::Complete);
1513 assert_eq!(k.0[0], 0b0000001);
1514 let k = k.set_data_status(LeExtAdvDataStatus::IncompleteMoreExpected);
1515 assert_eq!(k.0[0], 0b0100001);
1516 let k = k.set_data_status(LeExtAdvDataStatus::IncompleteTruncated);
1517 assert_eq!(k.0[0], 0b1000001);
1518 }
1519
1520 #[test]
1521 fn test_channel_map_new() {
1522 let m = ChannelMap::new();
1523 for chan in 0..37 {
1524 assert!(!m.is_channel_bad(chan));
1525 }
1526
1527 for chan in 37..40 {
1528 assert!(m.is_channel_bad(chan));
1529 }
1530 }
1531
1532 #[test]
1533 fn test_frequency_compensation_positive() {
1534 let fc = FrequencyCompensation(0x2710);
1535 assert!(fc.is_available());
1536 assert_eq!(fc.as_ppm_x100(), Some(10000));
1537 assert_eq!(fc.as_raw(), 0x2710);
1538 }
1539
1540 #[test]
1541 fn test_frequency_compensation_negative() {
1542 let fc = FrequencyCompensation(0x58F0);
1543 assert!(fc.is_available());
1544 assert_eq!(fc.as_ppm_x100(), Some(-10000));
1545 assert_eq!(fc.as_raw(), 0x58F0);
1546 }
1547
1548 #[test]
1549 fn test_frequency_compensation_not_available() {
1550 let fc = FrequencyCompensation(0xC000);
1551 assert!(!fc.is_available());
1552 assert_eq!(fc.as_ppm_x100(), None);
1553 assert_eq!(fc.as_raw(), 0xC000);
1554 }
1555}