dot15d4_frame/ie/
nested.rs

1use super::{Error, Result};
2use crate::time::Duration;
3use bitflags::bitflags;
4
5/// A reader/writer for the IEEE 802.15.4 Nested Information Elements.
6///
7/// ## Short format
8/// ```notrust
9/// +--------+--------+--------+--------------------------+
10/// | Length | Sub-ID | Type=0 | Content (0-255 octets)...|
11/// +--------+--------+--------+--------------------------+
12/// ```
13///
14/// ## Long format
15/// ```notrust
16/// +--------+--------+--------+---------------------------+
17/// | Length | Sub-ID | Type=1 | Content (0-2046 octets)...|
18/// +--------+--------+--------+---------------------------+
19/// ```
20#[derive(Debug, PartialEq, Eq, Copy, Clone)]
21pub struct NestedInformationElement<T: AsRef<[u8]>> {
22    data: T,
23}
24
25impl<T: AsRef<[u8]>> NestedInformationElement<T> {
26    /// Create a new [`NestedInformationElement`] reader/writer from a given
27    /// buffer.
28    ///
29    /// # Errors
30    ///
31    /// Returns an error if the buffer is too short to contain the nested
32    /// information element.
33    pub fn new(data: T) -> Result<Self> {
34        let nested = Self::new_unchecked(data);
35
36        if !nested.check_len() {
37            return Err(Error);
38        }
39
40        Ok(nested)
41    }
42
43    /// Returns `false` if the buffer is too short to contain the nested
44    /// information element.
45    fn check_len(&self) -> bool {
46        if self.data.as_ref().len() < 2 {
47            return false;
48        }
49
50        let len = self.length();
51
52        self.data.as_ref().len() >= len + 2
53    }
54
55    /// Create a new [`NestedInformationElement`] reader/writer from a given
56    /// buffer without length checking.
57    pub fn new_unchecked(data: T) -> Self {
58        Self { data }
59    }
60
61    /// Return the length of the Nested Information Element in bytes.
62    pub fn length(&self) -> usize {
63        let b = &self.data.as_ref()[0..];
64        if self.is_long() {
65            (u16::from_le_bytes([b[0], b[1]]) & 0b1111111111) as usize
66        } else {
67            (u16::from_le_bytes([b[0], b[1]]) & 0b1111111) as usize
68        }
69    }
70
71    /// Return the [`NestedSubId`].
72    pub fn sub_id(&self) -> NestedSubId {
73        let b = &self.data.as_ref()[0..];
74        let id = u16::from_le_bytes([b[0], b[1]]);
75        if self.is_long() {
76            NestedSubId::Long(NestedSubIdLong::from(((id >> 11) & 0b1111) as u8))
77        } else {
78            NestedSubId::Short(NestedSubIdShort::from(((id >> 8) & 0b111111) as u8))
79        }
80    }
81
82    /// Returns `true` when the Nested Information Element is a short type.
83    pub fn is_short(&self) -> bool {
84        !self.is_long()
85    }
86
87    /// Returns `true` when the Nested Information Element is a long type.
88    pub fn is_long(&self) -> bool {
89        let b = &self.data.as_ref()[0..];
90        (u16::from_le_bytes([b[0], b[1]]) >> 15) & 0b1 == 0b1
91    }
92
93    /// Return the content of this Nested Information Element.
94    pub fn content(&self) -> &[u8] {
95        &self.data.as_ref()[2..][..self.length()]
96    }
97}
98
99impl<T: AsRef<[u8]> + AsMut<[u8]>> NestedInformationElement<T> {
100    /// Clear the content of this Nested Information Element.
101    pub fn clear(&mut self) {
102        self.data.as_mut().fill(0);
103    }
104
105    /// Set the length of the Nested Information Element.
106    pub fn set_length(&mut self, len: u16, id: NestedSubId) {
107        let mask: u16 = if id.is_short() {
108            0b0000_1111_1111
109        } else {
110            0b0111_1111_1111
111        };
112
113        let b = &mut self.data.as_mut()[0..2];
114        let value = u16::from_le_bytes([b[0], b[1]]) & !mask;
115        let value = value | (len & mask);
116        b[0..2].copy_from_slice(&value.to_le_bytes());
117    }
118
119    /// Set the [`NestedSubId`].
120    pub fn set_sub_id(&mut self, id: NestedSubId) {
121        let mask: u16 = if id.is_short() {
122            0b0111_1111_0000_0000
123        } else {
124            0b0111_1000_0000_0000
125        };
126
127        let b = &mut self.data.as_mut()[0..2];
128        let value = u16::from_le_bytes([b[0], b[1]]) & !mask;
129        let value = value
130            | match id {
131                NestedSubId::Short(id) => (id as u16) << 8,
132                NestedSubId::Long(id) => ((id as u16) << 11) | 0b1000_0000_0000_0000,
133            };
134        b[0..2].copy_from_slice(&value.to_le_bytes());
135    }
136
137    /// Return a mutable reference to the content of this Nested Information
138    pub fn content_mut(&mut self) -> &mut [u8] {
139        &mut self.data.as_mut()[2..]
140    }
141}
142
143impl<T: AsRef<[u8]>> core::fmt::Display for NestedInformationElement<T> {
144    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
145        match self.sub_id() {
146            NestedSubId::Short(id) => match id {
147                NestedSubIdShort::TschSynchronization => {
148                    let Ok(ts) = TschSynchronization::new(self.content()) else {
149                        return write!(f, "  {id}");
150                    };
151                    write!(f, "  {id} {ts}")
152                }
153                NestedSubIdShort::TschTimeslot => {
154                    let Ok(tt) = TschTimeslot::new(self.content()) else {
155                        return write!(f, "  {id}");
156                    };
157                    write!(f, "  {id} {tt}")
158                }
159                NestedSubIdShort::TschSlotframeAndLink => {
160                    let Ok(ts) = TschSlotframeAndLink::new(self.content()) else {
161                        return write!(f, "  {id}");
162                    };
163                    write!(f, "  {id} {ts}")
164                }
165                _ => write!(f, "  {:?}({:0x?})", id, self.content()),
166            },
167            NestedSubId::Long(id) => match id {
168                NestedSubIdLong::ChannelHopping => {
169                    let Ok(ch) = ChannelHopping::new(self.content()) else {
170                        return write!(f, "  {id}");
171                    };
172                    write!(f, "  {id} {ch}")
173                }
174                id => write!(f, "  {:?}({:0x?})", id, self.content()),
175            },
176        }
177    }
178}
179
180/// Nested Information Element ID.
181#[derive(Debug, PartialEq, Eq, Copy, Clone)]
182pub enum NestedSubId {
183    /// Short Nested Information Element ID.
184    Short(NestedSubIdShort),
185    /// Long Nested Information Element ID.
186    Long(NestedSubIdLong),
187}
188
189impl NestedSubId {
190    /// Create a short [`NestedSubId`] from a `u8`.
191    pub fn from_short(value: u8) -> Self {
192        Self::Short(NestedSubIdShort::from(value))
193    }
194
195    /// Create a long [`NestedSubId`] from a `u8`.
196    pub fn from_long(value: u8) -> Self {
197        Self::Long(NestedSubIdLong::from(value))
198    }
199
200    /// Returns `true` when the Nested Information Element is a short type.
201    pub fn is_short(&self) -> bool {
202        matches!(self, Self::Short(_))
203    }
204
205    /// Returns `true` when the Nested Information Element is a long type.
206    pub fn is_long(&self) -> bool {
207        matches!(self, Self::Long(_))
208    }
209}
210
211/// Short Nested Information Element ID.
212#[derive(Debug, PartialEq, Eq, Copy, Clone)]
213pub enum NestedSubIdShort {
214    /// TSCH Synchronization.
215    TschSynchronization = 0x1a,
216    /// TSCH Slotframe and Link.
217    TschSlotframeAndLink = 0x1b,
218    /// TSCH Timeslot.
219    TschTimeslot = 0x1c,
220    /// Hopping Timing.
221    HoppingTiming = 0x1d,
222    /// Enhanced Beacon Filter.
223    EnhancedBeaconFilter = 0x1e,
224    /// MAC Metrics.
225    MacMetrics = 0x1f,
226    /// All MAC Metrics.
227    AllMacMetrics = 0x20,
228    /// Coexistence Specification.
229    CoexistenceSpecification = 0x21,
230    /// Sun Device Capabilities.
231    SunDeviceCapabilities = 0x22,
232    /// Sun FSK Generic PHY.
233    SunFskGenericPhy = 0x23,
234    /// Mode Switch Parameter.
235    ModeSwitchParameter = 0x24,
236    /// PHY Parameter Change.
237    PhyParameterChange = 0x25,
238    /// O-QPSK PHY Mode.
239    OQpskPhyMode = 0x26,
240    /// PCA Allocation.
241    PcaAllocation = 0x27,
242    /// LECIM DSSS Operating Mode.
243    LecimDsssOperatingMode = 0x28,
244    /// LECIM FSK Operating Mode.
245    LecimFskOperatingMode = 0x29,
246    /// TVWS PHY Operating Mode.
247    TvwsPhyOperatingMode = 0x2b,
248    /// TVWS Device Capabilities.
249    TvwsDeviceCapabilities = 0x2c,
250    /// TVWS Device Category.
251    TvwsDeviceCategory = 0x2d,
252    /// TVWS Device Identification.
253    TvwsDeviceIdentification = 0x2e,
254    /// TVWS Device Location.
255    TvwsDeviceLocation = 0x2f,
256    /// TVWS Channel Information Query.
257    TvwsChannelInformationQuery = 0x30,
258    /// TVWS Channel Information Source.
259    TvwsChannelInformationSource = 0x31,
260    /// CTM.
261    Ctm = 0x32,
262    /// Timestamp.
263    Timestamp = 0x33,
264    /// Timestamp Difference.
265    TimestampDifference = 0x34,
266    /// TMCTP Specification.
267    TmctpSpecification = 0x35,
268    /// RCC PHY Operating Mode.
269    RccPhyOperatingMode = 0x36,
270    /// Link Margin.
271    LinkMargin = 0x37,
272    /// RS-GFSK Device Capabilities.
273    RsGfskDeviceCapabilities = 0x38,
274    /// Multi-PHY.
275    MultiPhy = 0x39,
276    /// Vendor Specific.
277    VendorSpecific = 0x40,
278    /// SRM.
279    Srm = 0x46,
280    /// Unknown.
281    Unkown,
282}
283
284impl From<u8> for NestedSubIdShort {
285    fn from(value: u8) -> Self {
286        match value {
287            0x1a => Self::TschSynchronization,
288            0x1b => Self::TschSlotframeAndLink,
289            0x1c => Self::TschTimeslot,
290            0x1d => Self::HoppingTiming,
291            0x1e => Self::EnhancedBeaconFilter,
292            0x1f => Self::MacMetrics,
293            0x20 => Self::AllMacMetrics,
294            0x21 => Self::CoexistenceSpecification,
295            0x22 => Self::SunDeviceCapabilities,
296            0x23 => Self::SunFskGenericPhy,
297            0x24 => Self::ModeSwitchParameter,
298            0x25 => Self::PhyParameterChange,
299            0x26 => Self::OQpskPhyMode,
300            0x27 => Self::PcaAllocation,
301            0x28 => Self::LecimDsssOperatingMode,
302            0x29 => Self::LecimFskOperatingMode,
303            0x2b => Self::TvwsPhyOperatingMode,
304            0x2c => Self::TvwsDeviceCapabilities,
305            0x2d => Self::TvwsDeviceCategory,
306            0x2e => Self::TvwsDeviceIdentification,
307            0x2f => Self::TvwsDeviceLocation,
308            0x30 => Self::TvwsChannelInformationQuery,
309            0x31 => Self::TvwsChannelInformationSource,
310            0x32 => Self::Ctm,
311            0x33 => Self::Timestamp,
312            0x34 => Self::TimestampDifference,
313            0x35 => Self::TmctpSpecification,
314            0x36 => Self::RccPhyOperatingMode,
315            0x37 => Self::LinkMargin,
316            0x38 => Self::RsGfskDeviceCapabilities,
317            0x39 => Self::MultiPhy,
318            0x40 => Self::VendorSpecific,
319            0x46 => Self::Srm,
320            _ => Self::Unkown,
321        }
322    }
323}
324
325impl core::fmt::Display for NestedSubIdShort {
326    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
327        match self {
328            Self::TschTimeslot => write!(f, "TSCH Timeslot"),
329            Self::TschSlotframeAndLink => write!(f, "TSCH Slotframe and Link"),
330            Self::TschSynchronization => write!(f, "TSCH Synchronization"),
331            _ => write!(f, "{:?}", self),
332        }
333    }
334}
335
336/// Long Nested Information Element ID.
337#[derive(Debug, PartialEq, Eq, Copy, Clone)]
338pub enum NestedSubIdLong {
339    /// Vendor Specific Nested Information Elements.
340    VendorSpecificNested = 0x08,
341    /// Channel Hopping.
342    ChannelHopping = 0x09,
343    /// Unnown.
344    Unkown,
345}
346
347impl From<u8> for NestedSubIdLong {
348    fn from(value: u8) -> Self {
349        match value {
350            0x08 => Self::VendorSpecificNested,
351            0x09 => Self::ChannelHopping,
352            _ => Self::Unkown,
353        }
354    }
355}
356
357impl core::fmt::Display for NestedSubIdLong {
358    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
359        match self {
360            Self::ChannelHopping => write!(f, "Channel Hopping"),
361            _ => write!(f, "{:?}", self),
362        }
363    }
364}
365
366/// A reader/writer for the TSCH synchronization IE.
367/// ```notrust
368/// +-----+-------------+
369/// | ASN | Join metric |
370/// +-----+-------------+
371/// 0     5             6
372/// ```
373#[derive(Debug, Clone, Copy, PartialEq, Eq)]
374pub struct TschSynchronization<T: AsRef<[u8]>> {
375    data: T,
376}
377
378impl<T: AsRef<[u8]>> TschSynchronization<T> {
379    /// Create a new [`TschSynchronization`] reader/writer from a given buffer.
380    pub fn new(data: T) -> Result<Self> {
381        let ts = Self::new_unchecked(data);
382
383        if !ts.check_len() {
384            return Err(Error);
385        }
386
387        Ok(ts)
388    }
389
390    /// Returns `false` if the buffer is too short to contain a valid TSCH
391    /// Synchronization IE.
392    fn check_len(&self) -> bool {
393        self.data.as_ref().len() >= 6
394    }
395
396    /// Create a new [`TschSynchronization`] reader/writer from a given buffer
397    /// without length checking.
398    pub fn new_unchecked(data: T) -> Self {
399        Self { data }
400    }
401
402    /// Return the absolute slot number field.
403    pub fn absolute_slot_number(&self) -> u64 {
404        let data = self.data.as_ref();
405        let mut asn = data[0] as u64;
406        asn += (data[1] as u64) << 8;
407        asn += (data[2] as u64) << 16;
408        asn += (data[3] as u64) << 24;
409        asn += (data[4] as u64) << 32;
410        asn
411    }
412
413    /// Return the join metric field.
414    pub fn join_metric(&self) -> u8 {
415        self.data.as_ref()[5]
416    }
417}
418
419impl<T: AsRef<[u8]> + AsMut<[u8]>> TschSynchronization<T> {
420    /// Set the absolute slot number field.
421    pub fn set_absolute_slot_number(&mut self, asn: u64) {
422        let data = self.data.as_mut();
423        data[0] = (asn & 0xff) as u8;
424        data[1] = ((asn >> 8) & 0xff) as u8;
425        data[2] = ((asn >> 16) & 0xff) as u8;
426        data[3] = ((asn >> 24) & 0xff) as u8;
427        data[4] = ((asn >> 32) & 0xff) as u8;
428    }
429
430    /// Set the join metric field.
431    pub fn set_join_metric(&mut self, join_metric: u8) {
432        self.data.as_mut()[5] = join_metric;
433    }
434}
435
436impl<T: AsRef<[u8]>> core::fmt::Display for TschSynchronization<T> {
437    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
438        write!(
439            f,
440            "ASN: {}, join metric: {}",
441            self.absolute_slot_number(),
442            self.join_metric()
443        )
444    }
445}
446
447/// A reader/writer for the TSCH timeslot IE.
448/// ```notrust
449/// +----+--------------------------+
450/// | ID | TSCH timeslot timings... |
451/// +----+--------------------------+
452/// 0    1
453/// ```
454#[derive(Debug, Clone, Copy, PartialEq, Eq)]
455pub struct TschTimeslot<T: AsRef<[u8]>> {
456    data: T,
457}
458
459impl<T: AsRef<[u8]>> TschTimeslot<T> {
460    /// The default timeslot ID.
461    pub const DEFAULT_ID: u8 = 0;
462
463    /// Create a new [`TschTimeslot`] reader/writer from a given buffer.
464    pub fn new(data: T) -> Result<Self> {
465        let ts = Self::new_unchecked(data);
466
467        if !ts.check_len() {
468            return Err(Error);
469        }
470
471        Ok(ts)
472    }
473
474    /// Returns `false` if the buffer is too short to contain a valid TSCH
475    /// Timeslot IE.
476    fn check_len(&self) -> bool {
477        let len = self.data.as_ref().len();
478
479        if len < 1 {
480            return false;
481        }
482
483        if self.id() == Self::DEFAULT_ID {
484            return len >= 1;
485        }
486
487        len >= 25
488    }
489
490    /// Create a new [`TschTimeslot`] reader/writer from a given buffer without
491    /// length checking.
492    pub fn new_unchecked(data: T) -> Self {
493        Self { data }
494    }
495
496    /// Return the TSCH timeslot ID field.
497    pub fn id(&self) -> u8 {
498        self.data.as_ref()[0]
499    }
500
501    /// Return the TSCH timeslot timings.
502    pub fn timeslot_timings(&self) -> TschTimeslotTimings {
503        if self.id() == Self::DEFAULT_ID {
504            TschTimeslotTimings::default()
505        } else {
506            TschTimeslotTimings {
507                id: self.id(),
508                cca_offset: Duration::from_us({
509                    let b = &self.data.as_ref()[1..][..2];
510                    u16::from_le_bytes([b[0], b[1]]) as i64
511                }),
512                cca: Duration::from_us({
513                    let b = &self.data.as_ref()[3..][..2];
514                    u16::from_le_bytes([b[0], b[1]]) as i64
515                }),
516                tx_offset: Duration::from_us({
517                    let b = &self.data.as_ref()[5..][..2];
518                    u16::from_le_bytes([b[0], b[1]]) as i64
519                }),
520                rx_offset: Duration::from_us({
521                    let b = &self.data.as_ref()[7..][..2];
522                    u16::from_le_bytes([b[0], b[1]]) as i64
523                }),
524                rx_ack_delay: Duration::from_us({
525                    let b = &self.data.as_ref()[9..][..2];
526                    u16::from_le_bytes([b[0], b[1]]) as i64
527                }),
528                tx_ack_delay: Duration::from_us({
529                    let b = &self.data.as_ref()[11..][..2];
530                    u16::from_le_bytes([b[0], b[1]]) as i64
531                }),
532                rx_wait: Duration::from_us({
533                    let b = &self.data.as_ref()[13..][..2];
534                    u16::from_le_bytes([b[0], b[1]]) as i64
535                }),
536                ack_wait: Duration::from_us({
537                    let b = &self.data.as_ref()[15..][..2];
538                    u16::from_le_bytes([b[0], b[1]]) as i64
539                }),
540                rx_tx: Duration::from_us({
541                    let b = &self.data.as_ref()[17..][..2];
542                    u16::from_le_bytes([b[0], b[1]]) as i64
543                }),
544                max_ack: Duration::from_us({
545                    let b = &self.data.as_ref()[19..][..2];
546                    u16::from_le_bytes([b[0], b[1]]) as i64
547                }),
548                max_tx: Duration::from_us({
549                    let len = if self.data.as_ref().len() == 25 { 2 } else { 3 };
550                    let b = &self.data.as_ref()[21..][..len];
551                    // TODO: handle the case where a 3 byte length is used.
552                    u16::from_le_bytes([b[0], b[1]]) as i64
553                }),
554                time_slot_length: Duration::from_us({
555                    let offset = if self.data.as_ref().len() == 25 {
556                        23
557                    } else {
558                        24
559                    };
560                    let len = if self.data.as_ref().len() == 25 { 2 } else { 3 };
561                    let b = &self.data.as_ref()[offset..][..len];
562                    // TODO: handle the case where a 3 byte length is used.
563                    u16::from_le_bytes([b[0], b[1]]) as i64
564                }),
565            }
566        }
567    }
568}
569
570impl<T: AsRef<[u8]> + AsMut<[u8]>> TschTimeslot<T> {
571    /// Set the TSCH timeslot ID field.
572    pub fn set_time_slot_id(&mut self, id: u8) {
573        self.data.as_mut()[0] = id;
574    }
575}
576
577impl<T: AsRef<[u8]>> core::fmt::Display for TschTimeslot<T> {
578    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
579        write!(f, "slot ID: {}", self.id())
580    }
581}
582
583/// A TSCH time slot timings (figure 6-30 in IEEE 802.15.4-2020).
584///
585/// If the time slot ID is 0, the default timings are used.
586///
587/// ```notrust
588/// +----+------------+-----+-----------+-----------+--------------+--------------+---------+----------+-------+---------+--------+------------------+
589/// | ID | CCA offset | CCA | TX offset | RX offset | RX ACK delay | TX ACK delay | RX wait | ACK wait | RX/TX | Max ACK | Max TX | Time slot length |
590/// +----+------------+-----+-----------+-----------+--------------+--------------+---------+----------+-------+---------+--------+------------------+
591/// ```
592#[derive(Debug)]
593pub struct TschTimeslotTimings {
594    id: u8,
595    /// Offset from the start of the time slot to the start of the CCA in
596    /// microseconds.
597    cca_offset: Duration,
598    /// Duration of the CCA in microseconds.
599    cca: Duration,
600    /// Radio turnaround time in microseconds.
601    rx_tx: Duration,
602
603    /// Offset from the start of the time slot to the start of the TX in
604    /// microseconds.
605    tx_offset: Duration,
606    /// Maximum transmission time for a frame in microseconds.
607    max_tx: Duration,
608    /// Wait time between the end of the TX and the start of the ACK RX in
609    /// microseconds.
610    rx_ack_delay: Duration,
611    /// Maximum time to wait for receiving an ACK.
612    ack_wait: Duration,
613
614    /// Offset from the start of the time slot to the start of the RX in
615    /// microseconds.
616    rx_offset: Duration,
617    /// Maximum time to wait for receiving a frame.
618    rx_wait: Duration,
619    /// Wait time between the end of the RX and the start of the ACK TX in
620    /// microseconds.
621    tx_ack_delay: Duration,
622    /// Maximum transmission time for an ACK in microseconds.
623    max_ack: Duration,
624
625    /// Length of the time slot in microseconds.
626    time_slot_length: Duration,
627}
628
629impl Default for TschTimeslotTimings {
630    fn default() -> Self {
631        Self::new(0, Self::DEFAULT_GUARD_TIME)
632    }
633}
634
635impl TschTimeslotTimings {
636    /// The default guard time (2200us) in microseconds.
637    pub const DEFAULT_GUARD_TIME: Duration = Duration::from_us(2200);
638
639    /// Create a new set of time slot timings.
640    pub fn new(id: u8, guard_time: Duration) -> Self {
641        Self {
642            id,
643            cca_offset: Duration::from_us(1800),
644            cca: Duration::from_us(128),
645            tx_offset: Duration::from_us(2120),
646            rx_offset: Duration::from_us(2120) - (guard_time / 2),
647            rx_ack_delay: Duration::from_us(800),
648            tx_ack_delay: Duration::from_us(1000),
649            rx_wait: guard_time,
650            ack_wait: Duration::from_us(400),
651            rx_tx: Duration::from_us(192),
652            max_ack: Duration::from_us(2400),
653            max_tx: Duration::from_us(4256),
654            time_slot_length: Duration::from_us(10000),
655        }
656    }
657
658    /// Return the CCA offset in microseconds.
659    pub const fn cca_offset(&self) -> Duration {
660        self.cca_offset
661    }
662
663    /// Set the CCA offset in microseconds.
664    pub fn set_cca_offset(&mut self, cca_offset: Duration) {
665        self.cca_offset = cca_offset;
666    }
667
668    /// Return the CCA duration in microseconds.
669    pub const fn cca(&self) -> Duration {
670        self.cca
671    }
672
673    /// Set the CCA duration in microseconds.
674    pub fn set_cca(&mut self, cca: Duration) {
675        self.cca = cca;
676    }
677
678    /// Return the TX offset in microseconds.
679    pub const fn tx_offset(&self) -> Duration {
680        self.tx_offset
681    }
682
683    /// Set the TX offset in microseconds.
684    pub fn set_tx_offset(&mut self, tx_offset: Duration) {
685        self.tx_offset = tx_offset;
686    }
687
688    /// Return the RX offset in microseconds.
689    pub const fn rx_offset(&self) -> Duration {
690        self.rx_offset
691    }
692
693    /// Set the RX offset in microseconds.
694    pub fn set_rx_offset(&mut self, rx_offset: Duration) {
695        self.rx_offset = rx_offset;
696    }
697
698    /// Return the RX ACK delay in microseconds.
699    pub const fn rx_ack_delay(&self) -> Duration {
700        self.rx_ack_delay
701    }
702
703    /// Set the RX ACK delay in microseconds.
704    pub fn set_rx_ack_delay(&mut self, rx_ack_delay: Duration) {
705        self.rx_ack_delay = rx_ack_delay;
706    }
707
708    /// Return the TX ACK delay in microseconds.
709    pub const fn tx_ack_delay(&self) -> Duration {
710        self.tx_ack_delay
711    }
712
713    /// Set the TX ACK delay in microseconds.
714    pub fn set_tx_ack_delay(&mut self, tx_ack_delay: Duration) {
715        self.tx_ack_delay = tx_ack_delay;
716    }
717
718    /// Return the RX wait in microseconds.
719    pub const fn rx_wait(&self) -> Duration {
720        self.rx_wait
721    }
722
723    /// Set the RX wait in microseconds.
724    pub fn set_rx_wait(&mut self, rx_wait: Duration) {
725        self.rx_wait = rx_wait;
726    }
727
728    /// Return the ACK wait in microseconds.
729    pub const fn ack_wait(&self) -> Duration {
730        self.ack_wait
731    }
732
733    /// Set the ACK wait in microseconds.
734    pub fn set_ack_wait(&mut self, ack_wait: Duration) {
735        self.ack_wait = ack_wait;
736    }
737
738    /// Return the RX/TX in microseconds.
739    pub const fn rx_tx(&self) -> Duration {
740        self.rx_tx
741    }
742
743    /// Set the RX/TX in microseconds.
744    pub fn set_rx_tx(&mut self, rx_tx: Duration) {
745        self.rx_tx = rx_tx;
746    }
747
748    /// Return the maximum ACK in microseconds.
749    pub const fn max_ack(&self) -> Duration {
750        self.max_ack
751    }
752
753    /// Set the maximum ACK in microseconds.
754    pub fn set_max_ack(&mut self, max_ack: Duration) {
755        self.max_ack = max_ack;
756    }
757
758    /// Return the maximum TX in microseconds.
759    pub const fn max_tx(&self) -> Duration {
760        self.max_tx
761    }
762
763    /// Set the maximum TX in microseconds.
764    pub fn set_max_tx(&mut self, max_tx: Duration) {
765        self.max_tx = max_tx;
766    }
767
768    /// Return the time slot length in microseconds.
769    pub const fn time_slot_length(&self) -> Duration {
770        self.time_slot_length
771    }
772
773    /// Set the time slot length in microseconds.
774    pub fn set_time_slot_length(&mut self, time_slot_length: Duration) {
775        self.time_slot_length = time_slot_length;
776    }
777
778    /// Emit the time slot timings into a buffer.
779    pub fn emit(&self, buffer: &mut [u8]) {
780        buffer[0] = self.id;
781        buffer[1..][..2].copy_from_slice(&(self.cca_offset.as_us() as u16).to_le_bytes());
782        buffer[3..][..2].copy_from_slice(&(self.cca.as_us() as u16).to_le_bytes());
783        buffer[5..][..2].copy_from_slice(&(self.tx_offset.as_us() as u16).to_le_bytes());
784        buffer[7..][..2].copy_from_slice(&(self.rx_offset.as_us() as u16).to_le_bytes());
785        buffer[9..][..2].copy_from_slice(&(self.rx_ack_delay.as_us() as u16).to_le_bytes());
786        buffer[11..][..2].copy_from_slice(&(self.tx_ack_delay.as_us() as u16).to_le_bytes());
787        buffer[13..][..2].copy_from_slice(&(self.rx_wait.as_us() as u16).to_le_bytes());
788        buffer[15..][..2].copy_from_slice(&(self.ack_wait.as_us() as u16).to_le_bytes());
789        buffer[17..][..2].copy_from_slice(&(self.rx_tx.as_us() as u16).to_le_bytes());
790        buffer[19..][..2].copy_from_slice(&(self.max_ack.as_us() as u16).to_le_bytes());
791
792        // TODO: handle the case where the buffer is too small
793        buffer[21..][..2].copy_from_slice(&(self.max_tx.as_us() as u16).to_le_bytes());
794        // TODO: handle the case where the buffer is too small
795        buffer[23..][..2].copy_from_slice(&(self.time_slot_length.as_us() as u16).to_le_bytes());
796    }
797
798    fn fmt(&self, indent: usize, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
799        writeln!(f, "{:indent$}cca_offset: {}", "", self.cca_offset(),)?;
800        writeln!(f, "{:indent$}cca: {}", "", self.cca(), indent = indent)?;
801        writeln!(f, "{:indent$}tx offset: {}", "", self.tx_offset(),)?;
802        writeln!(f, "{:indent$}rx offset: {}", "", self.rx_offset(),)?;
803        writeln!(
804            f,
805            "{:indent$}tx ack delay: {}",
806            "",
807            self.tx_ack_delay(),
808            indent = indent
809        )?;
810        writeln!(f, "{:indent$}rx ack delay: {}", "", self.rx_ack_delay(),)?;
811        writeln!(f, "{:indent$}rx wait: {}", "", self.rx_wait(),)?;
812        writeln!(f, "{:indent$}ack wait: {}", "", self.ack_wait(),)?;
813        writeln!(f, "{:indent$}rx/tx: {}", "", self.rx_tx(), indent = indent)?;
814        writeln!(f, "{:indent$}max ack: {}", "", self.max_ack(),)?;
815        writeln!(f, "{:indent$}max tx: {}", "", self.max_tx(),)?;
816        writeln!(
817            f,
818            "{:indent$}time slot length: {}",
819            "",
820            self.time_slot_length(),
821        )
822    }
823}
824
825impl core::fmt::Display for TschTimeslotTimings {
826    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
827        self.fmt(0, f)
828    }
829}
830
831/// A reader/writer for the TSCH slotframe and link IE.
832/// ```notrust
833/// +----------------------+--------------------------+
834/// | Number of slotframes | Slotframe descriptors... |
835/// +----------------------+--------------------------+
836/// 0                      1
837/// ```
838#[derive(Debug, Clone, Copy, PartialEq, Eq)]
839pub struct TschSlotframeAndLink<T: AsRef<[u8]>> {
840    data: T,
841}
842
843impl<T: AsRef<[u8]>> TschSlotframeAndLink<T> {
844    /// Create a new [`TschSlotframeAndLink`] reader/writer from a given buffer.
845    pub fn new(data: T) -> Result<Self> {
846        let ts = Self::new_unchecked(data);
847
848        if !ts.check_len() {
849            return Err(Error);
850        }
851
852        Ok(ts)
853    }
854
855    /// Returns `false` if the buffer is too short to contain a valid TSCH
856    /// Slotframe and Link IE.
857    fn check_len(&self) -> bool {
858        let len = self.data.as_ref().len();
859
860        if len < 1 {
861            return false;
862        }
863
864        let _number_of_slot_frames = self.number_of_slot_frames() as usize;
865        let slotframe_descriptors_len =
866            self.slotframe_descriptors().map(|d| d.len()).sum::<usize>();
867
868        len > slotframe_descriptors_len
869    }
870
871    /// Create a new [`TschSlotframeAndLink`] reader/writer from a given buffer
872    /// without length checking.
873    pub fn new_unchecked(data: T) -> Self {
874        Self { data }
875    }
876
877    /// Return the number of slotframes field.
878    pub fn number_of_slot_frames(&self) -> u8 {
879        self.data.as_ref()[0]
880    }
881
882    /// Returns an [`Iterator`] over the [`SlotframeDescriptor`]s.
883    pub fn slotframe_descriptors(&self) -> SlotframeDescriptorIterator {
884        SlotframeDescriptorIterator::new(
885            self.number_of_slot_frames() as usize,
886            &self.data.as_ref()[1..],
887        )
888    }
889}
890
891impl<T: AsRef<[u8]> + AsMut<[u8]>> TschSlotframeAndLink<T> {
892    /// Set the number of slotframes field.
893    pub fn set_number_of_slot_frames(&mut self, number_of_slot_frames: u8) {
894        self.data.as_mut()[0] = number_of_slot_frames;
895    }
896}
897
898impl<T: AsRef<[u8]>> core::fmt::Display for TschSlotframeAndLink<T> {
899    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
900        write!(f, "#slot frames: {}", self.number_of_slot_frames())
901    }
902}
903
904/// A reader/writer for the Slotframe Descriptor.
905/// ```notrust
906/// +--------+------+-------+---------------------+
907/// | Handle | Size | Links | Link descriptors... |
908/// +--------+------+-------+---------------------+
909/// 0        1      3       4
910/// ```
911pub struct SlotframeDescriptor<T: AsRef<[u8]>> {
912    data: T,
913}
914
915impl<T: AsRef<[u8]>> SlotframeDescriptor<T> {
916    /// Create a new [`SlotframeDescriptor`] reader/writer from a given buffer.
917    pub fn new(data: T) -> Result<Self> {
918        let descriptor = Self::new_unchecked(data);
919
920        if !descriptor.check_len() {
921            return Err(Error);
922        }
923
924        Ok(descriptor)
925    }
926
927    /// Returns `false` if the buffer is too short to contain a valid Slotframe
928    /// Descriptor.
929    fn check_len(&self) -> bool {
930        let len = self.data.as_ref().len();
931
932        if len < 4 {
933            return false;
934        }
935
936        len > 4 + (self.links() as usize * LinkDescriptor::<&[u8]>::len())
937    }
938
939    /// Create a new [`SlotframeDescriptor`] reader/writer from a given buffer
940    /// without length checking.
941    pub fn new_unchecked(data: T) -> Self {
942        Self { data }
943    }
944
945    /// Return the length of the Slotframe Descriptor in bytes.
946    #[allow(clippy::len_without_is_empty)]
947    pub fn len(&self) -> usize {
948        4 + (self.links() as usize) * 5
949    }
950
951    /// Return the handle field.
952    pub fn handle(&self) -> u8 {
953        self.data.as_ref()[0]
954    }
955
956    /// Return the size field.
957    pub fn size(&self) -> u16 {
958        let b = &self.data.as_ref()[1..][..2];
959        u16::from_le_bytes([b[0], b[1]])
960    }
961
962    /// Return the links field.
963    pub fn links(&self) -> u8 {
964        self.data.as_ref()[3]
965    }
966
967    /// Return the link descriptors.
968    pub fn link_descriptors(&self) -> LinkDescriptorIterator {
969        LinkDescriptorIterator::new(
970            &self.data.as_ref()[4..][..(self.links() as usize * LinkDescriptor::<&[u8]>::len())],
971        )
972    }
973}
974
975/// An [`Iterator`] over [`SlotframeDescriptor`].
976pub struct SlotframeDescriptorIterator<'f> {
977    data: &'f [u8],
978    offset: usize,
979    terminated: bool,
980    slotframes: usize,
981    slotframe_count: usize,
982}
983
984impl<'f> SlotframeDescriptorIterator<'f> {
985    /// Create a new [`SlotframeDescriptorIterator`].
986    pub fn new(slotframes: usize, data: &'f [u8]) -> Self {
987        let terminated = slotframes == 0;
988
989        Self {
990            data,
991            offset: 0,
992            terminated,
993            slotframes,
994            slotframe_count: 0,
995        }
996    }
997}
998
999impl<'f> Iterator for SlotframeDescriptorIterator<'f> {
1000    type Item = SlotframeDescriptor<&'f [u8]>;
1001
1002    fn next(&mut self) -> Option<Self::Item> {
1003        if self.terminated {
1004            return None;
1005        }
1006
1007        let Ok(descriptor) = SlotframeDescriptor::new(&self.data[self.offset..]) else {
1008            self.terminated = true;
1009            return None;
1010        };
1011
1012        self.slotframe_count += 1;
1013        self.offset += descriptor.len();
1014
1015        if self.offset >= self.data.as_ref().len() || self.slotframe_count >= self.slotframes {
1016            self.terminated = true;
1017        }
1018
1019        Some(descriptor)
1020    }
1021}
1022
1023/// A reader/writer for the Link Descriptor.
1024/// ```notrust
1025/// +----------+----------------+--------------+
1026/// | Timeslot | Channel offset | Link options |
1027/// +----------+----------------+--------------+
1028/// 0          2                4
1029/// ```
1030pub struct LinkDescriptor<T: AsRef<[u8]>> {
1031    data: T,
1032}
1033
1034impl<T: AsRef<[u8]>> LinkDescriptor<T> {
1035    /// Create a new [`LinkDescriptor`] reader/writer from a given buffer.
1036    pub fn new(data: T) -> Self {
1037        Self { data }
1038    }
1039
1040    /// Return the length of the Link Descriptor in bytes.
1041    pub const fn len() -> usize {
1042        5
1043    }
1044
1045    /// Return the timeslot field.
1046    pub fn timeslot(&self) -> u16 {
1047        let b = &self.data.as_ref()[0..][..2];
1048        u16::from_le_bytes([b[0], b[1]])
1049    }
1050
1051    /// Return the channel offset field.
1052    pub fn channel_offset(&self) -> u16 {
1053        let b = &self.data.as_ref()[2..][..2];
1054        u16::from_le_bytes([b[0], b[1]])
1055    }
1056
1057    /// Return the link options field.
1058    pub fn link_options(&self) -> TschLinkOption {
1059        TschLinkOption::from_bits_truncate(self.data.as_ref()[4])
1060    }
1061}
1062
1063/// An [`Iterator`] over [`LinkDescriptor`].
1064pub struct LinkDescriptorIterator<'f> {
1065    data: &'f [u8],
1066    offset: usize,
1067    terminated: bool,
1068}
1069
1070impl<'f> LinkDescriptorIterator<'f> {
1071    /// Create a new [`LinkDescriptorIterator`].
1072    pub fn new(data: &'f [u8]) -> Self {
1073        Self {
1074            data,
1075            offset: 0,
1076            terminated: false,
1077        }
1078    }
1079}
1080
1081impl<'f> Iterator for LinkDescriptorIterator<'f> {
1082    type Item = LinkDescriptor<&'f [u8]>;
1083
1084    fn next(&mut self) -> Option<Self::Item> {
1085        if self.terminated {
1086            return None;
1087        }
1088
1089        let descriptor = LinkDescriptor::new(&self.data[self.offset..]);
1090
1091        self.offset += LinkDescriptor::<&[u8]>::len();
1092        self.terminated = self.offset >= self.data.as_ref().len();
1093
1094        Some(descriptor)
1095    }
1096}
1097
1098bitflags! {
1099    /// TSCH link options bitfield.
1100    /// ```notrust
1101    /// +----+----+--------+--------------+----------+----------+
1102    /// | Tx | Rx | Shared | Time keeping | Priority | Reserved |
1103    /// +----+----+--------+--------------+----------+----------+
1104    /// ```
1105    #[derive(Copy, Clone)]
1106    pub struct TschLinkOption: u8 {
1107        /// Transmit.
1108        const Tx = 0b0000_0001;
1109        /// Receive.
1110        const Rx = 0b0000_0010;
1111        /// Shared.
1112        const Shared = 0b0000_0100;
1113        /// Time keeping.
1114        const TimeKeeping = 0b0000_1000;
1115        /// Priority.
1116        const Priority = 0b0001_0000;
1117    }
1118}
1119
1120impl core::fmt::Debug for TschLinkOption {
1121    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
1122        bitflags::parser::to_writer(self, f)
1123    }
1124}
1125
1126/// A reader/writer for the Channel Hopping IE.
1127/// ```notrust
1128/// +-------------+-----+
1129/// | Sequence ID | ... |
1130/// +-------------+-----+
1131/// 0             1
1132/// ```
1133#[derive(Debug, Clone, Copy, PartialEq, Eq)]
1134pub struct ChannelHopping<T: AsRef<[u8]>> {
1135    data: T,
1136}
1137
1138impl<T: AsRef<[u8]>> ChannelHopping<T> {
1139    /// Create a new [`ChannelHopping`] reader/writer from a given buffer.
1140    ///
1141    /// # Errors
1142    ///
1143    /// Returns an error if the buffer is too small.
1144    pub fn new(data: T) -> Result<Self> {
1145        let ts = Self::new_unchecked(data);
1146
1147        if !ts.check_len() {
1148            return Err(Error);
1149        }
1150
1151        Ok(ts)
1152    }
1153
1154    /// Return `false` if the buffer is too small.
1155    fn check_len(&self) -> bool {
1156        !self.data.as_ref().is_empty()
1157    }
1158
1159    /// Create a new [`ChannelHopping`] reader/writer from a given buffer
1160    /// without checking the length.
1161    pub fn new_unchecked(data: T) -> Self {
1162        Self { data }
1163    }
1164
1165    /// Return the hopping sequence ID field.
1166    pub fn hopping_sequence_id(&self) -> u8 {
1167        self.data.as_ref()[0]
1168    }
1169}
1170
1171impl<T: AsRef<[u8]> + AsMut<[u8]>> ChannelHopping<T> {
1172    /// Set the hopping sequence ID field.
1173    pub fn set_hopping_sequence_id(&mut self, id: u8) {
1174        self.data.as_mut()[0] = id;
1175    }
1176}
1177
1178impl<T: AsRef<[u8]>> core::fmt::Display for ChannelHopping<T> {
1179    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
1180        write!(f, "sequence ID: {}", self.hopping_sequence_id())
1181    }
1182}
1183
1184/// An [`Iterator`] over [`NestedInformationElement`].
1185#[derive(Debug, PartialEq, Eq, Copy, Clone)]
1186pub struct NestedInformationElementsIterator<'f> {
1187    data: &'f [u8],
1188    offset: usize,
1189    terminated: bool,
1190}
1191
1192impl<'f> NestedInformationElementsIterator<'f> {
1193    /// Create a new [`NestedInformationElementsIterator`].
1194    pub fn new(data: &'f [u8]) -> Self {
1195        Self {
1196            data,
1197            offset: 0,
1198            terminated: false,
1199        }
1200    }
1201}
1202
1203impl<'f> Iterator for NestedInformationElementsIterator<'f> {
1204    type Item = NestedInformationElement<&'f [u8]>;
1205
1206    fn next(&mut self) -> Option<Self::Item> {
1207        if self.terminated {
1208            None
1209        } else {
1210            let Ok(nested) = NestedInformationElement::new(&self.data[self.offset..]) else {
1211                self.terminated = true;
1212                return None;
1213            };
1214            let len = nested.length() + 2;
1215
1216            let nested = NestedInformationElement {
1217                data: &self.data[self.offset..][..len],
1218            };
1219
1220            self.offset += len;
1221
1222            if self.offset >= self.data.len() {
1223                self.terminated = true;
1224            }
1225
1226            Some(nested)
1227        }
1228    }
1229}