Skip to main content

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 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/// Preferences when one can choose the phy.
172#[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/// PHY preference or requirement during extended advertisement (BLE5.4)
201#[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/// Parameters for different phy representations.
261#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
262#[cfg_attr(feature = "defmt", derive(defmt::Format))]
263pub struct PhyParams<T> {
264    /// 1M phy parameters.
265    pub le_1m_phy: Option<T>,
266    /// 2M phy parameters.
267    pub le_2m_phy: Option<T>,
268    /// Coded phy parameters.
269    pub le_coded_phy: Option<T>,
270}
271
272impl<T> PhyParams<T> {
273    /// Get the mask associated with the parameters.
274    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    /// Create a new instance.
311    pub const fn new(v: u8) -> Self {
312        Self(v)
313    }
314
315    /// Get the inner representation.
316    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/// Advertising data status.
575#[allow(missing_docs)]
576pub enum LeExtAdvDataStatus {
577    Complete,
578    IncompleteMoreExpected,
579    IncompleteTruncated,
580    Reserved,
581}
582
583impl LeExtAdvEventKind {
584    /// Get data status.
585    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    /// Set data status.
596    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    /// Check if there are more reports available.
628    pub fn is_empty(&self) -> bool {
629        self.num_reports == 0
630    }
631
632    /// Number of advertising reports.
633    pub fn len(&self) -> usize {
634        usize::from(self.num_reports)
635    }
636
637    /// Create an iterator over the advertising reports.
638    pub fn iter(&self) -> LeAdvReportsIter<'_> {
639        LeAdvReportsIter {
640            len: self.len(),
641            bytes: &self.bytes,
642        }
643    }
644}
645
646/// An iterator for advertising reports.
647pub 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 //secondary_adv_phy
712            + 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    /// Check if there are more reports available.
809    pub fn is_empty(&self) -> bool {
810        self.num_reports == 0
811    }
812
813    /// Number of advertising reports.
814    pub fn len(&self) -> usize {
815        usize::from(self.num_reports)
816    }
817
818    /// Create an iterator over the advertising reports.
819    pub fn iter(&self) -> LeExtAdvReportsIter<'_> {
820        LeExtAdvReportsIter {
821            len: self.len(),
822            bytes: &self.bytes,
823        }
824    }
825}
826
827/// An iterator for extended advertising reports.
828pub 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}