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 }
419}
420
421param! {
422 bitfield SwitchingSamplingRates[1] {
423 (0, is_1us_aod_tx, set_1us_aod_tx);
424 (1, is_1us_aod_rx, set_1us_aod_rx);
425 (2, is_1us_aoa_rx, set_1us_aoa_rx);
426 }
427}
428
429param! {
430 bitfield LePeriodicAdvReceiveEnable[1] {
431 (0, is_reporting, set_reporting);
432 (1, is_duplicate_filtering, set_duplicate_filtering);
433 }
434}
435
436param! {
437 #[derive(Default)]
438 enum LePeriodicAdvSyncTransferMode {
439 #[default]
440 NoSync = 0,
441 SyncRx = 1,
442 SyncRxReport = 2,
443 SyncRxReportFilterDuplicates = 3,
444 }
445}
446
447param! {
448 bitfield LeDataRelatedAddrChangeReasons[1] {
449 (0, change_on_adv_data_change, set_change_addr_on_adv_data_changes);
450 (1, change_on_scan_response_data_change, set_change_addr_on_scan_response_data_changes);
451 }
452}
453
454param! {
455 #[derive(Default)]
456 enum LeConnRole {
457 #[default]
458 Central = 0,
459 Peripheral = 1,
460 }
461}
462
463param! {
464 #[derive(Default)]
465 enum ClockAccuracy {
466 #[default]
467 Ppm500 = 0,
468 Ppm250 = 1,
469 Ppm150 = 2,
470 Ppm100 = 3,
471 Ppm75 = 4,
472 Ppm50 = 5,
473 Ppm30 = 6,
474 Ppm20 = 7,
475 }
476}
477
478param! {
479 struct LeAdvertisingReportParam<'a> {
480 event_type: u8,
481 addr_kind: AddrKind,
482 addr: BdAddr,
483 data: &'a [u8],
484 rssi: i8,
485 }
486}
487
488param_slice! {
489 [LeDirectedAdvertisingReportParam; 16] {
490 event_type[0]: u8,
491 addr_kind[1]: AddrKind,
492 addr[2]: BdAddr,
493 direct_addr_kind[8]: AddrKind,
494 direct_addr[9]: BdAddr,
495 rssi[15]: i8,
496 }
497}
498
499param_slice! {
500 [LeIQSample; 2] {
501 i_sample[0]: i8,
502 q_sample[1]: i8,
503 }
504}
505
506param_slice! {
507 [BisConnHandle; 2] {
508 handle[0]: ConnHandle,
509 }
510}
511
512param! {
513 #[derive(Default)]
514 enum DataStatus {
515 #[default]
516 Complete = 0,
517 Incomplete = 1,
518 }
519}
520
521param! {
522 #[derive(Default)]
523 enum PacketStatus {
524 #[default]
525 CrcCorrect = 0,
526 CrcIncorrectUsedLength = 1,
527 CrcIncorrectUsedOther = 2,
528 InsufficientResources = 0xff,
529 }
530}
531
532param! {
533 #[derive(Default)]
534 enum ZoneEntered {
535 #[default]
536 Low = 0,
537 Middle = 1,
538 High = 2,
539 }
540}
541
542param! {
543 #[derive(Default)]
544 enum LeTxPowerReportingReason {
545 #[default]
546 LocalTxPowerChanged = 0,
547 RemoteTxPowerChanged = 1,
548 LeReadRemoteTxPowerLevelCompleted = 2,
549 }
550}
551
552param! {
553 #[derive(Default)]
554 enum LeAdvEventKind {
555 #[default]
556 AdvInd = 0,
557 AdvDirectInd = 1,
558 AdvScanInd = 2,
559 AdvNonconnInd = 3,
560 ScanRsp = 4,
561 }
562}
563
564param! {
565 bitfield LeExtAdvEventKind[2] {
566 (0, connectable, set_connectable);
567 (1, scannable, set_scannable);
568 (2, directed, set_directed);
569 (3, scan_response, set_scan_response);
570 (4, legacy, set_legacy);
571 }
572}
573
574#[allow(missing_docs)]
576pub enum LeExtAdvDataStatus {
577 Complete,
578 IncompleteMoreExpected,
579 IncompleteTruncated,
580 Reserved,
581}
582
583impl LeExtAdvEventKind {
584 pub fn data_status(&self) -> LeExtAdvDataStatus {
586 let data_status = (self.0[0] >> 5) & 0x03;
587 match data_status {
588 0 => LeExtAdvDataStatus::Complete,
589 1 => LeExtAdvDataStatus::IncompleteMoreExpected,
590 2 => LeExtAdvDataStatus::IncompleteTruncated,
591 _ => LeExtAdvDataStatus::Reserved,
592 }
593 }
594
595 pub fn set_data_status(mut self, status: LeExtAdvDataStatus) -> Self {
597 let value = match status {
598 LeExtAdvDataStatus::Complete => 0,
599 LeExtAdvDataStatus::IncompleteMoreExpected => 1,
600 LeExtAdvDataStatus::IncompleteTruncated => 2,
601 LeExtAdvDataStatus::Reserved => 3,
602 };
603 self.0[0] &= !(0x03 << 5);
604 self.0[0] |= value << 5;
605 self
606 }
607}
608
609param! {
610 struct LeAdvReport<'a> {
611 event_kind: LeAdvEventKind,
612 addr_kind: AddrKind,
613 addr: BdAddr,
614 data: &'a [u8],
615 rssi: i8,
616 }
617}
618
619param! {
620 struct LeAdvReports<'a> {
621 num_reports: u8,
622 bytes: RemainingBytes<'a>,
623 }
624}
625
626impl LeAdvReports<'_> {
627 pub fn is_empty(&self) -> bool {
629 self.num_reports == 0
630 }
631
632 pub fn len(&self) -> usize {
634 usize::from(self.num_reports)
635 }
636
637 pub fn iter(&self) -> LeAdvReportsIter<'_> {
639 LeAdvReportsIter {
640 len: self.len(),
641 bytes: &self.bytes,
642 }
643 }
644}
645
646pub struct LeAdvReportsIter<'a> {
648 len: usize,
649 bytes: &'a [u8],
650}
651
652impl<'a> Iterator for LeAdvReportsIter<'a> {
653 type Item = Result<LeAdvReport<'a>, FromHciBytesError>;
654
655 fn next(&mut self) -> Option<Self::Item> {
656 if self.len == 0 {
657 None
658 } else {
659 match LeAdvReport::from_hci_bytes(self.bytes) {
660 Ok((report, rest)) => {
661 self.bytes = rest;
662 self.len -= 1;
663 Some(Ok(report))
664 }
665 Err(err) => {
666 self.len = 0;
667 Some(Err(err))
668 }
669 }
670 }
671 }
672
673 fn size_hint(&self) -> (usize, Option<usize>) {
674 (self.len, Some(self.len))
675 }
676}
677
678impl ExactSizeIterator for LeAdvReportsIter<'_> {
679 fn len(&self) -> usize {
680 self.len
681 }
682}
683
684impl FusedIterator for LeAdvReportsIter<'_> {}
685
686#[derive(Default, Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
687#[cfg_attr(feature = "defmt", derive(defmt::Format))]
688#[allow(missing_docs)]
689pub struct LeExtAdvReport<'a> {
690 pub event_kind: LeExtAdvEventKind,
691 pub addr_kind: AddrKind,
692 pub addr: BdAddr,
693 pub primary_adv_phy: PhyKind,
694 pub secondary_adv_phy: Option<PhyKind>,
695 pub adv_sid: u8,
696 pub tx_power: i8,
697 pub rssi: i8,
698 pub adv_interval: Duration<1_250>,
699 pub direct_addr_kind: AddrKind,
700 pub direct_addr: BdAddr,
701 pub data: &'a [u8],
702}
703
704impl WriteHci for LeExtAdvReport<'_> {
705 #[inline(always)]
706 fn size(&self) -> usize {
707 WriteHci::size(&self.event_kind)
708 + WriteHci::size(&self.addr_kind)
709 + WriteHci::size(&self.addr)
710 + WriteHci::size(&self.primary_adv_phy)
711 + 1 + WriteHci::size(&self.adv_sid)
713 + WriteHci::size(&self.tx_power)
714 + WriteHci::size(&self.rssi)
715 + WriteHci::size(&self.adv_interval)
716 + WriteHci::size(&self.direct_addr_kind)
717 + WriteHci::size(&self.direct_addr)
718 + WriteHci::size(&self.data)
719 }
720 #[inline(always)]
721 fn write_hci<W: ::embedded_io::Write>(&self, mut writer: W) -> Result<(), W::Error> {
722 self.event_kind.write_hci(&mut writer)?;
723 self.addr_kind.write_hci(&mut writer)?;
724 self.addr.write_hci(&mut writer)?;
725 self.primary_adv_phy.write_hci(&mut writer)?;
726 match self.secondary_adv_phy {
727 None => 0u8.write_hci(&mut writer)?,
728 Some(val) => val.write_hci(&mut writer)?,
729 };
730 self.adv_sid.write_hci(&mut writer)?;
731 self.tx_power.write_hci(&mut writer)?;
732 self.rssi.write_hci(&mut writer)?;
733 self.adv_interval.write_hci(&mut writer)?;
734 self.direct_addr_kind.write_hci(&mut writer)?;
735 self.direct_addr.write_hci(&mut writer)?;
736 self.data.write_hci(&mut writer)?;
737 Ok(())
738 }
739 #[inline(always)]
740 async fn write_hci_async<W: ::embedded_io_async::Write>(&self, mut writer: W) -> Result<(), W::Error> {
741 self.event_kind.write_hci_async(&mut writer).await?;
742 self.addr_kind.write_hci_async(&mut writer).await?;
743 self.addr.write_hci_async(&mut writer).await?;
744 self.primary_adv_phy.write_hci_async(&mut writer).await?;
745 match self.secondary_adv_phy {
746 None => 0u8.write_hci_async(&mut writer).await?,
747 Some(val) => val.write_hci_async(&mut writer).await?,
748 };
749 self.adv_sid.write_hci_async(&mut writer).await?;
750 self.tx_power.write_hci_async(&mut writer).await?;
751 self.rssi.write_hci_async(&mut writer).await?;
752 self.adv_interval.write_hci_async(&mut writer).await?;
753 self.direct_addr_kind.write_hci_async(&mut writer).await?;
754 self.direct_addr.write_hci_async(&mut writer).await?;
755 self.data.write_hci_async(&mut writer).await?;
756 Ok(())
757 }
758}
759
760impl<'de> crate::FromHciBytes<'de> for LeExtAdvReport<'de> {
761 #[allow(unused_variables)]
762 fn from_hci_bytes(data: &'de [u8]) -> Result<(Self, &'de [u8]), crate::FromHciBytesError> {
763 let (event_kind, data) = <LeExtAdvEventKind as crate::FromHciBytes>::from_hci_bytes(data)?;
764 let (addr_kind, data) = <AddrKind as crate::FromHciBytes>::from_hci_bytes(data)?;
765 let (addr, data) = <BdAddr as crate::FromHciBytes>::from_hci_bytes(data)?;
766 let (primary_adv_phy, data) = <PhyKind as crate::FromHciBytes>::from_hci_bytes(data)?;
767 let (secondary_adv_phy, data) = if data[0] == 0 {
768 (None, &data[1..])
769 } else {
770 let (ret, rest) = <PhyKind as crate::FromHciBytes>::from_hci_bytes(data)?;
771 (Some(ret), rest)
772 };
773 let (adv_sid, data) = <u8 as crate::FromHciBytes>::from_hci_bytes(data)?;
774 let (tx_power, data) = <i8 as crate::FromHciBytes>::from_hci_bytes(data)?;
775 let (rssi, data) = <i8 as crate::FromHciBytes>::from_hci_bytes(data)?;
776 let (adv_interval, data) = <Duration<1_250> as crate::FromHciBytes>::from_hci_bytes(data)?;
777 let (direct_addr_kind, data) = <AddrKind as crate::FromHciBytes>::from_hci_bytes(data)?;
778 let (direct_addr, data) = <BdAddr as crate::FromHciBytes>::from_hci_bytes(data)?;
779 let (data, rest) = <&'de [u8] as crate::FromHciBytes>::from_hci_bytes(data)?;
780 Ok((
781 Self {
782 event_kind,
783 addr_kind,
784 addr,
785 primary_adv_phy,
786 secondary_adv_phy,
787 adv_sid,
788 tx_power,
789 rssi,
790 adv_interval,
791 direct_addr_kind,
792 direct_addr,
793 data,
794 },
795 rest,
796 ))
797 }
798}
799
800param! {
801 struct LeExtAdvReports<'a> {
802 num_reports: u8,
803 bytes: RemainingBytes<'a>,
804 }
805}
806
807impl LeExtAdvReports<'_> {
808 pub fn is_empty(&self) -> bool {
810 self.num_reports == 0
811 }
812
813 pub fn len(&self) -> usize {
815 usize::from(self.num_reports)
816 }
817
818 pub fn iter(&self) -> LeExtAdvReportsIter<'_> {
820 LeExtAdvReportsIter {
821 len: self.len(),
822 bytes: &self.bytes,
823 }
824 }
825}
826
827pub struct LeExtAdvReportsIter<'a> {
829 len: usize,
830 bytes: &'a [u8],
831}
832
833impl<'a> Iterator for LeExtAdvReportsIter<'a> {
834 type Item = Result<LeExtAdvReport<'a>, FromHciBytesError>;
835
836 fn next(&mut self) -> Option<Self::Item> {
837 if self.len == 0 {
838 None
839 } else {
840 match LeExtAdvReport::from_hci_bytes(self.bytes) {
841 Ok((report, rest)) => {
842 self.bytes = rest;
843 self.len -= 1;
844 Some(Ok(report))
845 }
846 Err(err) => {
847 self.len = 0;
848 Some(Err(err))
849 }
850 }
851 }
852 }
853
854 fn size_hint(&self) -> (usize, Option<usize>) {
855 (self.len, Some(self.len))
856 }
857}
858
859impl ExactSizeIterator for LeExtAdvReportsIter<'_> {
860 fn len(&self) -> usize {
861 self.len
862 }
863}
864
865impl FusedIterator for LeExtAdvReportsIter<'_> {}
866
867param! {
868 struct LePeriodicAdvSubeventData<'a> {
869 subevent: u8,
870 response_slot_start: u8,
871 response_slot_count: u8,
872 subevent_data: &'a [u8],
873 }
874}
875
876impl<'a, 'b: 'a> WriteHci for &'a [LePeriodicAdvSubeventData<'b>] {
877 #[inline(always)]
878 fn size(&self) -> usize {
879 1 + self.iter().map(WriteHci::size).sum::<usize>()
880 }
881 #[inline(always)]
882 fn write_hci<W: ::embedded_io::Write>(&self, mut writer: W) -> Result<(), W::Error> {
883 writer.write_all(&[self.len() as u8])?;
884 for x in self.iter() {
885 <LePeriodicAdvSubeventData as WriteHci>::write_hci(x, &mut writer)?;
886 }
887 Ok(())
888 }
889 #[inline(always)]
890 async fn write_hci_async<W: ::embedded_io_async::Write>(&self, mut writer: W) -> Result<(), W::Error> {
891 writer.write_all(&[self.len() as u8]).await?;
892 for x in self.iter() {
893 <LePeriodicAdvSubeventData as WriteHci>::write_hci_async(x, &mut writer).await?;
894 }
895 Ok(())
896 }
897}
898
899#[cfg(test)]
900mod tests {
901 use super::*;
902
903 #[test]
904 fn test_ext_adv_event_kind() {
905 let k = LeExtAdvEventKind::new().set_connectable(true);
906 assert_eq!(k.0[0], 0b0000001);
907 let k = k.set_data_status(LeExtAdvDataStatus::Complete);
908 assert_eq!(k.0[0], 0b0000001);
909 let k = k.set_data_status(LeExtAdvDataStatus::IncompleteMoreExpected);
910 assert_eq!(k.0[0], 0b0100001);
911 let k = k.set_data_status(LeExtAdvDataStatus::IncompleteTruncated);
912 assert_eq!(k.0[0], 0b1000001);
913 }
914
915 #[test]
916 fn test_channel_map_new() {
917 let m = ChannelMap::new();
918 for chan in 0..37 {
919 assert!(!m.is_channel_bad(chan));
920 }
921
922 for chan in 37..40 {
923 assert!(m.is_channel_bad(chan));
924 }
925 }
926}