1use super::{Error, Result};
2use crate::time::Duration;
3use bitflags::bitflags;
4
5#[derive(Debug, PartialEq, Eq, Copy, Clone)]
21pub struct NestedInformationElement<T: AsRef<[u8]>> {
22 data: T,
23}
24
25impl<T: AsRef<[u8]>> NestedInformationElement<T> {
26 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 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 pub fn new_unchecked(data: T) -> Self {
58 Self { data }
59 }
60
61 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 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 pub fn is_short(&self) -> bool {
84 !self.is_long()
85 }
86
87 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 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 pub fn clear(&mut self) {
102 self.data.as_mut().fill(0);
103 }
104
105 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 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 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#[derive(Debug, PartialEq, Eq, Copy, Clone)]
182pub enum NestedSubId {
183 Short(NestedSubIdShort),
185 Long(NestedSubIdLong),
187}
188
189impl NestedSubId {
190 pub fn from_short(value: u8) -> Self {
192 Self::Short(NestedSubIdShort::from(value))
193 }
194
195 pub fn from_long(value: u8) -> Self {
197 Self::Long(NestedSubIdLong::from(value))
198 }
199
200 pub fn is_short(&self) -> bool {
202 matches!(self, Self::Short(_))
203 }
204
205 pub fn is_long(&self) -> bool {
207 matches!(self, Self::Long(_))
208 }
209}
210
211#[derive(Debug, PartialEq, Eq, Copy, Clone)]
213pub enum NestedSubIdShort {
214 TschSynchronization = 0x1a,
216 TschSlotframeAndLink = 0x1b,
218 TschTimeslot = 0x1c,
220 HoppingTiming = 0x1d,
222 EnhancedBeaconFilter = 0x1e,
224 MacMetrics = 0x1f,
226 AllMacMetrics = 0x20,
228 CoexistenceSpecification = 0x21,
230 SunDeviceCapabilities = 0x22,
232 SunFskGenericPhy = 0x23,
234 ModeSwitchParameter = 0x24,
236 PhyParameterChange = 0x25,
238 OQpskPhyMode = 0x26,
240 PcaAllocation = 0x27,
242 LecimDsssOperatingMode = 0x28,
244 LecimFskOperatingMode = 0x29,
246 TvwsPhyOperatingMode = 0x2b,
248 TvwsDeviceCapabilities = 0x2c,
250 TvwsDeviceCategory = 0x2d,
252 TvwsDeviceIdentification = 0x2e,
254 TvwsDeviceLocation = 0x2f,
256 TvwsChannelInformationQuery = 0x30,
258 TvwsChannelInformationSource = 0x31,
260 Ctm = 0x32,
262 Timestamp = 0x33,
264 TimestampDifference = 0x34,
266 TmctpSpecification = 0x35,
268 RccPhyOperatingMode = 0x36,
270 LinkMargin = 0x37,
272 RsGfskDeviceCapabilities = 0x38,
274 MultiPhy = 0x39,
276 VendorSpecific = 0x40,
278 Srm = 0x46,
280 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#[derive(Debug, PartialEq, Eq, Copy, Clone)]
338pub enum NestedSubIdLong {
339 VendorSpecificNested = 0x08,
341 ChannelHopping = 0x09,
343 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#[derive(Debug, Clone, Copy, PartialEq, Eq)]
374pub struct TschSynchronization<T: AsRef<[u8]>> {
375 data: T,
376}
377
378impl<T: AsRef<[u8]>> TschSynchronization<T> {
379 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 fn check_len(&self) -> bool {
393 self.data.as_ref().len() >= 6
394 }
395
396 pub fn new_unchecked(data: T) -> Self {
399 Self { data }
400 }
401
402 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 pub fn join_metric(&self) -> u8 {
415 self.data.as_ref()[5]
416 }
417}
418
419impl<T: AsRef<[u8]> + AsMut<[u8]>> TschSynchronization<T> {
420 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 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#[derive(Debug, Clone, Copy, PartialEq, Eq)]
455pub struct TschTimeslot<T: AsRef<[u8]>> {
456 data: T,
457}
458
459impl<T: AsRef<[u8]>> TschTimeslot<T> {
460 pub const DEFAULT_ID: u8 = 0;
462
463 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 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 pub fn new_unchecked(data: T) -> Self {
493 Self { data }
494 }
495
496 pub fn id(&self) -> u8 {
498 self.data.as_ref()[0]
499 }
500
501 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 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 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 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#[derive(Debug)]
593pub struct TschTimeslotTimings {
594 id: u8,
595 cca_offset: Duration,
598 cca: Duration,
600 rx_tx: Duration,
602
603 tx_offset: Duration,
606 max_tx: Duration,
608 rx_ack_delay: Duration,
611 ack_wait: Duration,
613
614 rx_offset: Duration,
617 rx_wait: Duration,
619 tx_ack_delay: Duration,
622 max_ack: Duration,
624
625 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 pub const DEFAULT_GUARD_TIME: Duration = Duration::from_us(2200);
638
639 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 pub const fn cca_offset(&self) -> Duration {
660 self.cca_offset
661 }
662
663 pub fn set_cca_offset(&mut self, cca_offset: Duration) {
665 self.cca_offset = cca_offset;
666 }
667
668 pub const fn cca(&self) -> Duration {
670 self.cca
671 }
672
673 pub fn set_cca(&mut self, cca: Duration) {
675 self.cca = cca;
676 }
677
678 pub const fn tx_offset(&self) -> Duration {
680 self.tx_offset
681 }
682
683 pub fn set_tx_offset(&mut self, tx_offset: Duration) {
685 self.tx_offset = tx_offset;
686 }
687
688 pub const fn rx_offset(&self) -> Duration {
690 self.rx_offset
691 }
692
693 pub fn set_rx_offset(&mut self, rx_offset: Duration) {
695 self.rx_offset = rx_offset;
696 }
697
698 pub const fn rx_ack_delay(&self) -> Duration {
700 self.rx_ack_delay
701 }
702
703 pub fn set_rx_ack_delay(&mut self, rx_ack_delay: Duration) {
705 self.rx_ack_delay = rx_ack_delay;
706 }
707
708 pub const fn tx_ack_delay(&self) -> Duration {
710 self.tx_ack_delay
711 }
712
713 pub fn set_tx_ack_delay(&mut self, tx_ack_delay: Duration) {
715 self.tx_ack_delay = tx_ack_delay;
716 }
717
718 pub const fn rx_wait(&self) -> Duration {
720 self.rx_wait
721 }
722
723 pub fn set_rx_wait(&mut self, rx_wait: Duration) {
725 self.rx_wait = rx_wait;
726 }
727
728 pub const fn ack_wait(&self) -> Duration {
730 self.ack_wait
731 }
732
733 pub fn set_ack_wait(&mut self, ack_wait: Duration) {
735 self.ack_wait = ack_wait;
736 }
737
738 pub const fn rx_tx(&self) -> Duration {
740 self.rx_tx
741 }
742
743 pub fn set_rx_tx(&mut self, rx_tx: Duration) {
745 self.rx_tx = rx_tx;
746 }
747
748 pub const fn max_ack(&self) -> Duration {
750 self.max_ack
751 }
752
753 pub fn set_max_ack(&mut self, max_ack: Duration) {
755 self.max_ack = max_ack;
756 }
757
758 pub const fn max_tx(&self) -> Duration {
760 self.max_tx
761 }
762
763 pub fn set_max_tx(&mut self, max_tx: Duration) {
765 self.max_tx = max_tx;
766 }
767
768 pub const fn time_slot_length(&self) -> Duration {
770 self.time_slot_length
771 }
772
773 pub fn set_time_slot_length(&mut self, time_slot_length: Duration) {
775 self.time_slot_length = time_slot_length;
776 }
777
778 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 buffer[21..][..2].copy_from_slice(&(self.max_tx.as_us() as u16).to_le_bytes());
794 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#[derive(Debug, Clone, Copy, PartialEq, Eq)]
839pub struct TschSlotframeAndLink<T: AsRef<[u8]>> {
840 data: T,
841}
842
843impl<T: AsRef<[u8]>> TschSlotframeAndLink<T> {
844 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 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 pub fn new_unchecked(data: T) -> Self {
874 Self { data }
875 }
876
877 pub fn number_of_slot_frames(&self) -> u8 {
879 self.data.as_ref()[0]
880 }
881
882 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 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
904pub struct SlotframeDescriptor<T: AsRef<[u8]>> {
912 data: T,
913}
914
915impl<T: AsRef<[u8]>> SlotframeDescriptor<T> {
916 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 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 pub fn new_unchecked(data: T) -> Self {
942 Self { data }
943 }
944
945 #[allow(clippy::len_without_is_empty)]
947 pub fn len(&self) -> usize {
948 4 + (self.links() as usize) * 5
949 }
950
951 pub fn handle(&self) -> u8 {
953 self.data.as_ref()[0]
954 }
955
956 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 pub fn links(&self) -> u8 {
964 self.data.as_ref()[3]
965 }
966
967 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
975pub 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 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
1023pub struct LinkDescriptor<T: AsRef<[u8]>> {
1031 data: T,
1032}
1033
1034impl<T: AsRef<[u8]>> LinkDescriptor<T> {
1035 pub fn new(data: T) -> Self {
1037 Self { data }
1038 }
1039
1040 pub const fn len() -> usize {
1042 5
1043 }
1044
1045 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 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 pub fn link_options(&self) -> TschLinkOption {
1059 TschLinkOption::from_bits_truncate(self.data.as_ref()[4])
1060 }
1061}
1062
1063pub struct LinkDescriptorIterator<'f> {
1065 data: &'f [u8],
1066 offset: usize,
1067 terminated: bool,
1068}
1069
1070impl<'f> LinkDescriptorIterator<'f> {
1071 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 #[derive(Copy, Clone)]
1106 pub struct TschLinkOption: u8 {
1107 const Tx = 0b0000_0001;
1109 const Rx = 0b0000_0010;
1111 const Shared = 0b0000_0100;
1113 const TimeKeeping = 0b0000_1000;
1115 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#[derive(Debug, Clone, Copy, PartialEq, Eq)]
1134pub struct ChannelHopping<T: AsRef<[u8]>> {
1135 data: T,
1136}
1137
1138impl<T: AsRef<[u8]>> ChannelHopping<T> {
1139 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 fn check_len(&self) -> bool {
1156 !self.data.as_ref().is_empty()
1157 }
1158
1159 pub fn new_unchecked(data: T) -> Self {
1162 Self { data }
1163 }
1164
1165 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 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#[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 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}