1#![no_std]
58#![cfg_attr(docsrs, feature(doc_auto_cfg))]
59#[cfg(feature = "alloc")]
60extern crate alloc;
61#[cfg(any(feature = "std", test))]
62extern crate std;
63
64use core::{fmt::Debug, hash::Hash};
65use crc::{Crc, CRC_16_IBM_3740};
66use delegate::delegate;
67use zerocopy::{FromBytes, IntoBytes};
68
69#[cfg(feature = "serde")]
70use serde::{Deserialize, Serialize};
71
72pub mod cfdp;
73pub mod ecss;
74pub mod seq_count;
75pub mod time;
76pub mod util;
77
78mod private {
79 pub trait Sealed {}
80}
81
82pub const CCSDS_HEADER_LEN: usize = core::mem::size_of::<crate::zc::SpHeader>();
83
84pub const CRC_CCITT_FALSE: Crc<u16> = Crc::<u16>::new(&CRC_16_IBM_3740);
86
87pub const MAX_APID: u16 = 2u16.pow(11) - 1;
88pub const MAX_SEQ_COUNT: u16 = 2u16.pow(14) - 1;
89
90#[derive(Debug, Copy, Clone, PartialEq, Eq, thiserror::Error)]
92#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
93#[cfg_attr(feature = "defmt", derive(defmt::Format))]
94pub enum ByteConversionError {
95 #[error("target slice with size {found} is too small, expected size of at least {expected}")]
97 ToSliceTooSmall { found: usize, expected: usize },
98 #[error("source slice with size {found} too small, expected at least {expected} bytes")]
100 FromSliceTooSmall { found: usize, expected: usize },
101 #[error("zerocopy serialization error")]
103 ZeroCopyToError,
104 #[error("zerocopy deserialization error")]
106 ZeroCopyFromError,
107}
108
109#[derive(Debug, PartialEq, Eq, Copy, Clone)]
111#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
112#[cfg_attr(feature = "defmt", derive(defmt::Format))]
113pub enum PacketType {
114 Tm = 0,
115 Tc = 1,
116}
117
118impl TryFrom<u8> for PacketType {
119 type Error = ();
120
121 fn try_from(value: u8) -> Result<Self, Self::Error> {
122 match value {
123 x if x == PacketType::Tm as u8 => Ok(PacketType::Tm),
124 x if x == PacketType::Tc as u8 => Ok(PacketType::Tc),
125 _ => Err(()),
126 }
127 }
128}
129
130pub fn packet_type_in_raw_packet_id(packet_id: u16) -> PacketType {
131 PacketType::try_from((packet_id >> 12) as u8 & 0b1).unwrap()
132}
133
134#[derive(Debug, PartialEq, Eq, Copy, Clone)]
135#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
136#[cfg_attr(feature = "defmt", derive(defmt::Format))]
137pub enum SequenceFlags {
138 ContinuationSegment = 0b00,
139 FirstSegment = 0b01,
140 LastSegment = 0b10,
141 Unsegmented = 0b11,
142}
143
144impl TryFrom<u8> for SequenceFlags {
145 type Error = ();
146
147 fn try_from(value: u8) -> Result<Self, Self::Error> {
148 match value {
149 x if x == SequenceFlags::ContinuationSegment as u8 => {
150 Ok(SequenceFlags::ContinuationSegment)
151 }
152 x if x == SequenceFlags::FirstSegment as u8 => Ok(SequenceFlags::FirstSegment),
153 x if x == SequenceFlags::LastSegment as u8 => Ok(SequenceFlags::LastSegment),
154 x if x == SequenceFlags::Unsegmented as u8 => Ok(SequenceFlags::Unsegmented),
155 _ => Err(()),
156 }
157 }
158}
159
160#[derive(Debug, Eq, Copy, Clone)]
163#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
164#[cfg_attr(feature = "defmt", derive(defmt::Format))]
165pub struct PacketId {
166 pub ptype: PacketType,
167 pub sec_header_flag: bool,
168 apid: u16,
169}
170
171impl PartialEq for PacketId {
172 #[inline]
173 fn eq(&self, other: &Self) -> bool {
174 self.raw().eq(&other.raw())
175 }
176}
177
178impl PartialOrd for PacketId {
179 #[inline]
180 fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
181 Some(self.cmp(other))
182 }
183}
184
185impl Ord for PacketId {
186 #[inline]
187 fn cmp(&self, other: &Self) -> core::cmp::Ordering {
188 self.raw().cmp(&other.raw())
189 }
190}
191
192impl Hash for PacketId {
193 fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
194 let raw = self.raw();
195 raw.hash(state);
196 }
197}
198
199impl Default for PacketId {
200 #[inline]
201 fn default() -> Self {
202 PacketId {
203 ptype: PacketType::Tm,
204 sec_header_flag: false,
205 apid: 0,
206 }
207 }
208}
209
210impl PacketId {
211 #[inline]
214 pub const fn new_for_tc(sec_header: bool, apid: u16) -> Self {
215 Self::new(PacketType::Tc, sec_header, apid)
216 }
217
218 #[inline]
221 pub const fn new_for_tm(sec_header: bool, apid: u16) -> Self {
222 Self::new(PacketType::Tm, sec_header, apid)
223 }
224
225 #[inline]
226 pub fn new_for_tc_checked(sec_header: bool, apid: u16) -> Option<Self> {
227 Self::new_checked(PacketType::Tc, sec_header, apid)
228 }
229
230 #[inline]
231 pub fn new_for_tm_checked(sec_header: bool, apid: u16) -> Option<Self> {
232 Self::new_checked(PacketType::Tm, sec_header, apid)
233 }
234
235 #[inline]
238 pub const fn new(ptype: PacketType, sec_header: bool, apid: u16) -> Self {
239 if apid > MAX_APID {
240 panic!("APID too large");
241 }
242 PacketId {
243 ptype,
244 sec_header_flag: sec_header,
245 apid,
246 }
247 }
248
249 #[inline]
250 pub fn new_checked(ptype: PacketType, sec_header_flag: bool, apid: u16) -> Option<PacketId> {
251 if apid > MAX_APID {
252 return None;
253 }
254 Some(PacketId::new(ptype, sec_header_flag, apid))
255 }
256
257 #[inline]
261 pub fn set_apid(&mut self, apid: u16) -> bool {
262 if apid > MAX_APID {
263 return false;
264 }
265 self.apid = apid;
266 true
267 }
268
269 #[inline]
270 pub fn apid(&self) -> u16 {
271 self.apid
272 }
273
274 #[inline]
275 pub fn raw(&self) -> u16 {
276 ((self.ptype as u16) << 12) | ((self.sec_header_flag as u16) << 11) | self.apid
277 }
278}
279
280impl From<u16> for PacketId {
281 fn from(raw_id: u16) -> Self {
282 PacketId {
283 ptype: PacketType::try_from(((raw_id >> 12) & 0b1) as u8).unwrap(),
284 sec_header_flag: ((raw_id >> 11) & 0b1) != 0,
285 apid: raw_id & 0x7FF,
286 }
287 }
288}
289
290#[derive(Debug, PartialEq, Eq, Copy, Clone)]
293#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
294#[cfg_attr(feature = "defmt", derive(defmt::Format))]
295pub struct PacketSequenceCtrl {
296 pub seq_flags: SequenceFlags,
297 seq_count: u16,
298}
299
300impl PacketSequenceCtrl {
301 #[inline]
304 pub const fn new(seq_flags: SequenceFlags, seq_count: u16) -> PacketSequenceCtrl {
305 if seq_count > MAX_SEQ_COUNT {
306 panic!("Sequence count too large");
307 }
308 PacketSequenceCtrl {
309 seq_flags,
310 seq_count,
311 }
312 }
313
314 #[inline]
316 pub fn new_checked(seq_flags: SequenceFlags, seq_count: u16) -> Option<PacketSequenceCtrl> {
317 if seq_count > MAX_SEQ_COUNT {
318 return None;
319 }
320 Some(PacketSequenceCtrl::new(seq_flags, seq_count))
321 }
322
323 #[inline]
324 pub fn raw(&self) -> u16 {
325 ((self.seq_flags as u16) << 14) | self.seq_count
326 }
327
328 #[inline]
331 pub fn set_seq_count(&mut self, ssc: u16) -> bool {
332 if ssc > MAX_SEQ_COUNT {
333 return false;
334 }
335 self.seq_count = ssc;
336 true
337 }
338
339 #[inline]
340 pub fn seq_count(&self) -> u16 {
341 self.seq_count
342 }
343}
344
345impl From<u16> for PacketSequenceCtrl {
346 fn from(raw_id: u16) -> Self {
347 PacketSequenceCtrl {
348 seq_flags: SequenceFlags::try_from(((raw_id >> 14) & 0b11) as u8).unwrap(),
349 seq_count: raw_id & SSC_MASK,
350 }
351 }
352}
353
354macro_rules! sph_from_other {
355 ($Self: path, $other: path) => {
356 impl From<$other> for $Self {
357 fn from(other: $other) -> Self {
358 Self::from_composite_fields(
359 other.packet_id(),
360 other.psc(),
361 other.data_len(),
362 Some(other.ccsds_version()),
363 )
364 }
365 }
366 };
367}
368
369const SSC_MASK: u16 = 0x3FFF;
370const VERSION_MASK: u16 = 0xE000;
371
372pub trait CcsdsPacket {
374 fn ccsds_version(&self) -> u8;
375 fn packet_id(&self) -> PacketId;
376 fn psc(&self) -> PacketSequenceCtrl;
377
378 fn data_len(&self) -> u16;
380 #[inline]
382 fn total_len(&self) -> usize {
383 usize::from(self.data_len()) + CCSDS_HEADER_LEN + 1
384 }
385
386 #[inline]
389 fn packet_id_raw(&self) -> u16 {
390 self.packet_id().raw()
391 }
392 #[inline]
394 fn psc_raw(&self) -> u16 {
395 self.psc().raw()
396 }
397
398 #[inline]
400 fn ptype(&self) -> PacketType {
401 self.packet_id().ptype
403 }
404
405 #[inline]
406 fn is_tm(&self) -> bool {
407 self.ptype() == PacketType::Tm
408 }
409
410 #[inline]
411 fn is_tc(&self) -> bool {
412 self.ptype() == PacketType::Tc
413 }
414
415 #[inline]
418 fn sec_header_flag(&self) -> bool {
419 self.packet_id().sec_header_flag
420 }
421
422 #[inline]
424 fn apid(&self) -> u16 {
425 self.packet_id().apid
426 }
427
428 #[inline]
429 fn seq_count(&self) -> u16 {
430 self.psc().seq_count
431 }
432
433 #[inline]
434 fn sequence_flags(&self) -> SequenceFlags {
435 self.psc().seq_flags
438 }
439}
440
441pub trait CcsdsPrimaryHeader {
442 fn from_composite_fields(
443 packet_id: PacketId,
444 psc: PacketSequenceCtrl,
445 data_len: u16,
446 version: Option<u8>,
447 ) -> Self;
448}
449
450#[derive(Debug, PartialEq, Eq, Copy, Clone)]
461#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
462#[cfg_attr(feature = "defmt", derive(defmt::Format))]
463pub struct SpHeader {
464 pub version: u8,
465 pub packet_id: PacketId,
466 pub psc: PacketSequenceCtrl,
467 pub data_len: u16,
468}
469
470pub type SpacePacketHeader = SpHeader;
471
472impl Default for SpHeader {
473 #[inline]
476 fn default() -> Self {
477 SpHeader {
478 version: 0,
479 packet_id: PacketId::default(),
480 psc: PacketSequenceCtrl {
481 seq_flags: SequenceFlags::Unsegmented,
482 seq_count: 0,
483 },
484 data_len: 0,
485 }
486 }
487}
488
489impl SpHeader {
490 #[inline]
491 pub const fn new(packet_id: PacketId, psc: PacketSequenceCtrl, data_len: u16) -> Self {
492 Self {
493 version: 0,
494 packet_id,
495 psc,
496 data_len,
497 }
498 }
499
500 #[inline]
505 pub const fn new_from_apid(apid: u16) -> Self {
506 SpHeader {
507 version: 0,
508 packet_id: PacketId::new(PacketType::Tm, false, apid),
509 psc: PacketSequenceCtrl {
510 seq_flags: SequenceFlags::Unsegmented,
511 seq_count: 0,
512 },
513 data_len: 0,
514 }
515 }
516
517 #[inline]
519 pub fn new_from_apid_checked(apid: u16) -> Option<Self> {
520 Some(SpHeader {
521 version: 0,
522 packet_id: PacketId::new_checked(PacketType::Tm, false, apid)?,
523 psc: PacketSequenceCtrl {
524 seq_flags: SequenceFlags::Unsegmented,
525 seq_count: 0,
526 },
527 data_len: 0,
528 })
529 }
530
531 #[inline]
536 pub const fn new_from_fields(
537 ptype: PacketType,
538 sec_header: bool,
539 apid: u16,
540 seq_flags: SequenceFlags,
541 seq_count: u16,
542 data_len: u16,
543 ) -> Self {
544 if seq_count > MAX_SEQ_COUNT {
545 panic!("Sequence count is too large");
546 }
547 if apid > MAX_APID {
548 panic!("APID is too large");
549 }
550 Self {
551 psc: PacketSequenceCtrl::new(seq_flags, seq_count),
552 packet_id: PacketId::new(ptype, sec_header, apid),
553 data_len,
554 version: 0,
555 }
556 }
557
558 #[inline]
564 pub fn new_from_fields_checked(
565 ptype: PacketType,
566 sec_header: bool,
567 apid: u16,
568 seq_flags: SequenceFlags,
569 seq_count: u16,
570 data_len: u16,
571 ) -> Option<Self> {
572 if seq_count > MAX_SEQ_COUNT || apid > MAX_APID {
573 return None;
574 }
575 Some(SpHeader::new_from_fields(
576 ptype, sec_header, apid, seq_flags, seq_count, data_len,
577 ))
578 }
579
580 #[inline]
583 pub fn new_for_tm_checked(
584 apid: u16,
585 seq_flags: SequenceFlags,
586 seq_count: u16,
587 data_len: u16,
588 ) -> Option<Self> {
589 Self::new_from_fields_checked(PacketType::Tm, false, apid, seq_flags, seq_count, data_len)
590 }
591
592 #[inline]
595 pub fn new_for_tc_checked(
596 apid: u16,
597 seq_flags: SequenceFlags,
598 seq_count: u16,
599 data_len: u16,
600 ) -> Option<Self> {
601 Self::new_from_fields_checked(PacketType::Tc, false, apid, seq_flags, seq_count, data_len)
602 }
603
604 #[inline]
606 pub const fn new_for_tm(
607 apid: u16,
608 seq_flags: SequenceFlags,
609 seq_count: u16,
610 data_len: u16,
611 ) -> Self {
612 Self::new_from_fields(PacketType::Tm, false, apid, seq_flags, seq_count, data_len)
613 }
614
615 #[inline]
617 pub const fn new_for_tc(
618 apid: u16,
619 seq_flags: SequenceFlags,
620 seq_count: u16,
621 data_len: u16,
622 ) -> Self {
623 Self::new_from_fields(PacketType::Tc, false, apid, seq_flags, seq_count, data_len)
624 }
625
626 #[inline]
628 pub fn new_for_unseg_tm_checked(apid: u16, seq_count: u16, data_len: u16) -> Option<Self> {
629 Self::new_for_tm_checked(apid, SequenceFlags::Unsegmented, seq_count, data_len)
630 }
631
632 #[inline]
634 pub fn new_for_unseg_tc_checked(apid: u16, seq_count: u16, data_len: u16) -> Option<Self> {
635 Self::new_for_tc_checked(apid, SequenceFlags::Unsegmented, seq_count, data_len)
636 }
637
638 #[inline]
642 pub const fn new_for_unseg_tc(apid: u16, seq_count: u16, data_len: u16) -> Self {
643 Self::new_for_tc(apid, SequenceFlags::Unsegmented, seq_count, data_len)
644 }
645
646 #[inline]
650 pub const fn new_for_unseg_tm(apid: u16, seq_count: u16, data_len: u16) -> Self {
651 Self::new_for_tm(apid, SequenceFlags::Unsegmented, seq_count, data_len)
652 }
653
654 delegate! {
655 to self.packet_id {
656 #[inline]
658 pub fn set_apid(&mut self, apid: u16) -> bool;
659 }
660 }
661
662 delegate! {
663 to self.psc {
664 #[inline]
666 pub fn set_seq_count(&mut self, seq_count: u16) -> bool;
667 }
668 }
669
670 #[inline]
671 pub fn set_seq_flags(&mut self, seq_flags: SequenceFlags) {
672 self.psc.seq_flags = seq_flags;
673 }
674
675 #[inline]
676 pub fn set_sec_header_flag(&mut self) {
677 self.packet_id.sec_header_flag = true;
678 }
679
680 #[inline]
681 pub fn clear_sec_header_flag(&mut self) {
682 self.packet_id.sec_header_flag = false;
683 }
684
685 #[inline]
686 pub fn set_packet_type(&mut self, packet_type: PacketType) {
687 self.packet_id.ptype = packet_type;
688 }
689
690 pub fn from_be_bytes(buf: &[u8]) -> Result<(Self, &[u8]), ByteConversionError> {
694 if buf.len() < CCSDS_HEADER_LEN {
695 return Err(ByteConversionError::FromSliceTooSmall {
696 found: buf.len(),
697 expected: CCSDS_HEADER_LEN,
698 });
699 }
700 let zc_header = zc::SpHeader::read_from_bytes(&buf[0..CCSDS_HEADER_LEN])
701 .map_err(|_| ByteConversionError::ZeroCopyFromError)?;
702 Ok((Self::from(zc_header), &buf[CCSDS_HEADER_LEN..]))
703 }
704
705 pub fn write_to_be_bytes<'a>(
708 &self,
709 buf: &'a mut [u8],
710 ) -> Result<&'a mut [u8], ByteConversionError> {
711 if buf.len() < CCSDS_HEADER_LEN {
712 return Err(ByteConversionError::FromSliceTooSmall {
713 found: buf.len(),
714 expected: CCSDS_HEADER_LEN,
715 });
716 }
717 let zc_header: zc::SpHeader = zc::SpHeader::from(*self);
718 zc_header
719 .write_to(&mut buf[0..CCSDS_HEADER_LEN])
720 .map_err(|_| ByteConversionError::ZeroCopyToError)?;
721 Ok(&mut buf[CCSDS_HEADER_LEN..])
722 }
723
724 #[cfg(feature = "alloc")]
726 pub fn to_vec(&self) -> alloc::vec::Vec<u8> {
727 let mut vec = alloc::vec![0; CCSDS_HEADER_LEN];
728 self.write_to_be_bytes(&mut vec[..]).unwrap();
730 vec
731 }
732}
733
734impl CcsdsPacket for SpHeader {
735 #[inline]
736 fn ccsds_version(&self) -> u8 {
737 self.version
738 }
739
740 #[inline]
741 fn packet_id(&self) -> PacketId {
742 self.packet_id
743 }
744
745 #[inline]
746 fn psc(&self) -> PacketSequenceCtrl {
747 self.psc
748 }
749
750 #[inline]
751 fn data_len(&self) -> u16 {
752 self.data_len
753 }
754}
755
756impl CcsdsPrimaryHeader for SpHeader {
757 #[inline]
758 fn from_composite_fields(
759 packet_id: PacketId,
760 psc: PacketSequenceCtrl,
761 data_len: u16,
762 version: Option<u8>,
763 ) -> Self {
764 let mut version_to_set = 0b000;
765 if let Some(version) = version {
766 version_to_set = version;
767 }
768 SpHeader {
769 version: version_to_set,
770 packet_id,
771 psc,
772 data_len,
773 }
774 }
775}
776
777sph_from_other!(SpHeader, crate::zc::SpHeader);
778
779pub mod zc {
780 use crate::{CcsdsPacket, CcsdsPrimaryHeader, PacketId, PacketSequenceCtrl, VERSION_MASK};
781 use zerocopy::byteorder::NetworkEndian;
782 use zerocopy::{FromBytes, Immutable, IntoBytes, Unaligned, U16};
783
784 #[derive(FromBytes, IntoBytes, Immutable, Unaligned, Debug)]
785 #[repr(C)]
786 pub struct SpHeader {
787 version_packet_id: U16<NetworkEndian>,
788 psc: U16<NetworkEndian>,
789 data_len: U16<NetworkEndian>,
790 }
791
792 impl SpHeader {
793 pub fn new(
794 packet_id: PacketId,
795 psc: PacketSequenceCtrl,
796 data_len: u16,
797 version: Option<u8>,
798 ) -> Self {
799 let mut version_packet_id = packet_id.raw();
800 if let Some(version) = version {
801 version_packet_id = ((version as u16) << 13) | packet_id.raw()
802 }
803 SpHeader {
804 version_packet_id: U16::from(version_packet_id),
805 psc: U16::from(psc.raw()),
806 data_len: U16::from(data_len),
807 }
808 }
809 }
810
811 impl CcsdsPacket for SpHeader {
812 #[inline]
813 fn ccsds_version(&self) -> u8 {
814 ((self.version_packet_id.get() >> 13) as u8) & 0b111
815 }
816
817 #[inline]
818 fn packet_id(&self) -> PacketId {
819 PacketId::from(self.packet_id_raw())
820 }
821
822 #[inline]
823 fn psc(&self) -> PacketSequenceCtrl {
824 PacketSequenceCtrl::from(self.psc_raw())
825 }
826
827 #[inline]
828 fn data_len(&self) -> u16 {
829 self.data_len.get()
830 }
831
832 #[inline]
833 fn packet_id_raw(&self) -> u16 {
834 self.version_packet_id.get() & (!VERSION_MASK)
835 }
836
837 #[inline]
838 fn psc_raw(&self) -> u16 {
839 self.psc.get()
840 }
841 }
842
843 impl CcsdsPrimaryHeader for SpHeader {
844 fn from_composite_fields(
845 packet_id: PacketId,
846 psc: PacketSequenceCtrl,
847 data_len: u16,
848 version: Option<u8>,
849 ) -> Self {
850 SpHeader::new(packet_id, psc, data_len, version)
851 }
852 }
853
854 sph_from_other!(SpHeader, crate::SpHeader);
855}
856
857#[cfg(all(test, feature = "std"))]
858pub(crate) mod tests {
859 use std::collections::HashSet;
860
861 #[allow(unused_imports)]
862 use crate::ByteConversionError;
863 #[cfg(feature = "serde")]
864 use crate::CcsdsPrimaryHeader;
865 use crate::{
866 packet_type_in_raw_packet_id, zc, CcsdsPacket, PacketId, PacketSequenceCtrl, PacketType,
867 };
868 use crate::{SequenceFlags, SpHeader};
869 use alloc::vec;
870 #[cfg(feature = "serde")]
871 use core::fmt::Debug;
872 use num_traits::pow;
873 #[cfg(feature = "serde")]
874 use postcard::{from_bytes, to_allocvec};
875 #[cfg(feature = "serde")]
876 use serde::{de::DeserializeOwned, Serialize};
877 use zerocopy::FromBytes;
878
879 const CONST_SP: SpHeader = SpHeader::new(
880 PacketId::new_for_tc(true, 0x36),
881 PacketSequenceCtrl::new(SequenceFlags::ContinuationSegment, 0x88),
882 0x90,
883 );
884
885 const PACKET_ID_TM: PacketId = PacketId::new_for_tm(true, 0x22);
886
887 #[cfg(feature = "serde")]
888 pub(crate) fn generic_serde_test<T: Serialize + DeserializeOwned + PartialEq + Debug>(
889 value: T,
890 ) {
891 let output: alloc::vec::Vec<u8> = to_allocvec(&value).unwrap();
892 let output_converted_back: T = from_bytes(&output).unwrap();
893 assert_eq!(output_converted_back, value);
894 }
895
896 #[test]
897 #[allow(clippy::assertions_on_constants)]
898 fn verify_const_packet_id() {
899 assert_eq!(PACKET_ID_TM.apid(), 0x22);
900 assert!(PACKET_ID_TM.sec_header_flag);
901 assert_eq!(PACKET_ID_TM.ptype, PacketType::Tm);
902 let const_tc_id = PacketId::new_for_tc(true, 0x23);
903 assert_eq!(const_tc_id.ptype, PacketType::Tc);
904 }
905
906 #[test]
907 fn test_default_packet_id() {
908 let id_default = PacketId::default();
909 assert_eq!(id_default.ptype, PacketType::Tm);
910 assert_eq!(id_default.apid, 0x000);
911 assert!(!id_default.sec_header_flag);
912 }
913
914 #[test]
915 fn test_packet_id_ctors() {
916 let packet_id = PacketId::new_checked(PacketType::Tc, true, 0x1ff);
917 assert!(packet_id.is_some());
918 let packet_id = packet_id.unwrap();
919 assert_eq!(packet_id.apid(), 0x1ff);
920 assert_eq!(packet_id.ptype, PacketType::Tc);
921 assert!(packet_id.sec_header_flag);
922 let packet_id_tc = PacketId::new_for_tc_checked(true, 0x1ff);
923 assert!(packet_id_tc.is_some());
924 let packet_id_tc = packet_id_tc.unwrap();
925 assert_eq!(packet_id_tc, packet_id);
926 let packet_id_tm = PacketId::new_for_tm_checked(true, 0x2ff);
927 assert!(packet_id_tm.is_some());
928 let packet_id_tm = packet_id_tm.unwrap();
929 assert!(packet_id_tm.sec_header_flag);
930 assert_eq!(packet_id_tm.ptype, PacketType::Tm);
931 assert_eq!(packet_id_tm.apid, 0x2ff);
932 }
933
934 #[test]
935 fn verify_const_sp_header() {
936 assert!(CONST_SP.sec_header_flag());
937 assert_eq!(CONST_SP.apid(), 0x36);
938 assert_eq!(
939 CONST_SP.sequence_flags(),
940 SequenceFlags::ContinuationSegment
941 );
942 assert_eq!(CONST_SP.seq_count(), 0x88);
943 assert_eq!(CONST_SP.data_len, 0x90);
944 }
945
946 #[test]
947 fn test_seq_flag_helpers() {
948 assert_eq!(
949 SequenceFlags::try_from(0b00).expect("SEQ flag creation failed"),
950 SequenceFlags::ContinuationSegment
951 );
952 assert_eq!(
953 SequenceFlags::try_from(0b01).expect("SEQ flag creation failed"),
954 SequenceFlags::FirstSegment
955 );
956 assert_eq!(
957 SequenceFlags::try_from(0b10).expect("SEQ flag creation failed"),
958 SequenceFlags::LastSegment
959 );
960 assert_eq!(
961 SequenceFlags::try_from(0b11).expect("SEQ flag creation failed"),
962 SequenceFlags::Unsegmented
963 );
964 assert!(SequenceFlags::try_from(0b100).is_err());
965 }
966
967 #[test]
968 fn test_packet_type_helper() {
969 assert_eq!(PacketType::try_from(0b00).unwrap(), PacketType::Tm);
970 assert_eq!(PacketType::try_from(0b01).unwrap(), PacketType::Tc);
971 assert!(PacketType::try_from(0b10).is_err());
972 }
973
974 #[test]
975 fn test_packet_id() {
976 let packet_id =
977 PacketId::new_checked(PacketType::Tm, false, 0x42).expect("Packet ID creation failed");
978 assert_eq!(packet_id.raw(), 0x0042);
979 let packet_id_from_raw = PacketId::from(packet_id.raw());
980 assert_eq!(
981 packet_type_in_raw_packet_id(packet_id.raw()),
982 PacketType::Tm
983 );
984 assert_eq!(packet_id_from_raw, packet_id);
985 let packet_id_from_new = PacketId::new_checked(PacketType::Tm, false, 0x42).unwrap();
986 assert_eq!(packet_id_from_new, packet_id);
987 }
988
989 #[test]
990 fn test_invalid_packet_id() {
991 let packet_id_invalid = PacketId::new_checked(PacketType::Tc, true, 0xFFFF);
992 assert!(packet_id_invalid.is_none());
993 }
994
995 #[test]
996 fn test_invalid_apid_setter() {
997 let mut packet_id =
998 PacketId::new_checked(PacketType::Tm, false, 0x42).expect("Packet ID creation failed");
999 assert!(!packet_id.set_apid(0xffff));
1000 }
1001
1002 #[test]
1003 fn test_invalid_seq_count() {
1004 let mut psc = PacketSequenceCtrl::new_checked(SequenceFlags::ContinuationSegment, 77)
1005 .expect("PSC creation failed");
1006 assert_eq!(psc.seq_count(), 77);
1007 assert!(!psc.set_seq_count(0xffff));
1008 }
1009
1010 #[test]
1011 fn test_packet_seq_ctrl() {
1012 let mut psc = PacketSequenceCtrl::new_checked(SequenceFlags::ContinuationSegment, 77)
1013 .expect("PSC creation failed");
1014 assert_eq!(psc.raw(), 77);
1015 let psc_from_raw = PacketSequenceCtrl::from(psc.raw());
1016 assert_eq!(psc_from_raw, psc);
1017 assert!(!psc.set_seq_count(2u16.pow(15)));
1019 assert_eq!(psc.raw(), 77);
1020
1021 let psc_invalid = PacketSequenceCtrl::new_checked(SequenceFlags::FirstSegment, 0xFFFF);
1022 assert!(psc_invalid.is_none());
1023 let psc_from_new =
1024 PacketSequenceCtrl::new_checked(SequenceFlags::ContinuationSegment, 77).unwrap();
1025 assert_eq!(psc_from_new, psc);
1026 }
1027
1028 #[test]
1029 #[cfg(feature = "serde")]
1030 fn test_serde_sph() {
1031 let sp_header =
1032 SpHeader::new_for_unseg_tc_checked(0x42, 12, 0).expect("Error creating SP header");
1033 assert_eq!(sp_header.ccsds_version(), 0b000);
1034 assert!(sp_header.is_tc());
1035 assert!(!sp_header.sec_header_flag());
1036 assert_eq!(sp_header.ptype(), PacketType::Tc);
1037 assert_eq!(sp_header.seq_count(), 12);
1038 assert_eq!(sp_header.apid(), 0x42);
1039 assert_eq!(sp_header.sequence_flags(), SequenceFlags::Unsegmented);
1040 assert_eq!(sp_header.data_len(), 0);
1041 let output = to_allocvec(&sp_header).unwrap();
1042 let sp_header: SpHeader = from_bytes(&output).unwrap();
1043 assert_eq!(sp_header.version, 0b000);
1044 assert!(!sp_header.packet_id.sec_header_flag);
1045 assert_eq!(sp_header.ptype(), PacketType::Tc);
1046 assert_eq!(sp_header.seq_count(), 12);
1047 assert_eq!(sp_header.apid(), 0x42);
1048 assert_eq!(sp_header.sequence_flags(), SequenceFlags::Unsegmented);
1049 assert_eq!(sp_header.packet_id_raw(), 0x1042);
1050 assert_eq!(sp_header.psc_raw(), 0xC00C);
1051 assert_eq!(sp_header.ccsds_version(), 0b000);
1052 assert_eq!(sp_header.data_len, 0);
1053
1054 let sp_header =
1055 SpHeader::new_for_unseg_tm_checked(0x7, 22, 36).expect("Error creating SP header");
1056 assert_eq!(sp_header.ccsds_version(), 0b000);
1057 assert!(sp_header.is_tm());
1058 assert!(!sp_header.sec_header_flag());
1059 assert_eq!(sp_header.ptype(), PacketType::Tm);
1060 assert_eq!(sp_header.seq_count(), 22);
1061 assert_eq!(sp_header.apid(), 0x07);
1062 assert_eq!(sp_header.sequence_flags(), SequenceFlags::Unsegmented);
1063 assert_eq!(sp_header.packet_id_raw(), 0x0007);
1064 assert_eq!(sp_header.psc_raw(), 0xC016);
1065 assert_eq!(sp_header.data_len(), 36);
1066 assert_eq!(sp_header.ccsds_version(), 0b000);
1067
1068 let from_comp_fields = SpHeader::from_composite_fields(
1069 PacketId::new(PacketType::Tc, true, 0x42),
1070 PacketSequenceCtrl::new(SequenceFlags::Unsegmented, 0x7),
1071 0,
1072 None,
1073 );
1074 assert_eq!(from_comp_fields.ptype(), PacketType::Tc);
1075 assert_eq!(from_comp_fields.apid(), 0x42);
1076 assert!(from_comp_fields.sec_header_flag());
1077 assert_eq!(
1078 from_comp_fields.sequence_flags(),
1079 SequenceFlags::Unsegmented
1080 );
1081 assert_eq!(from_comp_fields.seq_count(), 0x7);
1082 assert_eq!(from_comp_fields.data_len(), 0);
1083 }
1084
1085 #[test]
1086 fn test_setters() {
1087 let sp_header = SpHeader::new_for_tc_checked(0x42, SequenceFlags::Unsegmented, 25, 0);
1088 assert!(sp_header.is_some());
1089 let mut sp_header = sp_header.unwrap();
1090 sp_header.set_apid(0x12);
1091 assert_eq!(sp_header.apid(), 0x12);
1092 sp_header.set_sec_header_flag();
1093 assert!(sp_header.sec_header_flag());
1094 sp_header.clear_sec_header_flag();
1095 assert!(!sp_header.sec_header_flag());
1096 assert_eq!(sp_header.ptype(), PacketType::Tc);
1097 sp_header.set_packet_type(PacketType::Tm);
1098 assert_eq!(sp_header.ptype(), PacketType::Tm);
1099 sp_header.set_seq_count(0x45);
1100 assert_eq!(sp_header.seq_count(), 0x45);
1101 }
1102
1103 #[test]
1104 fn test_tc_ctor() {
1105 let sp_header = SpHeader::new_for_tc_checked(0x42, SequenceFlags::Unsegmented, 25, 0);
1106 assert!(sp_header.is_some());
1107 let sp_header = sp_header.unwrap();
1108 verify_sp_fields(PacketType::Tc, &sp_header);
1109 }
1110
1111 #[test]
1112 fn test_tc_ctor_unseg() {
1113 let sp_header = SpHeader::new_for_unseg_tc_checked(0x42, 25, 0);
1114 assert!(sp_header.is_some());
1115 let sp_header = sp_header.unwrap();
1116 verify_sp_fields(PacketType::Tc, &sp_header);
1117 }
1118
1119 #[test]
1120 fn test_tc_ctor_unseg_const() {
1121 let sp_header = SpHeader::new_for_unseg_tc(0x42, 25, 0);
1122 verify_sp_fields(PacketType::Tc, &sp_header);
1123 }
1124
1125 #[test]
1126 fn test_tm_ctor() {
1127 let sp_header = SpHeader::new_for_tm_checked(0x42, SequenceFlags::Unsegmented, 25, 0);
1128 assert!(sp_header.is_some());
1129 let sp_header = sp_header.unwrap();
1130 verify_sp_fields(PacketType::Tm, &sp_header);
1131 }
1132
1133 #[test]
1134 fn test_tm_ctor_const() {
1135 let sp_header = SpHeader::new_for_tm(0x42, SequenceFlags::Unsegmented, 25, 0);
1136 verify_sp_fields(PacketType::Tm, &sp_header);
1137 }
1138
1139 #[test]
1140 fn test_tm_ctor_unseg() {
1141 let sp_header = SpHeader::new_for_unseg_tm_checked(0x42, 25, 0);
1142 assert!(sp_header.is_some());
1143 let sp_header = sp_header.unwrap();
1144 verify_sp_fields(PacketType::Tm, &sp_header);
1145 }
1146
1147 fn verify_sp_fields(ptype: PacketType, sp_header: &SpHeader) {
1148 assert_eq!(sp_header.ptype(), ptype);
1149 assert_eq!(sp_header.sequence_flags(), SequenceFlags::Unsegmented);
1150 assert_eq!(sp_header.apid(), 0x42);
1151 assert_eq!(sp_header.seq_count(), 25);
1152 assert_eq!(sp_header.data_len(), 0);
1153 }
1154
1155 #[test]
1156 fn test_zc_sph() {
1157 use zerocopy::IntoBytes;
1158
1159 let sp_header = SpHeader::new_for_unseg_tc_checked(0x7FF, pow(2, 14) - 1, 0)
1160 .expect("Error creating SP header");
1161 assert_eq!(sp_header.ptype(), PacketType::Tc);
1162 assert_eq!(sp_header.apid(), 0x7FF);
1163 assert_eq!(sp_header.data_len(), 0);
1164 assert_eq!(sp_header.ccsds_version(), 0b000);
1165 assert!(sp_header.is_tc());
1166 let sp_header_zc = zc::SpHeader::from(sp_header);
1167 let slice = sp_header_zc.as_bytes();
1168 assert_eq!(slice.len(), 6);
1169 assert_eq!(slice[0], 0x17);
1170 assert_eq!(slice[1], 0xFF);
1171 assert_eq!(slice[2], 0xFF);
1172 assert_eq!(slice[3], 0xFF);
1173 assert_eq!(slice[4], 0x00);
1174 assert_eq!(slice[5], 0x00);
1175
1176 let mut slice = [0; 6];
1177 sp_header_zc.write_to(slice.as_mut_slice()).unwrap();
1178 assert_eq!(slice.len(), 6);
1179 assert_eq!(slice[0], 0x17);
1180 assert_eq!(slice[1], 0xFF);
1181 assert_eq!(slice[2], 0xFF);
1182 assert_eq!(slice[3], 0xFF);
1183 assert_eq!(slice[4], 0x00);
1184 assert_eq!(slice[5], 0x00);
1185
1186 let mut test_vec = vec![0_u8; 6];
1187 let slice = test_vec.as_mut_slice();
1188 sp_header_zc.write_to(slice).unwrap();
1189 let slice = test_vec.as_slice();
1190 assert_eq!(slice.len(), 6);
1191 assert_eq!(slice[0], 0x17);
1192 assert_eq!(slice[1], 0xFF);
1193 assert_eq!(slice[2], 0xFF);
1194 assert_eq!(slice[3], 0xFF);
1195 assert_eq!(slice[4], 0x00);
1196 assert_eq!(slice[5], 0x00);
1197
1198 let sp_header = zc::SpHeader::read_from_bytes(slice);
1199 assert!(sp_header.is_ok());
1200 let sp_header = sp_header.unwrap();
1201 assert_eq!(sp_header.ccsds_version(), 0b000);
1202 assert_eq!(sp_header.packet_id_raw(), 0x17FF);
1203 assert_eq!(sp_header.apid(), 0x7FF);
1204 assert_eq!(sp_header.ptype(), PacketType::Tc);
1205 assert_eq!(sp_header.data_len(), 0);
1206 }
1207
1208 #[test]
1209 fn packet_id_ord_partial_ord() {
1210 let packet_id_small = PacketId::from(1_u16);
1211 let packet_id_larger = PacketId::from(2_u16);
1212 assert!(packet_id_small < packet_id_larger);
1213 assert!(packet_id_larger > packet_id_small);
1214 assert_eq!(
1215 packet_id_small.cmp(&packet_id_larger),
1216 core::cmp::Ordering::Less
1217 );
1218 }
1219
1220 #[test]
1221 fn packet_id_hashable() {
1222 let mut id_set = HashSet::new();
1223 id_set.insert(PacketId::from(1_u16));
1224 }
1225
1226 #[test]
1227 fn sp_header_from_apid() {
1228 let sp_header = SpHeader::new_from_apid(0x03);
1229 assert_eq!(sp_header.apid(), 0x03);
1230 assert_eq!(sp_header.data_len(), 0);
1231 }
1232
1233 #[test]
1234 fn sp_header_from_apid_checked() {
1235 let sp_header = SpHeader::new_from_apid_checked(0x03).unwrap();
1236 assert_eq!(sp_header.apid(), 0x03);
1237 assert_eq!(sp_header.data_len(), 0);
1238 }
1239
1240 #[cfg(feature = "defmt")]
1241 fn is_defmt_format<T: defmt::Format>(_t: T) {}
1242
1243 #[test]
1244 #[cfg(feature = "defmt")]
1245 fn test_defmt_format() {
1246 is_defmt_format(ByteConversionError::ToSliceTooSmall {
1247 found: 1,
1248 expected: 2,
1249 });
1250 }
1251
1252 #[test]
1253 fn test_sp_header_as_vec() {
1254 let sp_header = SpHeader::new_for_unseg_tc(0x42, 25, 1);
1255 let sp_header_as_vec = sp_header.to_vec();
1256 let sp_header_read_back = SpHeader::from_be_bytes(&sp_header_as_vec)
1257 .expect("Error reading back SP header")
1258 .0;
1259 assert_eq!(sp_header, sp_header_read_back);
1260 }
1261}