bt_hci/param/
le.rs

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    /// Create a new instance.
17    pub const fn new(v: u8) -> Self {
18        Self(v)
19    }
20
21    /// Get the inner representation.
22    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    /// Create a new instance.
56    pub fn new() -> Self {
57        Self([0xff, 0xff, 0xff, 0xff, 0x1f])
58    }
59
60    /// Check if channel is marked as bad.
61    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    /// Set channel to be marked as bad.
68    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 AllPhys[1] {
140        (0, has_no_tx_phy_preference, set_has_no_tx_phy_preference);
141        (1, has_no_rx_phy_preference, set_has_no_rx_phy_preference);
142    }
143}
144
145param! {
146    bitfield PhyMask[1] {
147        (0, is_le_1m_preferred, set_le_1m_preferred);
148        (1, is_le_2m_preferred, set_le_2m_preferred);
149        (2, is_le_coded_preferred, set_le_coded_preferred);
150    }
151}
152
153/// Preferences when one can choose the phy.
154#[derive(Default)]
155#[repr(u16, align(1))]
156#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
157#[cfg_attr(feature = "defmt", derive(defmt::Format))]
158#[allow(missing_docs)]
159pub enum PhyOptions {
160    #[default]
161    NoPreferredCoding = 0,
162    S2CodingPreferred = 1,
163    S8CodingPreferred = 2,
164}
165
166unsafe impl FixedSizeValue for PhyOptions {
167    #[inline(always)]
168    fn is_valid(data: &[u8]) -> bool {
169        data[0] == 0 || data[0] == 1 || data[0] == 2
170    }
171}
172
173unsafe impl ByteAlignedValue for PhyOptions {}
174
175impl<'de> FromHciBytes<'de> for &'de PhyOptions {
176    #[inline(always)]
177    fn from_hci_bytes(data: &'de [u8]) -> Result<(Self, &'de [u8]), FromHciBytesError> {
178        <PhyOptions as ByteAlignedValue>::ref_from_hci_bytes(data)
179    }
180}
181
182/// PHY preference or requirement during extended advertisement (BLE5.4)
183#[derive(Default)]
184#[repr(u16, align(1))]
185#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
186#[cfg_attr(feature = "defmt", derive(defmt::Format))]
187#[allow(missing_docs)]
188pub enum AdvPhyOptions {
189    #[default]
190    NoPreferredCoding = 0,
191    S2CodingPreferred = 1,
192    S8CodingPreferred = 2,
193    S2CodingRequired = 3,
194    S8CodingRequired = 4,
195}
196
197unsafe impl FixedSizeValue for AdvPhyOptions {
198    #[inline(always)]
199    fn is_valid(data: &[u8]) -> bool {
200        data[0] == 0 || data[0] == 1 || data[0] == 2 || data[0] == 3 || data[0] == 4
201    }
202}
203
204unsafe impl ByteAlignedValue for AdvPhyOptions {}
205
206impl<'de> FromHciBytes<'de> for &'de AdvPhyOptions {
207    #[inline(always)]
208    fn from_hci_bytes(data: &'de [u8]) -> Result<(Self, &'de [u8]), FromHciBytesError> {
209        <AdvPhyOptions as ByteAlignedValue>::ref_from_hci_bytes(data)
210    }
211}
212
213param! {
214    struct ScanningPhy {
215        active_scan: bool,
216        scan_interval: Duration<625>,
217        scan_window: Duration<625>,
218    }
219}
220
221param! {
222    struct InitiatingPhy {
223        scan_interval: Duration<625>,
224        scan_window: Duration<625>,
225        conn_interval_min: Duration<1_250>,
226        conn_interval_max: Duration<1_250>,
227        max_latency: u16,
228        supervision_timeout: Duration<10_000>,
229        min_ce_len: Duration<625>,
230        max_ce_len: Duration<625>,
231    }
232}
233
234/// Parameters for different phy representations.
235#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
236#[cfg_attr(feature = "defmt", derive(defmt::Format))]
237pub struct PhyParams<T> {
238    /// 1M phy parameters.
239    pub le_1m_phy: Option<T>,
240    /// 2M phy parameters.
241    pub le_2m_phy: Option<T>,
242    /// Coded phy parameters.
243    pub le_coded_phy: Option<T>,
244}
245
246impl<T> PhyParams<T> {
247    /// Get the mask associated with the parameters.
248    pub fn scanning_phys(&self) -> PhyMask {
249        PhyMask::new()
250            .set_le_1m_preferred(self.le_1m_phy.is_some())
251            .set_le_2m_preferred(self.le_2m_phy.is_some())
252            .set_le_coded_preferred(self.le_coded_phy.is_some())
253    }
254}
255
256impl<T: WriteHci> WriteHci for PhyParams<T> {
257    #[inline(always)]
258    fn size(&self) -> usize {
259        1 + self.le_1m_phy.size() + self.le_2m_phy.size() + self.le_coded_phy.size()
260    }
261
262    #[inline(always)]
263    fn write_hci<W: embedded_io::Write>(&self, mut writer: W) -> Result<(), W::Error> {
264        self.scanning_phys().write_hci(&mut writer)?;
265        self.le_1m_phy.write_hci(&mut writer)?;
266        self.le_2m_phy.write_hci(&mut writer)?;
267        self.le_coded_phy.write_hci(&mut writer)?;
268        Ok(())
269    }
270
271    #[inline(always)]
272    async fn write_hci_async<W: ::embedded_io_async::Write>(&self, mut writer: W) -> Result<(), W::Error> {
273        self.scanning_phys().write_hci_async(&mut writer).await?;
274        self.le_1m_phy.write_hci_async(&mut writer).await?;
275        self.le_2m_phy.write_hci_async(&mut writer).await?;
276        self.le_coded_phy.write_hci_async(&mut writer).await?;
277        Ok(())
278    }
279}
280
281param!(struct AdvHandle(u8));
282
283impl AdvHandle {
284    /// Create a new instance.
285    pub const fn new(v: u8) -> Self {
286        Self(v)
287    }
288
289    /// Get the inner representation.
290    pub fn as_raw(&self) -> u8 {
291        self.0
292    }
293}
294
295unsafe impl ByteAlignedValue for AdvHandle {}
296
297impl<'de> crate::FromHciBytes<'de> for &'de AdvHandle {
298    #[inline(always)]
299    fn from_hci_bytes(data: &'de [u8]) -> Result<(Self, &'de [u8]), crate::FromHciBytesError> {
300        <AdvHandle as crate::ByteAlignedValue>::ref_from_hci_bytes(data)
301    }
302}
303
304param! {
305    bitfield AdvEventProps[2] {
306        (0, connectable_adv, set_connectable_adv);
307        (1, scannable_adv, set_scannable_adv);
308        (2, directed_adv, set_directed_adv);
309        (3, high_duty_cycle_directed_connectable_adv, set_high_duty_cycle_directed_connectable_adv);
310        (4, legacy_adv, set_legacy_adv);
311        (5, anonymous_adv, set_anonymous_adv);
312        (6, include_tx_power, set_include_tx_power);
313    }
314}
315
316param! {
317    #[derive(Default)]
318    enum Operation {
319        #[default]
320        IntermediateFragment = 0,
321        FirstFragment = 1,
322        LastFragment = 2,
323        Complete = 3,
324        Unchanged = 4,
325    }
326}
327
328param! {
329    struct AdvSet {
330        adv_handle: AdvHandle,
331        duration: Duration<10_000>,
332        max_ext_adv_events: u8,
333    }
334}
335
336param_slice!(&'a [AdvSet]);
337
338param! {
339    bitfield PeriodicAdvProps[2] {
340        (6, is_tx_power_included, include_tx_power);
341    }
342}
343
344param! {
345    #[derive(Default)]
346    enum FilterDuplicates {
347        #[default]
348        Disabled = 0,
349        Enabled = 1,
350        EnabledPerScanPeriod = 2,
351    }
352}
353
354param! {
355    bitfield LePeriodicAdvCreateSyncOptions[1] {
356        (0, is_using_periodic_adv_list, use_periodic_adv_list);
357        (1, is_reporting_initially_disabled, disable_initial_reporting);
358        (2, is_duplicate_filtering_enabled, enable_duplicate_filtering);
359    }
360}
361
362param! {
363    bitfield CteMask[1] {
364        (0, is_aoa_cte, set_aoa_cte);
365        (1, is_aod_1us_cte, set_aod_1us_cte);
366        (2, is_aod_2us_cte, set_aod_2us_cte);
367        (3, is_type_3_cte, set_type_3_cte);
368        (4, is_non_cte, set_non_cte);
369    }
370}
371
372param!(struct SyncHandle(u16));
373
374param!(struct BigHandle(u16));
375
376param! {
377    #[derive(Default)]
378    enum PrivacyMode {
379        #[default]
380        Network = 0,
381        Device = 1,
382    }
383}
384
385param! {
386    #[derive(Default)]
387    enum CteKind {
388        #[default]
389        AoA = 0,
390        AoD1Us = 1,
391        AoD2Us = 2,
392    }
393}
394
395param! {
396    bitfield SwitchingSamplingRates[1] {
397        (0, is_1us_aod_tx, set_1us_aod_tx);
398        (1, is_1us_aod_rx, set_1us_aod_rx);
399        (2, is_1us_aoa_rx, set_1us_aoa_rx);
400    }
401}
402
403param! {
404    bitfield LePeriodicAdvReceiveEnable[1] {
405        (0, is_reporting, set_reporting);
406        (1, is_duplicate_filtering, set_duplicate_filtering);
407    }
408}
409
410param! {
411    #[derive(Default)]
412    enum LePeriodicAdvSyncTransferMode {
413        #[default]
414        NoSync = 0,
415        SyncRx = 1,
416        SyncRxReport = 2,
417        SyncRxReportFilterDuplicates = 3,
418    }
419}
420
421param! {
422    bitfield LeDataRelatedAddrChangeReasons[1] {
423        (0, change_on_adv_data_change, set_change_addr_on_adv_data_changes);
424        (1, change_on_scan_response_data_change, set_change_addr_on_scan_response_data_changes);
425    }
426}
427
428param! {
429    #[derive(Default)]
430    enum LeConnRole {
431        #[default]
432        Central = 0,
433        Peripheral = 1,
434    }
435}
436
437param! {
438    #[derive(Default)]
439    enum ClockAccuracy {
440        #[default]
441        Ppm500 = 0,
442        Ppm250 = 1,
443        Ppm150 = 2,
444        Ppm100 = 3,
445        Ppm75 = 4,
446        Ppm50 = 5,
447        Ppm30 = 6,
448        Ppm20 = 7,
449    }
450}
451
452param! {
453    struct LeAdvertisingReportParam<'a> {
454        event_type: u8,
455        addr_kind: AddrKind,
456        addr: BdAddr,
457        data: &'a [u8],
458        rssi: i8,
459    }
460}
461
462param_slice! {
463    [LeDirectedAdvertisingReportParam; 16] {
464        event_type[0]: u8,
465        addr_kind[1]: AddrKind,
466        addr[2]: BdAddr,
467        direct_addr_kind[8]: AddrKind,
468        direct_addr[9]: BdAddr,
469        rssi[15]: i8,
470    }
471}
472
473param_slice! {
474    [LeIQSample; 2] {
475        i_sample[0]: i8,
476        q_sample[1]: i8,
477    }
478}
479
480param_slice! {
481    [BisConnHandle; 2] {
482        handle[0]: ConnHandle,
483    }
484}
485
486param! {
487    #[derive(Default)]
488    enum DataStatus {
489        #[default]
490        Complete = 0,
491        Incomplete = 1,
492    }
493}
494
495param! {
496    #[derive(Default)]
497    enum PacketStatus {
498        #[default]
499        CrcCorrect = 0,
500        CrcIncorrectUsedLength = 1,
501        CrcIncorrectUsedOther = 2,
502        InsufficientResources = 0xff,
503    }
504}
505
506param! {
507    #[derive(Default)]
508    enum ZoneEntered {
509        #[default]
510        Low = 0,
511        Middle = 1,
512        High = 2,
513    }
514}
515
516param! {
517    #[derive(Default)]
518    enum LeTxPowerReportingReason {
519        #[default]
520        LocalTxPowerChanged = 0,
521        RemoteTxPowerChanged = 1,
522        LeReadRemoteTxPowerLevelCompleted = 2,
523    }
524}
525
526param! {
527    #[derive(Default)]
528    enum LeAdvEventKind {
529        #[default]
530        AdvInd = 0,
531        AdvDirectInd = 1,
532        AdvScanInd = 2,
533        AdvNonconnInd = 3,
534        ScanRsp = 4,
535    }
536}
537
538param! {
539    bitfield LeExtAdvEventKind[2] {
540        (0, connectable, set_connectable);
541        (1, scannable, set_scannable);
542        (2, directed, set_directed);
543        (3, scan_response, set_scan_response);
544        (4, legacy, set_legacy);
545    }
546}
547
548/// Advertising data status.
549#[allow(missing_docs)]
550pub enum LeExtAdvDataStatus {
551    Complete,
552    IncompleteMoreExpected,
553    IncompleteTruncated,
554    Reserved,
555}
556
557impl LeExtAdvEventKind {
558    /// Get data status.
559    pub fn data_status(&self) -> LeExtAdvDataStatus {
560        let data_status = (self.0[0] >> 5) & 0x03;
561        match data_status {
562            0 => LeExtAdvDataStatus::Complete,
563            1 => LeExtAdvDataStatus::IncompleteMoreExpected,
564            2 => LeExtAdvDataStatus::IncompleteTruncated,
565            _ => LeExtAdvDataStatus::Reserved,
566        }
567    }
568
569    /// Set data status.
570    pub fn set_data_status(mut self, status: LeExtAdvDataStatus) -> Self {
571        let value = match status {
572            LeExtAdvDataStatus::Complete => 0,
573            LeExtAdvDataStatus::IncompleteMoreExpected => 1,
574            LeExtAdvDataStatus::IncompleteTruncated => 2,
575            LeExtAdvDataStatus::Reserved => 3,
576        };
577        self.0[0] &= !(0x03 << 5);
578        self.0[0] |= value << 5;
579        self
580    }
581}
582
583param! {
584    struct LeAdvReport<'a> {
585        event_kind: LeAdvEventKind,
586        addr_kind: AddrKind,
587        addr: BdAddr,
588        data: &'a [u8],
589        rssi: i8,
590    }
591}
592
593param! {
594    struct LeAdvReports<'a> {
595        num_reports: u8,
596        bytes: RemainingBytes<'a>,
597    }
598}
599
600impl LeAdvReports<'_> {
601    /// Check if there are more reports available.
602    pub fn is_empty(&self) -> bool {
603        self.num_reports == 0
604    }
605
606    /// Number of advertising reports.
607    pub fn len(&self) -> usize {
608        usize::from(self.num_reports)
609    }
610
611    /// Create an iterator over the advertising reports.
612    pub fn iter(&self) -> LeAdvReportsIter<'_> {
613        LeAdvReportsIter {
614            len: self.len(),
615            bytes: &self.bytes,
616        }
617    }
618}
619
620/// An iterator for advertising reports.
621pub struct LeAdvReportsIter<'a> {
622    len: usize,
623    bytes: &'a [u8],
624}
625
626impl<'a> Iterator for LeAdvReportsIter<'a> {
627    type Item = Result<LeAdvReport<'a>, FromHciBytesError>;
628
629    fn next(&mut self) -> Option<Self::Item> {
630        if self.len == 0 {
631            None
632        } else {
633            match LeAdvReport::from_hci_bytes(self.bytes) {
634                Ok((report, rest)) => {
635                    self.bytes = rest;
636                    self.len -= 1;
637                    Some(Ok(report))
638                }
639                Err(err) => {
640                    self.len = 0;
641                    Some(Err(err))
642                }
643            }
644        }
645    }
646
647    fn size_hint(&self) -> (usize, Option<usize>) {
648        (self.len, Some(self.len))
649    }
650}
651
652impl ExactSizeIterator for LeAdvReportsIter<'_> {
653    fn len(&self) -> usize {
654        self.len
655    }
656}
657
658impl FusedIterator for LeAdvReportsIter<'_> {}
659
660#[derive(Default, Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
661#[cfg_attr(feature = "defmt", derive(defmt::Format))]
662#[allow(missing_docs)]
663pub struct LeExtAdvReport<'a> {
664    pub event_kind: LeExtAdvEventKind,
665    pub addr_kind: AddrKind,
666    pub addr: BdAddr,
667    pub primary_adv_phy: PhyKind,
668    pub secondary_adv_phy: Option<PhyKind>,
669    pub adv_sid: u8,
670    pub tx_power: i8,
671    pub rssi: i8,
672    pub adv_interval: Duration<1_250>,
673    pub direct_addr_kind: AddrKind,
674    pub direct_addr: BdAddr,
675    pub data: &'a [u8],
676}
677
678impl WriteHci for LeExtAdvReport<'_> {
679    #[inline(always)]
680    fn size(&self) -> usize {
681        WriteHci::size(&self.event_kind)
682            + WriteHci::size(&self.addr_kind)
683            + WriteHci::size(&self.addr)
684            + WriteHci::size(&self.primary_adv_phy)
685            + 1 //secondary_adv_phy
686            + WriteHci::size(&self.adv_sid)
687            + WriteHci::size(&self.tx_power)
688            + WriteHci::size(&self.rssi)
689            + WriteHci::size(&self.adv_interval)
690            + WriteHci::size(&self.direct_addr_kind)
691            + WriteHci::size(&self.direct_addr)
692            + WriteHci::size(&self.data)
693    }
694    #[inline(always)]
695    fn write_hci<W: ::embedded_io::Write>(&self, mut writer: W) -> Result<(), W::Error> {
696        self.event_kind.write_hci(&mut writer)?;
697        self.addr_kind.write_hci(&mut writer)?;
698        self.addr.write_hci(&mut writer)?;
699        self.primary_adv_phy.write_hci(&mut writer)?;
700        match self.secondary_adv_phy {
701            None => 0u8.write_hci(&mut writer)?,
702            Some(val) => val.write_hci(&mut writer)?,
703        };
704        self.adv_sid.write_hci(&mut writer)?;
705        self.tx_power.write_hci(&mut writer)?;
706        self.rssi.write_hci(&mut writer)?;
707        self.adv_interval.write_hci(&mut writer)?;
708        self.direct_addr_kind.write_hci(&mut writer)?;
709        self.direct_addr.write_hci(&mut writer)?;
710        self.data.write_hci(&mut writer)?;
711        Ok(())
712    }
713    #[inline(always)]
714    async fn write_hci_async<W: ::embedded_io_async::Write>(&self, mut writer: W) -> Result<(), W::Error> {
715        self.event_kind.write_hci_async(&mut writer).await?;
716        self.addr_kind.write_hci_async(&mut writer).await?;
717        self.addr.write_hci_async(&mut writer).await?;
718        self.primary_adv_phy.write_hci_async(&mut writer).await?;
719        match self.secondary_adv_phy {
720            None => 0u8.write_hci_async(&mut writer).await?,
721            Some(val) => val.write_hci_async(&mut writer).await?,
722        };
723        self.adv_sid.write_hci_async(&mut writer).await?;
724        self.tx_power.write_hci_async(&mut writer).await?;
725        self.rssi.write_hci_async(&mut writer).await?;
726        self.adv_interval.write_hci_async(&mut writer).await?;
727        self.direct_addr_kind.write_hci_async(&mut writer).await?;
728        self.direct_addr.write_hci_async(&mut writer).await?;
729        self.data.write_hci_async(&mut writer).await?;
730        Ok(())
731    }
732}
733
734impl<'de> crate::FromHciBytes<'de> for LeExtAdvReport<'de> {
735    #[allow(unused_variables)]
736    fn from_hci_bytes(data: &'de [u8]) -> Result<(Self, &'de [u8]), crate::FromHciBytesError> {
737        let (event_kind, data) = <LeExtAdvEventKind as crate::FromHciBytes>::from_hci_bytes(data)?;
738        let (addr_kind, data) = <AddrKind as crate::FromHciBytes>::from_hci_bytes(data)?;
739        let (addr, data) = <BdAddr as crate::FromHciBytes>::from_hci_bytes(data)?;
740        let (primary_adv_phy, data) = <PhyKind as crate::FromHciBytes>::from_hci_bytes(data)?;
741        let (secondary_adv_phy, data) = if data[0] == 0 {
742            (None, &data[1..])
743        } else {
744            let (ret, rest) = <PhyKind as crate::FromHciBytes>::from_hci_bytes(data)?;
745            (Some(ret), rest)
746        };
747        let (adv_sid, data) = <u8 as crate::FromHciBytes>::from_hci_bytes(data)?;
748        let (tx_power, data) = <i8 as crate::FromHciBytes>::from_hci_bytes(data)?;
749        let (rssi, data) = <i8 as crate::FromHciBytes>::from_hci_bytes(data)?;
750        let (adv_interval, data) = <Duration<1_250> as crate::FromHciBytes>::from_hci_bytes(data)?;
751        let (direct_addr_kind, data) = <AddrKind as crate::FromHciBytes>::from_hci_bytes(data)?;
752        let (direct_addr, data) = <BdAddr as crate::FromHciBytes>::from_hci_bytes(data)?;
753        let (data, rest) = <&'de [u8] as crate::FromHciBytes>::from_hci_bytes(data)?;
754        Ok((
755            Self {
756                event_kind,
757                addr_kind,
758                addr,
759                primary_adv_phy,
760                secondary_adv_phy,
761                adv_sid,
762                tx_power,
763                rssi,
764                adv_interval,
765                direct_addr_kind,
766                direct_addr,
767                data,
768            },
769            rest,
770        ))
771    }
772}
773
774param! {
775    struct LeExtAdvReports<'a> {
776        num_reports: u8,
777        bytes: RemainingBytes<'a>,
778    }
779}
780
781impl LeExtAdvReports<'_> {
782    /// Check if there are more reports available.
783    pub fn is_empty(&self) -> bool {
784        self.num_reports == 0
785    }
786
787    /// Number of advertising reports.
788    pub fn len(&self) -> usize {
789        usize::from(self.num_reports)
790    }
791
792    /// Create an iterator over the advertising reports.
793    pub fn iter(&self) -> LeExtAdvReportsIter<'_> {
794        LeExtAdvReportsIter {
795            len: self.len(),
796            bytes: &self.bytes,
797        }
798    }
799}
800
801/// An iterator for extended advertising reports.
802pub struct LeExtAdvReportsIter<'a> {
803    len: usize,
804    bytes: &'a [u8],
805}
806
807impl<'a> Iterator for LeExtAdvReportsIter<'a> {
808    type Item = Result<LeExtAdvReport<'a>, FromHciBytesError>;
809
810    fn next(&mut self) -> Option<Self::Item> {
811        if self.len == 0 {
812            None
813        } else {
814            match LeExtAdvReport::from_hci_bytes(self.bytes) {
815                Ok((report, rest)) => {
816                    self.bytes = rest;
817                    self.len -= 1;
818                    Some(Ok(report))
819                }
820                Err(err) => {
821                    self.len = 0;
822                    Some(Err(err))
823                }
824            }
825        }
826    }
827
828    fn size_hint(&self) -> (usize, Option<usize>) {
829        (self.len, Some(self.len))
830    }
831}
832
833impl ExactSizeIterator for LeExtAdvReportsIter<'_> {
834    fn len(&self) -> usize {
835        self.len
836    }
837}
838
839impl FusedIterator for LeExtAdvReportsIter<'_> {}
840
841param! {
842    struct LePeriodicAdvSubeventData<'a> {
843        subevent: u8,
844        response_slot_start: u8,
845        response_slot_count: u8,
846        subevent_data: &'a [u8],
847    }
848}
849
850impl<'a, 'b: 'a> WriteHci for &'a [LePeriodicAdvSubeventData<'b>] {
851    #[inline(always)]
852    fn size(&self) -> usize {
853        1 + self.iter().map(WriteHci::size).sum::<usize>()
854    }
855    #[inline(always)]
856    fn write_hci<W: ::embedded_io::Write>(&self, mut writer: W) -> Result<(), W::Error> {
857        writer.write_all(&[self.len() as u8])?;
858        for x in self.iter() {
859            <LePeriodicAdvSubeventData as WriteHci>::write_hci(x, &mut writer)?;
860        }
861        Ok(())
862    }
863    #[inline(always)]
864    async fn write_hci_async<W: ::embedded_io_async::Write>(&self, mut writer: W) -> Result<(), W::Error> {
865        writer.write_all(&[self.len() as u8]).await?;
866        for x in self.iter() {
867            <LePeriodicAdvSubeventData as WriteHci>::write_hci_async(x, &mut writer).await?;
868        }
869        Ok(())
870    }
871}
872
873#[cfg(test)]
874mod tests {
875    use super::*;
876
877    #[test]
878    fn test_ext_adv_event_kind() {
879        let k = LeExtAdvEventKind::new().set_connectable(true);
880        assert_eq!(k.0[0], 0b0000001);
881        let k = k.set_data_status(LeExtAdvDataStatus::Complete);
882        assert_eq!(k.0[0], 0b0000001);
883        let k = k.set_data_status(LeExtAdvDataStatus::IncompleteMoreExpected);
884        assert_eq!(k.0[0], 0b0100001);
885        let k = k.set_data_status(LeExtAdvDataStatus::IncompleteTruncated);
886        assert_eq!(k.0[0], 0b1000001);
887    }
888
889    #[test]
890    fn test_channel_map_new() {
891        let m = ChannelMap::new();
892        for chan in 0..37 {
893            assert!(!m.is_channel_bad(chan));
894        }
895
896        for chan in 37..40 {
897            assert!(m.is_channel_bad(chan));
898        }
899    }
900}