1use crate::time::Duration;
4use crate::{Error, Result};
5use dot15d4_macros::frame;
6
7#[derive(Debug, Eq, PartialEq, Clone, Copy)]
9pub struct HeaderInformationElement<T: AsRef<[u8]>> {
10 data: T,
11}
12
13impl<T: AsRef<[u8]>> HeaderInformationElement<T> {
14 pub fn new(data: T) -> Result<Self> {
21 let ie = Self::new_unchecked(data);
22
23 if !ie.check_len() {
24 return Err(Error);
25 }
26
27 Ok(ie)
28 }
29
30 fn check_len(&self) -> bool {
33 self.data.as_ref().len() >= 2
34 }
35
36 pub fn new_unchecked(data: T) -> Self {
39 Self { data }
40 }
41
42 #[must_use]
44 pub fn is_empty(&self) -> bool {
45 self.len() == 0
46 }
47
48 pub fn len(&self) -> usize {
50 let b = &self.data.as_ref()[0..2];
51 u16::from_le_bytes([b[0], b[1]]) as usize & 0b1111_1110
52 }
53
54 pub fn element_id(&self) -> HeaderElementId {
56 let b = &self.data.as_ref()[0..2];
57 let id = (u16::from_le_bytes([b[0], b[1]]) >> 7) & 0b1111_1111;
58 HeaderElementId::from(id as u8)
59 }
60
61 pub fn content(&self) -> &[u8] {
63 &self.data.as_ref()[2..][..self.len()]
64 }
65}
66
67impl<T: AsRef<[u8]> + AsMut<[u8]>> HeaderInformationElement<T> {
68 pub fn clear(&mut self) {
70 self.data.as_mut().fill(0);
71 }
72
73 pub fn set_length(&mut self, len: u16) {
75 const MASK: u16 = 0b1111_1110;
76
77 let b = &mut self.data.as_mut()[0..2];
78 let value = u16::from_le_bytes([b[0], b[1]]) & !MASK;
79 let value = value | (len & MASK);
80 b[0..2].copy_from_slice(&value.to_le_bytes());
81 }
82
83 pub fn set_element_id(&mut self, id: HeaderElementId) {
85 const SHIFT: u16 = 7;
86 const MASK: u16 = 0b0111_1111_1000_0000;
87
88 let b = &mut self.data.as_mut()[0..2];
89 let value = u16::from_le_bytes([b[0], b[1]]) & !MASK;
90 let value = value | (((id as u16) << SHIFT) & MASK);
91 b[0..2].copy_from_slice(&value.to_le_bytes());
92 }
93
94 pub fn content_mut(&mut self) -> &mut [u8] {
96 &mut self.data.as_mut()[2..]
97 }
98}
99
100impl<T: AsRef<[u8]>> core::fmt::Display for HeaderInformationElement<T> {
101 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
102 let id = self.element_id();
103 match id {
104 HeaderElementId::HeaderTermination1 | HeaderElementId::HeaderTermination2 => {
105 write!(f, "{:?}", id)
106 }
107 HeaderElementId::SimplifiedSuperframeSpecification => {
108 write!(
109 f,
110 "{} {:?}",
111 id,
112 SimplifiedSuperframeSpecification::new(self.content())
113 )
114 }
115 HeaderElementId::TimeCorrection => {
116 let Ok(tc) = TimeCorrection::new(self.content()) else {
117 return write!(f, "{:?}({:0x?})", id, self.content());
118 };
119 write!(f, "{} {}", id, tc)
120 }
121 id => write!(f, "{:?}({:0x?})", id, self.content()),
122 }
123 }
124}
125
126#[derive(Debug, Eq, PartialEq, Clone, Copy)]
128pub enum HeaderElementId {
129 VendorSpecificHeader = 0x00,
131 Csl = 0x1a,
133 Rit = 0x1b,
135 DsmePanDescriptor = 0x1c,
137 RendezvousTime = 0x1d,
139 TimeCorrection = 0x1e,
141 ExtendedDsmePanDescriptor = 0x21,
143 FragmentSequenceContextDescription = 0x22,
145 SimplifiedSuperframeSpecification = 0x23,
147 SimplifiedGtsSpecification = 0x24,
149 LecimCapabilities = 0x25,
151 TrleDescriptor = 0x26,
153 RccCapabilities = 0x27,
155 RccnDescriptor = 0x28,
157 GlobalTime = 0x29,
159 Da = 0x2b,
161 HeaderTermination1 = 0x7e,
163 HeaderTermination2 = 0x7f,
165 Unkown,
167}
168
169impl From<u8> for HeaderElementId {
170 fn from(value: u8) -> Self {
171 match value {
172 0x00 => Self::VendorSpecificHeader,
173 0x1a => Self::Csl,
174 0x1b => Self::Rit,
175 0x1c => Self::DsmePanDescriptor,
176 0x1d => Self::RendezvousTime,
177 0x1e => Self::TimeCorrection,
178 0x21 => Self::ExtendedDsmePanDescriptor,
179 0x22 => Self::FragmentSequenceContextDescription,
180 0x23 => Self::SimplifiedSuperframeSpecification,
181 0x24 => Self::SimplifiedGtsSpecification,
182 0x25 => Self::LecimCapabilities,
183 0x26 => Self::TrleDescriptor,
184 0x27 => Self::RccCapabilities,
185 0x28 => Self::RccnDescriptor,
186 0x29 => Self::GlobalTime,
187 0x2b => Self::Da,
188 0x7e => Self::HeaderTermination1,
189 0x7f => Self::HeaderTermination2,
190 _ => Self::Unkown,
191 }
192 }
193}
194
195impl core::fmt::Display for HeaderElementId {
196 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
197 match self {
198 Self::TimeCorrection => write!(f, "Time Correction"),
199 _ => write!(f, "{:?}", self),
200 }
201 }
202}
203
204#[derive(Debug)]
206pub struct HeaderInformationElementsIterator<'f> {
207 pub(crate) data: &'f [u8],
208 pub(crate) offset: usize,
209 pub(crate) terminated: bool,
210}
211
212impl HeaderInformationElementsIterator<'_> {
213 pub fn offset(&self) -> usize {
215 self.offset
216 }
217}
218
219impl<'f> Iterator for HeaderInformationElementsIterator<'f> {
220 type Item = HeaderInformationElement<&'f [u8]>;
221
222 fn next(&mut self) -> Option<Self::Item> {
223 if self.terminated {
224 None
225 } else {
226 let ie = HeaderInformationElement::new(&self.data[self.offset..]).ok()?;
227
228 self.terminated = matches!(
229 ie.element_id(),
230 HeaderElementId::HeaderTermination1 | HeaderElementId::HeaderTermination2
231 );
232
233 self.offset += ie.len() + 2;
234
235 if self.offset >= self.data.len() {
236 self.terminated = true;
237 }
238
239 Some(ie)
240 }
241 }
242}
243
244#[frame]
246#[derive(Debug)]
247pub struct VendorSpecific {
248 #[bytes(3)]
249 vendor_oui: u32,
251
252 #[bytes(0)]
253 vendor_specific_payload: &[u8],
255}
256
257#[frame]
259#[derive(Debug)]
260pub struct Csl {
261 csl_phase: u16,
263 csl_period: u16,
265 #[condition(self.buffer.as_ref().len() > 4)]
266 rendezvous_time: u16,
268}
269
270#[frame]
272#[derive(Debug)]
273pub struct Rit {
274 time_to_first_listen: u8,
276 number_of_repeat_listen: u8,
278 repeat_listen_interval: u16,
280}
281
282#[frame]
284pub struct DsmeSuperframeSpecification {
285 #[bits(4)]
286 multi_superframe_order: u8,
288 #[bits(1)]
289 channel_diversity_mode: bool,
291 #[bits(1)]
292 _reserved: bool,
293 #[bits(1)]
294 cap_reduction: bool,
296 #[bits(1)]
297 deferred_beacon: bool,
299}
300
301#[frame]
303pub struct TimeSynchronizationSpecification {
304 #[bytes(8)]
305 beacon_timestamp: &[u8],
308 beacon_offset_timestamp: u16,
310}
311
312#[frame]
314pub struct ChannelHoppingSpecification {
315 hopping_sequence_id: u8,
317 pan_coordinator_bsn: u8,
319 channel_offset: u16,
321 channel_offset_bitmap_length: u8,
323 #[bytes(0)]
324 channel_offset_bitmap: &[u8],
326}
327
328#[frame]
330pub struct RendezvousTime {
331 rendezvous_time: u16,
333 wake_up_interval: u16,
335}
336
337pub struct TimeCorrection<T: AsRef<[u8]>> {
340 buffer: T,
341}
342
343impl<T: AsRef<[u8]>> TimeCorrection<T> {
344 pub fn new(buffer: T) -> Result<Self> {
350 let ie = Self::new_unchecked(buffer);
351
352 if !ie.check_len() {
353 return Err(Error);
354 }
355
356 Ok(ie)
357 }
358
359 fn check_len(&self) -> bool {
362 self.buffer.as_ref().len() >= 2
363 }
364
365 pub fn new_unchecked(buffer: T) -> Self {
368 Self { buffer }
369 }
370
371 #[allow(clippy::len_without_is_empty)]
372 pub const fn len(&self) -> usize {
374 2
375 }
376
377 pub fn time_correction(&self) -> Duration {
379 let b = &self.buffer.as_ref()[0..2];
380 let time = ((u16::from_le_bytes([b[0], b[1]]) & 0x0fff) << 4) as i16;
381 Duration::from_us((time >> 4) as i64)
382 }
383
384 pub fn nack(&self) -> bool {
386 let b = &self.buffer.as_ref()[0..2];
387 i16::from_le_bytes([b[0], b[1]]) & (0x8000u16 as i16) != 0
388 }
389}
390
391impl<T: AsRef<[u8]> + AsMut<[u8]>> TimeCorrection<T> {
392 pub fn set_time_correction(&mut self, time_correction: Duration) {
394 let time = (((time_correction.as_us() as i16) << 4) >> 4) & 0x0fff;
395 let b = &mut self.buffer.as_mut()[0..2];
396 b[0..2].copy_from_slice(&time.to_le_bytes());
397 }
398
399 pub fn set_nack(&mut self, nack: bool) {
401 let b = &mut self.buffer.as_mut()[0..2];
402 let value = i16::from_le_bytes([b[0], b[1]]);
403 if nack {
404 b[0..2].copy_from_slice(&((value | (0x8000_u16 as i16)) as u16).to_le_bytes());
405 } else {
406 b[0..2].copy_from_slice(&((value & 0x7fff) as u16).to_le_bytes());
407 }
408 }
409}
410
411impl<T: AsRef<[u8]>> core::fmt::Display for TimeCorrection<T> {
412 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
413 write!(
414 f,
415 "{}, nack: {}",
416 self.time_correction(),
417 self.nack() as usize
418 )
419 }
420}
421
422#[frame]
423#[derive(Debug)]
424pub struct SimplifiedSuperframeSpecification {
427 timestamp: u16,
429 #[bytes(2)]
430 superframe_specification: SuperframeSpecification,
432 #[bytes(2)]
433 cfp_specification: CfpSpecification,
435}
436
437#[frame]
438#[derive(Debug)]
439pub struct SuperframeSpecification {
442 #[bits(4)]
444 #[into(BeaconOrder)]
445 beacon_order: u8,
446 #[bits(4)]
448 #[into(SuperframeOrder)]
449 superframe_order: u8,
450 #[bits(4)]
451 final_cap_slot: u8,
453 #[bits(1)]
454 battery_life_extension: bool,
456 #[bits(1)]
457 _reserved: bool,
458 #[bits(1)]
459 pan_coordinator: bool,
461 #[bits(1)]
462 association_permit: bool,
464}
465
466#[derive(Debug, Eq, PartialEq, Clone, Copy)]
467#[repr(u8)]
468pub enum BeaconOrder {
470 Order(u8),
473 OnDemand,
475}
476
477impl From<u8> for BeaconOrder {
478 fn from(value: u8) -> Self {
479 match value {
480 value @ 0..=14 => Self::Order(value),
481 _ => Self::OnDemand,
482 }
483 }
484}
485impl From<BeaconOrder> for u8 {
486 fn from(value: BeaconOrder) -> Self {
487 match value {
488 BeaconOrder::Order(value) => value,
489 BeaconOrder::OnDemand => 15,
490 }
491 }
492}
493
494#[derive(Debug, Eq, PartialEq, Clone, Copy)]
495#[repr(u8)]
496pub enum SuperframeOrder {
498 Order(u8),
501 Inactive,
503}
504
505impl From<u8> for SuperframeOrder {
506 fn from(value: u8) -> Self {
507 match value {
508 value @ 0..=14 => Self::Order(value),
509 _ => Self::Inactive,
510 }
511 }
512}
513impl From<SuperframeOrder> for u8 {
514 fn from(value: SuperframeOrder) -> Self {
515 match value {
516 SuperframeOrder::Order(value) => value,
517 SuperframeOrder::Inactive => 15,
518 }
519 }
520}
521
522#[frame]
523#[derive(Debug)]
524pub struct CfpSpecification {
527 #[bits(3)]
528 gts_count: u8,
530 #[bits(5)]
531 first_cfp_slot: u8,
533 #[bits(4)]
534 last_cfp_slot: u8,
536 #[bits(1)]
537 gts_permit: bool,
539}
540
541#[frame]
542#[derive(Debug)]
543pub struct GtsSpecification {
545 #[bits(3)]
546 descriptor_count: u8,
548 #[bits(4)]
549 _reserved: u8,
550 #[bits(1)]
552 gts_permit: bool,
553}
554
555#[frame(no_constructor)]
557pub struct GtsSlot {
558 #[bytes(2)]
560 #[into(crate::Address)]
561 short_address: &[u8],
562 #[bits(4)]
564 starting_slot: u8,
565 #[bits(4)]
567 length: u8,
568
569 #[field]
571 direction: GtsDirection,
572}
573
574impl<T: AsRef<[u8]>> GtsSlot<T> {
575 pub fn new(buffer: T, direction: GtsDirection) -> Result<Self> {
577 let s = Self::new_unchecked(buffer, direction);
578
579 if !s.check_len() {
580 return Err(Error);
581 }
582
583 Ok(s)
584 }
585
586 fn check_len(&self) -> bool {
588 self.buffer.as_ref().len() >= Self::size()
589 }
590
591 pub fn new_unchecked(buffer: T, direction: GtsDirection) -> Self {
594 Self { buffer, direction }
595 }
596}
597
598impl<T: AsRef<[u8]>> GtsSpecification<T> {
599 pub fn slots(&self) -> GtsSlotIterator {
601 if self.descriptor_count() == 0 {
602 GtsSlotIterator {
603 data: &[],
604 count: 0,
605 terminated: true,
606 }
607 } else {
608 GtsSlotIterator {
609 data: &self.buffer.as_ref()[1..]
610 [..1 + self.descriptor_count() as usize * GtsSlot::<T>::size()],
611 count: 0,
612 terminated: false,
613 }
614 }
615 }
616}
617
618pub struct GtsSlotIterator<'f> {
620 data: &'f [u8],
621 count: usize,
622 terminated: bool,
623}
624
625impl<'f> Iterator for GtsSlotIterator<'f> {
626 type Item = GtsSlot<&'f [u8]>;
627
628 fn next(&mut self) -> Option<Self::Item> {
629 if self.terminated {
630 None
631 } else {
632 const L: usize = GtsSlot::<&[u8]>::size();
633 if 1 + self.count * L >= self.data.len() {
634 return None;
635 }
636
637 let direction = GtsDirection::from((self.data[0] >> self.count) & 0b1);
638 let descriptor = GtsSlot::new(&self.data[1 + self.count * L..], direction).ok()?;
639
640 self.count += 1;
641 if 1 + self.count * L >= self.data.len() {
642 self.terminated = true;
643 }
644
645 Some(descriptor)
646 }
647 }
648}
649
650#[derive(Debug, Eq, PartialEq, Clone, Copy)]
652#[repr(u8)]
653pub enum GtsDirection {
654 Receive,
656 Transmit,
658}
659
660impl From<u8> for GtsDirection {
661 fn from(value: u8) -> Self {
662 match value {
663 0b0 => Self::Receive,
664 _ => Self::Transmit,
665 }
666 }
667}
668
669impl From<GtsDirection> for u8 {
670 fn from(value: GtsDirection) -> Self {
671 match value {
672 GtsDirection::Receive => 0b0,
673 GtsDirection::Transmit => 0b1,
674 }
675 }
676}
677
678bitflags::bitflags! {
679 pub struct SupportedFrequencyBands: u16 {
681 const BAND_161_MHZ = 0b0000_0000_0000_0001;
683 const BAND_216_MHZ = 0b0000_0000_0000_0010;
685 const BAND_217_MHZ = 0b0000_0000_0000_0100;
687 const BAND_220_MHZ = 0b0000_0000_0000_1000;
689 const BAND_450_MHZ = 0b0000_0000_0001_0000;
691 const BAND_779_MHZ = 0b0000_0000_0010_0000;
693 const BAND_800_MHZ = 0b0000_0000_0100_0000;
695 const BAND_806_MHZ = 0b0000_0000_1000_0000;
697 const BAND_896_MHZ = 0b0000_0001_0000_0000;
699 const BAND_915_MHZ = 0b0000_0010_0000_0000;
701 const BAND_928_MHZ = 0b0000_0100_0000_0000;
703 const BAND_2450_MHZ = 0b0000_1000_0000_0000;
705 const BAND_4965_MHZ = 0b0001_0000_0000_0000;
707 const BAND_5800_MHZ = 0b0010_0000_0000_0000;
709 const BAND_RESERVED = 0b1100_0000_0000_0000;
711 }
712}
713
714bitflags::bitflags! {
715 pub struct SupportedRccPhyAndModulation: u16 {
717 const GMSK_9_6_KBPS = 0b0000_0000_0000_0001;
719 const GMSK_19_2_KBPS = 0b0000_0000_0000_0010;
721 const FOUR_FSK_9_6_KBPS = 0b0000_0000_0000_0100;
723 const FOUR_FSK_19_2_KBPS = 0b0000_0000_0000_1000;
725 const FOUR_FSK_38_4_KBPS = 0b0000_0000_0001_0000;
727 const QPSK_16_KBPS = 0b0000_0000_0010_0000;
729 const QPSK_32_KBPS = 0b0000_0000_0100_0000;
731 const PI_4_DQPSK_16_KBPS = 0b0000_0000_1000_0000;
733 const PI_4_DQPSK_32_KBPS = 0b0000_0001_0000_0000;
735 const PI_4_DQPSK_64_KBPS = 0b0000_0010_0000_0000;
737 const DSSS_DPSK = 0b0000_0100_0000_0000;
739 const DSSS_BPSK = 0b0000_1000_0000_0000;
741 const RESERVED = 0b1111_0000_0000_0000;
743 }
744}
745
746bitflags::bitflags! {
747 pub struct SupportedDsssDpskModulation: u16 {
749 const RATE_300_KCPS = 0b0000_0000_0000_0001;
751 const RATE_600_KCPS = 0b0000_0000_0000_0010;
753 const RATE_800_KCPS = 0b0000_0000_0000_0100;
755 const RATE_1_MCPS = 0b0000_0000_0000_1000;
757 const RATE_1_6_MCPS = 0b0000_0000_0001_0000;
759 const RATE_2_MCPS = 0b0000_0000_0010_0000;
761 const RATE_3_MCPS = 0b0000_0000_0100_0000;
763 const RATE_4_MCPS = 0b0000_0000_1000_0000;
765 const SPREADING_11_CHIP = 0b0000_0001_0000_0000;
767 const SPREADING_15_CHIP = 0b0000_0010_0000_0000;
769 const SPREADING_20_CHIP = 0b0000_0100_0000_0000;
771 const SPREADING_40_CHIP = 0b0000_1000_0000_0000;
773 const DSSS_DBPSK = 0b0001_0000_0000_0000;
775 const DSSS_DQPSK = 0b0010_0000_0000_0000;
777 const RESERVED = 0b1100_0000_0000_0000;
779 }
780}
781
782#[cfg(test)]
783mod tests {
784 use super::*;
785
786 #[test]
787 fn superframe_specification() {
788 let data = [0xff, 0x0f];
789 let ie = SuperframeSpecification::new(&data).unwrap();
790 assert_eq!(ie.beacon_order(), BeaconOrder::OnDemand);
791 assert_eq!(ie.superframe_order(), SuperframeOrder::Inactive);
792 assert_eq!(ie.final_cap_slot(), 0x0f);
793 assert!(!ie.battery_life_extension());
794 assert!(!ie.pan_coordinator());
795 assert!(!ie.association_permit());
796 }
797
798 #[test]
799 fn gts_specification() {
800 use crate::Address;
801
802 let data = [0b0000_0000];
803 let gts = GtsSpecification::new(&data).unwrap();
804 assert_eq!(gts.descriptor_count(), 0);
805 assert!(!gts.gts_permit());
806
807 let data = [0b1000_0000];
808 let gts = GtsSpecification::new(&data).unwrap();
809 assert_eq!(gts.descriptor_count(), 0);
810 assert!(gts.gts_permit());
811
812 assert!(gts.slots().next().is_none());
813
814 let data = [0x82, 0x01, 0x34, 0x12, 0x11, 0x78, 0x56, 0x14];
815 let gts = GtsSpecification::new(&data).unwrap();
816
817 assert!(gts.gts_permit());
818 assert_eq!(gts.descriptor_count(), 2);
819
820 let mut slots = gts.slots();
821 let s0 = slots.next().unwrap();
822 assert_eq!(s0.short_address(), Address::Short([0x34, 0x12]));
823 assert_eq!(s0.starting_slot(), 1);
824 assert_eq!(s0.length(), 1);
825 assert_eq!(s0.direction(), GtsDirection::Transmit);
826
827 let s1 = slots.next().unwrap();
828 assert_eq!(s1.short_address(), Address::Short([0x78, 0x56]));
829 assert_eq!(s1.starting_slot(), 4);
830 assert_eq!(s1.length(), 1);
831 assert_eq!(s1.direction(), GtsDirection::Receive);
832
833 assert!(slots.next().is_none());
834 }
835
836 #[test]
837 fn gts_slot() {
838 use crate::Address;
839 let data = [0xab, 0xcd, 0b0101_1010];
840 let slot = GtsSlot::new(&data[..], GtsDirection::Transmit).unwrap();
841 assert_eq!(slot.short_address(), Address::Short([0xab, 0xcd]));
842 assert_eq!(slot.starting_slot(), 0b1010);
843 assert_eq!(slot.length(), 0b0101);
844 assert_eq!(slot.direction(), GtsDirection::Transmit);
845 }
846
847 #[test]
848 fn header_iformation_element_id() {
849 assert_eq!(
850 HeaderElementId::from(0x00),
851 HeaderElementId::VendorSpecificHeader
852 );
853 assert_eq!(HeaderElementId::from(0x1a), HeaderElementId::Csl);
854 assert_eq!(HeaderElementId::from(0x1b), HeaderElementId::Rit);
855 assert_eq!(
856 HeaderElementId::from(0x1c),
857 HeaderElementId::DsmePanDescriptor
858 );
859 assert_eq!(HeaderElementId::from(0x1d), HeaderElementId::RendezvousTime);
860 assert_eq!(HeaderElementId::from(0x1e), HeaderElementId::TimeCorrection);
861 assert_eq!(
862 HeaderElementId::from(0x21),
863 HeaderElementId::ExtendedDsmePanDescriptor
864 );
865 assert_eq!(
866 HeaderElementId::from(0x22),
867 HeaderElementId::FragmentSequenceContextDescription
868 );
869 assert_eq!(
870 HeaderElementId::from(0x23),
871 HeaderElementId::SimplifiedSuperframeSpecification
872 );
873 assert_eq!(
874 HeaderElementId::from(0x24),
875 HeaderElementId::SimplifiedGtsSpecification
876 );
877 assert_eq!(
878 HeaderElementId::from(0x25),
879 HeaderElementId::LecimCapabilities
880 );
881 assert_eq!(HeaderElementId::from(0x26), HeaderElementId::TrleDescriptor);
882 assert_eq!(
883 HeaderElementId::from(0x27),
884 HeaderElementId::RccCapabilities
885 );
886 assert_eq!(HeaderElementId::from(0x28), HeaderElementId::RccnDescriptor);
887 assert_eq!(HeaderElementId::from(0x29), HeaderElementId::GlobalTime);
888 assert_eq!(HeaderElementId::from(0x2b), HeaderElementId::Da);
889 assert_eq!(
890 HeaderElementId::from(0x7e),
891 HeaderElementId::HeaderTermination1
892 );
893 assert_eq!(
894 HeaderElementId::from(0x7f),
895 HeaderElementId::HeaderTermination2
896 );
897 assert_eq!(HeaderElementId::from(0x80), HeaderElementId::Unkown);
898 }
899}