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