spacepackets/
lib.rs

1//! # CCSDS and ECSS packet standards implementations
2//!
3//! This crate contains generic implementations for various
4//! CCSDS (Consultative Committee for Space Data Systems) and
5//! ECSS (European Cooperation for Space Standardization) packet standards.
6//! Currently, this includes the following components:
7//!
8//!  - Space Packet implementation according to
9//!    [CCSDS Blue Book 133.0-B-2](https://public.ccsds.org/Pubs/133x0b2e1.pdf)
10//!  - CCSDS File Delivery Protocol (CFDP) packet implementations according to
11//!    [CCSDS Blue Book 727.0-B-5](https://public.ccsds.org/Pubs/727x0b5.pdf)
12//!  - PUS Telecommand and PUS Telemetry implementation according to the
13//!    [ECSS-E-ST-70-41C standard](https://ecss.nl/standard/ecss-e-st-70-41c-space-engineering-telemetry-and-telecommand-packet-utilization-15-april-2016/).
14//!  - CUC (CCSDS Unsegmented Time Code) implementation according to
15//!    [CCSDS 301.0-B-4 3.2](https://public.ccsds.org/Pubs/301x0b4e1.pdf)
16//!  - CDS (CCSDS Day Segmented Time Code) implementation according to
17//!    [CCSDS 301.0-B-4 3.3](https://public.ccsds.org/Pubs/301x0b4e1.pdf)
18//!  - Some helper types to support ASCII timecodes as specified in
19//!    [CCSDS 301.0-B-4 3.5](https://public.ccsds.org/Pubs/301x0b4e1.pdf)
20//!
21//! ## Features
22//!
23//! `spacepackets` supports various runtime environments and is also suitable for `no_std` environments.
24//!
25//! ### Default features
26//!
27//!  - [`std`](https://doc.rust-lang.org/std/): Enables functionality relying on the standard library.
28//!  - [`alloc`](https://doc.rust-lang.org/alloc/): Enables features which operate on containers
29//!    like [`alloc::vec::Vec`](https://doc.rust-lang.org/beta/alloc/vec/struct.Vec.html).
30//!    Enabled by the `std` feature.
31//!
32//! ### Optional features
33//!
34//!  - [`serde`](https://serde.rs/): Adds `serde` support for most types by adding `Serialize` and
35//!    `Deserialize` `derives.
36//!  - [`chrono`](https://crates.io/crates/chrono): Add basic support for the `chrono` time library.
37//!  - [`timelib`](https://crates.io/crates/time): Add basic support for the `time` time library.
38//!  - [`defmt`](https://defmt.ferrous-systems.com/): Add support for the `defmt` by adding the
39//!    [`defmt::Format`](https://defmt.ferrous-systems.com/format) derive on many types.
40//!  - [`portable-atomic`](https://github.com/taiki-e/portable-atomic): Basic support for
41//!    `portable-atomic` crate in addition to the support for core atomic types. This support
42//!    requires atomic CAS support enabled in the portable atomic crate.
43//!
44//! ## Module
45//!
46//! This module contains helpers and data structures to generate Space Packets according to the
47//! [CCSDS 133.0-B-2](https://public.ccsds.org/Pubs/133x0b2e1.pdf). This includes the
48//! [SpHeader] class to generate the Space Packet Header component common to all space packets.
49//!
50//! ## Example
51//!
52//! ```rust
53//! use spacepackets::SpHeader;
54//! use arbitrary_int::{u11, u14};
55//!
56//! let sp_header = SpHeader::new_for_unseg_tc(u11::new(0x42), u14::new(12), 1);
57//! println!("{:?}", sp_header);
58//! let mut ccsds_buf: [u8; 32] = [0; 32];
59//! sp_header.write_to_be_bytes(&mut ccsds_buf).expect("Writing CCSDS TC header failed");
60//! println!("{:x?}", &ccsds_buf[0..6]);
61//! ```
62#![no_std]
63#![cfg_attr(docsrs, feature(doc_cfg))]
64#![warn(missing_docs)]
65#[cfg(feature = "alloc")]
66extern crate alloc;
67#[cfg(any(feature = "std", test))]
68extern crate std;
69
70use arbitrary_int::{prelude::*, u11, u14};
71use core::{fmt::Debug, hash::Hash};
72use delegate::delegate;
73use zerocopy::{FromBytes, IntoBytes};
74
75#[cfg(feature = "serde")]
76use serde::{Deserialize, Serialize};
77
78use crate::crc::CRC_CCITT_FALSE;
79
80pub mod cfdp;
81pub mod crc;
82pub mod ecss;
83pub mod seq_count;
84pub mod time;
85pub mod uslp;
86pub mod util;
87
88mod private {
89    pub trait Sealed {}
90}
91
92/// Length of the CCSDS header.
93pub const CCSDS_HEADER_LEN: usize = core::mem::size_of::<crate::zc::SpHeader>();
94
95/// Maximum allowed value for the 11-bit APID.
96pub const MAX_APID: u11 = u11::MAX;
97/// Maximum allowed value for the 14-bit APID.
98pub const MAX_SEQ_COUNT: u14 = u14::MAX;
99
100/// Checksum types currently provided by the CCSDS packet support.
101#[derive(Debug, Copy, Clone, PartialEq, Eq)]
102#[cfg_attr(feature = "defmt", derive(defmt::Format))]
103#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
104#[non_exhaustive]
105pub enum ChecksumType {
106    /// Check the default CRC16-CCITT checksum.
107    WithCrc16,
108    /// Packet has a CRC16 which should be ignored.
109    ///
110    /// It is either not generated for packet creation or ignored when reading a packet.
111    WithCrc16ButIgnored,
112}
113
114/// Generic error type when converting to and from raw byte slices.
115#[derive(Debug, Copy, Clone, PartialEq, Eq, thiserror::Error)]
116#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
117#[cfg_attr(feature = "defmt", derive(defmt::Format))]
118pub enum ByteConversionError {
119    /// The passed slice is too small. Returns the passed slice length and expected minimum size
120    #[error("target slice with size {found} is too small, expected size of at least {expected}")]
121    ToSliceTooSmall {
122        /// Found slice size.
123        found: usize,
124        /// Expected slice size.
125        expected: usize,
126    },
127    /// The provider buffer is too small. Returns the passed slice length and expected minimum size
128    #[error("source slice with size {found} too small, expected at least {expected} bytes")]
129    FromSliceTooSmall {
130        /// Found slice size.
131        found: usize,
132        /// Expected slice size.
133        expected: usize,
134    },
135}
136
137/// [zerocopy] serialization and deserialization errors.
138#[derive(Debug, Copy, Clone, PartialEq, Eq, thiserror::Error)]
139#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
140#[cfg_attr(feature = "defmt", derive(defmt::Format))]
141pub enum ZeroCopyError {
142    /// The [zerocopy] library failed to write to bytes
143    #[error("zerocopy serialization error")]
144    ZeroCopyToError,
145    /// The [zerocopy] library failed to read from bytes
146    #[error("zerocopy deserialization error")]
147    ZeroCopyFromError,
148}
149
150/// Invalid payload length which is bounded by [u16::MAX]
151#[derive(thiserror::Error, Debug)]
152#[cfg_attr(feature = "defmt", derive(defmt::Format))]
153#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
154#[error("invalid payload length: {0}")]
155pub struct InvalidPayloadLengthError(usize);
156
157/// Errors during CCSDS packet creation.
158#[derive(thiserror::Error, Debug)]
159#[cfg_attr(feature = "defmt", derive(defmt::Format))]
160#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
161pub enum CcsdsPacketCreationError {
162    /// Byte conversion error.
163    #[error("byte conversion: {0}")]
164    ByteConversion(#[from] ByteConversionError),
165    /// Invalid payload length which exceeded [u16::MAX].
166    #[error("invalid payload length: {0}")]
167    InvalidPayloadLength(#[from] InvalidPayloadLengthError),
168}
169
170/// CCSDS packet type enumeration.
171#[derive(Debug, PartialEq, Eq, num_enum::TryFromPrimitive)]
172#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
173#[cfg_attr(feature = "defmt", derive(defmt::Format))]
174#[bitbybit::bitenum(u1, exhaustive = true)]
175#[repr(u8)]
176pub enum PacketType {
177    /// Telemetry packet.
178    Tm = 0,
179    /// Telecommand packet.
180    Tc = 1,
181}
182
183/// CCSDS packet sequence flags.
184#[derive(Debug, PartialEq, Eq, num_enum::TryFromPrimitive)]
185#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
186#[cfg_attr(feature = "defmt", derive(defmt::Format))]
187#[bitbybit::bitenum(u2, exhaustive = true)]
188#[repr(u8)]
189pub enum SequenceFlags {
190    /// Continuation segment of a segmented packet.
191    ContinuationSegment = 0b00,
192    /// First segment of a sequence.
193    FirstSegment = 0b01,
194    /// Last segment of a sequence.
195    LastSegment = 0b10,
196    /// Unsegmented packet.
197    Unsegmented = 0b11,
198}
199
200/// Retrieve the [PacketType] from a raw packet ID.
201#[inline]
202pub fn packet_type_in_raw_packet_id(packet_id: u16) -> PacketType {
203    PacketType::try_from((packet_id >> 12) as u8 & 0b1).unwrap()
204}
205
206/// Calculate the full CCSDS packet length for a given user data length and optional checksum type.
207///
208/// Returns [None] if the calculated length allowed by the CCSDS data length field.
209#[inline]
210pub const fn ccsds_packet_len_for_user_data_len(
211    data_len: usize,
212    checksum: Option<ChecksumType>,
213) -> Option<usize> {
214    // Special case: A value of zero is not allowed for the data length field.
215    if data_len == 0 {
216        return Some(7);
217    }
218    let checksum_len = match checksum {
219        Some(ChecksumType::WithCrc16) => 2,
220        Some(ChecksumType::WithCrc16ButIgnored) => 2,
221        None => 0,
222    };
223    let len = data_len
224        .saturating_add(CCSDS_HEADER_LEN)
225        .saturating_add(checksum_len);
226    if len - CCSDS_HEADER_LEN - 1 > u16::MAX as usize {
227        return None;
228    }
229    Some(len)
230}
231
232/// Calculate the full CCSDS packet length for a given user data length.
233///
234/// Returns [None] if the packet length exceeds the maximum allowed size [u16::MAX].
235#[inline]
236pub fn ccsds_packet_len_for_user_data_len_with_checksum(data_len: usize) -> Option<usize> {
237    ccsds_packet_len_for_user_data_len(data_len, Some(ChecksumType::WithCrc16))
238}
239
240/// Abstraction for the CCSDS Packet ID, which forms the last thirteen bits
241/// of the first two bytes in the CCSDS primary header.
242#[derive(Debug, Eq, Copy, Clone)]
243#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
244#[cfg_attr(feature = "defmt", derive(defmt::Format))]
245pub struct PacketId {
246    /// Packet type (telemetry or telecommand).
247    pub packet_type: PacketType,
248    /// Secondary header flag.
249    pub sec_header_flag: bool,
250    /// Application Process ID (APID).
251    pub apid: u11,
252}
253
254impl PartialEq for PacketId {
255    #[inline]
256    fn eq(&self, other: &Self) -> bool {
257        self.raw().eq(&other.raw())
258    }
259}
260
261impl PartialOrd for PacketId {
262    #[inline]
263    fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
264        Some(self.cmp(other))
265    }
266}
267
268impl Ord for PacketId {
269    #[inline]
270    fn cmp(&self, other: &Self) -> core::cmp::Ordering {
271        self.raw().cmp(&other.raw())
272    }
273}
274
275impl Hash for PacketId {
276    fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
277        let raw = self.raw();
278        raw.hash(state);
279    }
280}
281
282impl Default for PacketId {
283    #[inline]
284    fn default() -> Self {
285        PacketId {
286            packet_type: PacketType::Tm,
287            sec_header_flag: false,
288            apid: u11::new(0),
289        }
290    }
291}
292
293impl PacketId {
294    /// Generic constructor for telecommands.
295    #[inline]
296    pub const fn new_for_tc(sec_header: bool, apid: u11) -> Self {
297        Self::new(PacketType::Tc, sec_header, apid)
298    }
299
300    /// Generic constructor for telemetry.
301    #[inline]
302    pub const fn new_for_tm(sec_header: bool, apid: u11) -> Self {
303        Self::new(PacketType::Tm, sec_header, apid)
304    }
305
306    /// Generic constructor.
307    #[inline]
308    pub const fn new(packet_type: PacketType, sec_header_flag: bool, apid: u11) -> Self {
309        PacketId {
310            packet_type,
311            sec_header_flag,
312            apid,
313        }
314    }
315
316    /// Set a new Application Process ID (APID). If the passed number is invalid, the APID will
317    /// not be set and false will be returned. The maximum allowed value for the 11-bit field is
318    /// 2047
319    #[inline]
320    pub fn set_apid(&mut self, apid: u11) {
321        self.apid = apid;
322    }
323
324    /// 11-bit CCSDS Application Process ID (APID) field.
325    #[inline]
326    pub const fn apid(&self) -> u11 {
327        self.apid
328    }
329
330    /// Raw numeric value.
331    #[inline]
332    pub const fn raw(&self) -> u16 {
333        ((self.packet_type as u16) << 12)
334            | ((self.sec_header_flag as u16) << 11)
335            | self.apid.value()
336    }
337}
338
339impl From<u16> for PacketId {
340    fn from(raw_id: u16) -> Self {
341        PacketId {
342            packet_type: PacketType::try_from(((raw_id >> 12) & 0b1) as u8).unwrap(),
343            sec_header_flag: ((raw_id >> 11) & 0b1) != 0,
344            apid: u11::new(raw_id & 0x7FF),
345        }
346    }
347}
348
349/// Deprecated type alias.
350#[deprecated(since = "0.16.0", note = "use PacketSequenceControl instead")]
351pub type PacketSequenceCtrl = PacketSequenceControl;
352
353/// Abstraction for the CCSDS Packet Sequence Control (PSC) field which is the
354/// third and the fourth byte in the CCSDS primary header.
355#[derive(Debug, PartialEq, Eq, Copy, Clone)]
356#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
357#[cfg_attr(feature = "defmt", derive(defmt::Format))]
358pub struct PacketSequenceControl {
359    /// CCSDS sequence flags.
360    pub seq_flags: SequenceFlags,
361    /// CCSDS sequence count.
362    pub seq_count: u14,
363}
364
365impl PacketSequenceControl {
366    /// Generic constructor.
367    #[inline]
368    pub const fn new(seq_flags: SequenceFlags, seq_count: u14) -> PacketSequenceControl {
369        PacketSequenceControl {
370            seq_flags,
371            seq_count,
372        }
373    }
374
375    /// Raw value.
376    #[inline]
377    pub const fn raw(&self) -> u16 {
378        ((self.seq_flags as u16) << 14) | self.seq_count.value()
379    }
380}
381
382impl From<u16> for PacketSequenceControl {
383    fn from(raw_id: u16) -> Self {
384        PacketSequenceControl {
385            seq_flags: SequenceFlags::try_from(((raw_id >> 14) & 0b11) as u8).unwrap(),
386            seq_count: u14::new(raw_id & SSC_MASK),
387        }
388    }
389}
390
391macro_rules! sph_from_other {
392    ($Self: path, $other: path) => {
393        impl From<$other> for $Self {
394            fn from(other: $other) -> Self {
395                Self::new_from_composite_fields(
396                    other.packet_id(),
397                    other.psc(),
398                    other.data_len(),
399                    Some(other.ccsds_version()),
400                )
401            }
402        }
403    };
404}
405
406const SSC_MASK: u16 = 0x3FFF;
407const VERSION_MASK: u16 = 0xE000;
408
409/// Generic trait to access fields of a CCSDS space packet header according to CCSDS 133.0-B-2.
410pub trait CcsdsPacket {
411    /// CCSDS version field.
412    fn ccsds_version(&self) -> u3;
413
414    /// CCSDS packet ID.
415    ///
416    /// First two bytes of the CCSDS primary header without the first three bits.
417    fn packet_id(&self) -> PacketId;
418
419    /// CCSDS packet sequence control.
420    ///
421    /// Third and fourth byte of the CCSDS primary header.
422    fn psc(&self) -> PacketSequenceControl;
423
424    /// Data length field.
425    ///
426    /// Please note that this is NOT the full packet length.
427    /// The full length can be calculated by adding the header length [CCSDS_HEADER_LEN] + 1 or
428    /// using [Self::packet_len].
429    fn data_len(&self) -> u16;
430
431    /// Total packet size based on the data length field
432    #[inline]
433    fn packet_len(&self) -> usize {
434        usize::from(self.data_len()) + CCSDS_HEADER_LEN + 1
435    }
436
437    /// Deprecated alias for [Self::packet_len].
438    #[deprecated(since = "0.16.0", note = "use packet_len instead")]
439    #[inline]
440    fn total_len(&self) -> usize {
441        self.packet_len()
442    }
443
444    /// Retrieve 13 bit Packet Identification field. Can usually be retrieved with a bitwise AND
445    /// of the first 2 bytes with 0x1FFF.
446    #[inline]
447    fn packet_id_raw(&self) -> u16 {
448        self.packet_id().raw()
449    }
450    /// Retrieve Packet Sequence Count
451    #[inline]
452    fn psc_raw(&self) -> u16 {
453        self.psc().raw()
454    }
455
456    /// CCSDS packet type.
457    #[inline]
458    fn packet_type(&self) -> PacketType {
459        // This call should never fail because only 0 and 1 can be passed to the try_from call
460        self.packet_id().packet_type
461    }
462
463    /// Is this a telemetry packet?
464    #[inline]
465    fn is_tm(&self) -> bool {
466        self.packet_type() == PacketType::Tm
467    }
468
469    /// Is this a telecommand packet?
470    #[inline]
471    fn is_tc(&self) -> bool {
472        self.packet_type() == PacketType::Tc
473    }
474
475    /// CCSDS secondary header flag. Returns true if a secondary header is present
476    /// and false if it is not.
477    #[inline]
478    fn sec_header_flag(&self) -> bool {
479        self.packet_id().sec_header_flag
480    }
481
482    /// CCSDS Application Process ID (APID).
483    #[inline]
484    fn apid(&self) -> u11 {
485        self.packet_id().apid
486    }
487
488    /// CCSDS sequence count.
489    #[inline]
490    fn seq_count(&self) -> u14 {
491        self.psc().seq_count
492    }
493
494    /// CCSDS sequence flags.
495    #[inline]
496    fn sequence_flags(&self) -> SequenceFlags {
497        // This call should never fail because the mask ensures that only valid values are passed
498        // into the try_from function
499        self.psc().seq_flags
500    }
501}
502
503/// Helper trait to generate the primary header from the composite fields.
504pub trait CcsdsPrimaryHeader {
505    /// Constructor.
506    fn new_from_composite_fields(
507        packet_id: PacketId,
508        psc: PacketSequenceControl,
509        data_len: u16,
510        version: Option<u3>,
511    ) -> Self;
512}
513
514/// Space Packet Primary Header according to CCSDS 133.0-B-2.
515#[derive(Debug, PartialEq, Eq, Copy, Clone)]
516#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
517#[cfg_attr(feature = "defmt", derive(defmt::Format))]
518pub struct SpacePacketHeader {
519    /// CCSDS version field, occupies the first 3 bits of the raw header. Will generally
520    /// be set to 0b000 in all constructors provided by this crate.
521    pub version: u3,
522    /// CCSDS Packet Identifier, which can also be used as a start marker. Occupies the last
523    /// 13 bits of the first two bytes of the raw header
524    pub packet_id: PacketId,
525    /// CCSDS Packet Sequence Control, occupies the third and fourth byte of the raw header
526    pub psc: PacketSequenceControl,
527    /// Data length field occupies the fifth and the sixth byte of the raw header
528    pub data_len: u16,
529}
530
531/// Alias for [SpacePacketHeader].
532pub type SpHeader = SpacePacketHeader;
533
534impl Default for SpacePacketHeader {
535    /// The default function sets the sequence flag field to [SequenceFlags::Unsegmented] and the
536    /// data length to 0.
537    #[inline]
538    fn default() -> Self {
539        SpHeader {
540            version: u3::new(0),
541            packet_id: PacketId::default(),
542            psc: PacketSequenceControl {
543                seq_flags: SequenceFlags::Unsegmented,
544                seq_count: u14::new(0),
545            },
546            data_len: 0,
547        }
548    }
549}
550
551impl SpacePacketHeader {
552    /// Length of the CCSDS primary header.
553    pub const LENGTH: usize = CCSDS_HEADER_LEN;
554
555    /// Generic constructor.
556    #[inline]
557    pub const fn new(packet_id: PacketId, psc: PacketSequenceControl, data_len: u16) -> Self {
558        Self {
559            version: u3::new(0),
560            packet_id,
561            psc,
562            data_len,
563        }
564    }
565
566    /// This constructor sets the sequence flag field to [SequenceFlags::Unsegmented] and the data
567    /// length to 0.
568    #[inline]
569    pub const fn new_from_apid(apid: u11) -> Self {
570        Self {
571            version: u3::new(0b000),
572            packet_id: PacketId::new(PacketType::Tm, false, apid),
573            psc: PacketSequenceControl {
574                seq_flags: SequenceFlags::Unsegmented,
575                seq_count: u14::new(0),
576            },
577            data_len: 0,
578        }
579    }
580
581    /// Constructor from individual fields.
582    #[inline]
583    pub const fn new_from_fields(
584        ptype: PacketType,
585        sec_header: bool,
586        apid: u11,
587        seq_flags: SequenceFlags,
588        seq_count: u14,
589        data_len: u16,
590    ) -> Self {
591        Self {
592            psc: PacketSequenceControl::new(seq_flags, seq_count),
593            packet_id: PacketId::new(ptype, sec_header, apid),
594            data_len,
595            version: u3::new(0b000),
596        }
597    }
598
599    /// Constructor for telemetry packets.
600    #[inline]
601    pub const fn new_for_tm(
602        apid: u11,
603        seq_flags: SequenceFlags,
604        seq_count: u14,
605        data_len: u16,
606    ) -> Self {
607        Self::new_from_fields(PacketType::Tm, false, apid, seq_flags, seq_count, data_len)
608    }
609
610    /// Constructor for telecommand packets.
611    #[inline]
612    pub const fn new_for_tc(
613        apid: u11,
614        seq_flags: SequenceFlags,
615        seq_count: u14,
616        data_len: u16,
617    ) -> Self {
618        Self::new_from_fields(PacketType::Tc, false, apid, seq_flags, seq_count, data_len)
619    }
620
621    /// Variant of [SpHeader::new_for_tc] which sets the sequence flag field to [SequenceFlags::Unsegmented].
622    #[inline]
623    pub const fn new_for_unseg_tc(apid: u11, seq_count: u14, data_len: u16) -> Self {
624        Self::new_for_tc(apid, SequenceFlags::Unsegmented, seq_count, data_len)
625    }
626
627    /// Variant of [SpHeader::new_for_tm] which sets the sequence flag field to [SequenceFlags::Unsegmented].
628    #[inline]
629    pub const fn new_for_unseg_tm(apid: u11, seq_count: u14, data_len: u16) -> Self {
630        Self::new_for_tm(apid, SequenceFlags::Unsegmented, seq_count, data_len)
631    }
632
633    delegate! {
634        to self.packet_id {
635            /// Set the application process ID (APID).
636            #[inline]
637            pub fn set_apid(&mut self, apid: u11);
638        }
639    }
640
641    /// Retrieve the total packet size based on the data length field
642    #[inline]
643    pub fn packet_len(&self) -> usize {
644        usize::from(self.data_len()) + Self::LENGTH + 1
645    }
646
647    /// Set the CCSDS sequence count.
648    #[inline]
649    pub fn set_seq_count(&mut self, seq_count: u14) {
650        self.psc.seq_count = seq_count;
651    }
652
653    /// Set the CCSDS sequence flags.
654    #[inline]
655    pub fn set_seq_flags(&mut self, seq_flags: SequenceFlags) {
656        self.psc.seq_flags = seq_flags;
657    }
658
659    /// Set the CCSDS secondary header flag.
660    #[inline]
661    pub fn set_sec_header_flag(&mut self) {
662        self.packet_id.sec_header_flag = true;
663    }
664
665    /// Clear the CCSDS secondary header flag.
666    #[inline]
667    pub fn clear_sec_header_flag(&mut self) {
668        self.packet_id.sec_header_flag = false;
669    }
670
671    /// Set the CCSDS packet type.
672    #[inline]
673    pub fn set_packet_type(&mut self, packet_type: PacketType) {
674        self.packet_id.packet_type = packet_type;
675    }
676
677    /// Application Process ID (APID) field.
678    #[inline]
679    pub fn apid(&self) -> u11 {
680        self.packet_id.apid
681    }
682
683    /// Create a struct from a raw slice where the fields have network endianness (big).
684    /// This function also returns the remaining part of the passed slice starting past the read
685    /// CCSDS header.
686    pub fn from_be_bytes(buf: &[u8]) -> Result<(Self, &[u8]), ByteConversionError> {
687        if buf.len() < Self::LENGTH {
688            return Err(ByteConversionError::FromSliceTooSmall {
689                found: buf.len(),
690                expected: CCSDS_HEADER_LEN,
691            });
692        }
693        // Unwrap okay, this can not fail.
694        let zc_header = zc::SpHeader::read_from_bytes(&buf[0..Self::LENGTH]).unwrap();
695        Ok((Self::from(zc_header), &buf[Self::LENGTH..]))
696    }
697
698    /// Write the header to a raw buffer using big endian format. This function returns the
699    /// remaining part of the passed slice starting past the written CCSDS header.
700    pub fn write_to_be_bytes<'a>(
701        &self,
702        buf: &'a mut [u8],
703    ) -> Result<&'a mut [u8], ByteConversionError> {
704        if buf.len() < Self::LENGTH {
705            return Err(ByteConversionError::ToSliceTooSmall {
706                found: buf.len(),
707                expected: CCSDS_HEADER_LEN,
708            });
709        }
710        let zc_header: zc::SpHeader = zc::SpHeader::from(*self);
711        // Unwrap okay, this can not fail.
712        zc_header.write_to(&mut buf[0..Self::LENGTH]).unwrap();
713        Ok(&mut buf[Self::LENGTH..])
714    }
715
716    /// Create a vector containing the CCSDS header.
717    #[cfg(feature = "alloc")]
718    pub fn to_vec(&self) -> alloc::vec::Vec<u8> {
719        let mut vec = alloc::vec![0; Self::LENGTH];
720        // This can not fail.
721        self.write_to_be_bytes(&mut vec[..]).unwrap();
722        vec
723    }
724}
725
726impl CcsdsPacket for SpacePacketHeader {
727    /// CCSDS version field.
728    #[inline]
729    fn ccsds_version(&self) -> u3 {
730        self.version
731    }
732
733    /// Full packet length.
734    #[inline]
735    fn packet_len(&self) -> usize {
736        self.packet_len()
737    }
738
739    /// CCSDS packet ID field.
740    #[inline]
741    fn packet_id(&self) -> PacketId {
742        self.packet_id
743    }
744
745    /// CCSDS packet sequence control.
746    #[inline]
747    fn psc(&self) -> PacketSequenceControl {
748        self.psc
749    }
750
751    /// CCSDS data length field.
752    #[inline]
753    fn data_len(&self) -> u16 {
754        self.data_len
755    }
756}
757
758impl CcsdsPrimaryHeader for SpacePacketHeader {
759    #[inline]
760    fn new_from_composite_fields(
761        packet_id: PacketId,
762        psc: PacketSequenceControl,
763        data_len: u16,
764        version: Option<u3>,
765    ) -> Self {
766        let mut version_to_set = u3::new(0b000);
767        if let Some(version) = version {
768            version_to_set = version;
769        }
770        SpHeader {
771            version: version_to_set,
772            packet_id,
773            psc,
774            data_len,
775        }
776    }
777}
778
779sph_from_other!(SpHeader, crate::zc::SpHeader);
780
781/// [zerocopy] based CCSDS Space Packet Primary Header implementation.
782pub mod zc {
783    use crate::{CcsdsPacket, CcsdsPrimaryHeader, PacketId, PacketSequenceControl, VERSION_MASK};
784    use arbitrary_int::traits::Integer;
785    use arbitrary_int::u3;
786    use zerocopy::byteorder::NetworkEndian;
787    use zerocopy::{FromBytes, Immutable, IntoBytes, Unaligned, U16};
788
789    /// [zerocopy] space packet header.
790    #[derive(FromBytes, IntoBytes, Immutable, Unaligned, Debug)]
791    #[repr(C)]
792    pub struct SpHeader {
793        version_packet_id: U16<NetworkEndian>,
794        psc: U16<NetworkEndian>,
795        data_len: U16<NetworkEndian>,
796    }
797
798    impl SpHeader {
799        /// Generic constructor.
800        pub fn new(
801            packet_id: PacketId,
802            psc: PacketSequenceControl,
803            data_len: u16,
804            version: Option<u3>,
805        ) -> Self {
806            let mut version_packet_id = packet_id.raw();
807            if let Some(version) = version {
808                version_packet_id = (version.as_u16() << 13) | packet_id.raw()
809            }
810            SpHeader {
811                version_packet_id: U16::from(version_packet_id),
812                psc: U16::from(psc.raw()),
813                data_len: U16::from(data_len),
814            }
815        }
816    }
817
818    impl CcsdsPacket for SpHeader {
819        /// CCSDS version field.
820        #[inline]
821        fn ccsds_version(&self) -> u3 {
822            u3::new(((self.version_packet_id.get() >> 13) as u8) & 0b111)
823        }
824
825        /// CCSDS packet ID field.
826        #[inline]
827        fn packet_id(&self) -> PacketId {
828            PacketId::from(self.packet_id_raw())
829        }
830
831        /// CCSDS packet sequence control field.
832        #[inline]
833        fn psc(&self) -> PacketSequenceControl {
834            PacketSequenceControl::from(self.psc_raw())
835        }
836
837        /// CCSDS data length field.
838        #[inline]
839        fn data_len(&self) -> u16 {
840            self.data_len.get()
841        }
842
843        #[inline]
844        fn packet_id_raw(&self) -> u16 {
845            self.version_packet_id.get() & (!VERSION_MASK)
846        }
847
848        #[inline]
849        fn psc_raw(&self) -> u16 {
850            self.psc.get()
851        }
852    }
853
854    impl CcsdsPrimaryHeader for SpHeader {
855        fn new_from_composite_fields(
856            packet_id: PacketId,
857            psc: PacketSequenceControl,
858            data_len: u16,
859            version: Option<u3>,
860        ) -> Self {
861            SpHeader::new(packet_id, psc, data_len, version)
862        }
863    }
864
865    sph_from_other!(SpHeader, crate::SpHeader);
866}
867
868/// CCSDS packet creator with optional support for a CRC16 CCITT checksum appended to the
869/// end of the packet and support for copying into the user buffer directly.
870///
871/// This packet creator variant reserves memory based on the required user data length specified
872/// by the user and then provides mutable or shared access to that memory. This is useful
873/// to avoid an additional slice for the user data and allow copying data directly
874/// into the packet.
875///
876/// Please note that packet creation has to be completed using the [Self::finish] call.
877#[derive(Debug)]
878pub struct CcsdsPacketCreatorWithReservedData<'buf> {
879    sp_header: SpHeader,
880    buf: &'buf mut [u8],
881    checksum: Option<ChecksumType>,
882}
883
884impl<'buf> CcsdsPacketCreatorWithReservedData<'buf> {
885    /// CCSDS header length.
886    pub const HEADER_LEN: usize = CCSDS_HEADER_LEN;
887
888    /// Calculate the full CCSDS packet length for a given user data length and with a CRC16
889    /// checksum.
890    #[inline]
891    pub fn packet_len_for_user_data_with_checksum(user_data_len: usize) -> Option<usize> {
892        ccsds_packet_len_for_user_data_len(user_data_len, Some(ChecksumType::WithCrc16))
893    }
894
895    /// Generic constructor.
896    pub fn new(
897        mut sp_header: SpacePacketHeader,
898        packet_type: PacketType,
899        packet_data_len: usize,
900        buf: &'buf mut [u8],
901        checksum: Option<ChecksumType>,
902    ) -> Result<Self, CcsdsPacketCreationError> {
903        let full_packet_len = match checksum {
904            Some(crc_type) => match crc_type {
905                ChecksumType::WithCrc16 | ChecksumType::WithCrc16ButIgnored => {
906                    CCSDS_HEADER_LEN + packet_data_len + 2
907                }
908            },
909            None => {
910                // Special case: At least one byte of user data is required.
911                if packet_data_len == 0 {
912                    CCSDS_HEADER_LEN + 1
913                } else {
914                    CCSDS_HEADER_LEN + packet_data_len
915                }
916            }
917        };
918        if full_packet_len > buf.len() {
919            return Err(ByteConversionError::ToSliceTooSmall {
920                found: buf.len(),
921                expected: full_packet_len,
922            }
923            .into());
924        }
925        if full_packet_len - CCSDS_HEADER_LEN - 1 > u16::MAX as usize {
926            return Err(InvalidPayloadLengthError(packet_data_len).into());
927        }
928        sp_header.data_len = (full_packet_len - CCSDS_HEADER_LEN - 1) as u16;
929        sp_header.packet_id.packet_type = packet_type;
930
931        Ok(Self {
932            sp_header,
933            buf: buf[0..full_packet_len].as_mut(),
934            checksum,
935        })
936    }
937
938    /// Constructor which always appends a CRC16 checksum at the packet end.
939    pub fn new_with_checksum(
940        sp_header: SpHeader,
941        packet_type: PacketType,
942        payload_len: usize,
943        buf: &'buf mut [u8],
944    ) -> Result<Self, CcsdsPacketCreationError> {
945        Self::new(
946            sp_header,
947            packet_type,
948            payload_len,
949            buf,
950            Some(ChecksumType::WithCrc16),
951        )
952    }
953
954    /// Constructor for telemetry packets which always appends a CRC16 checksum at the packet end.
955    pub fn new_tm_with_checksum(
956        sp_header: SpHeader,
957        payload_len: usize,
958        buf: &'buf mut [u8],
959    ) -> Result<Self, CcsdsPacketCreationError> {
960        Self::new(
961            sp_header,
962            PacketType::Tm,
963            payload_len,
964            buf,
965            Some(ChecksumType::WithCrc16),
966        )
967    }
968
969    /// Constructor for telecommand packets which always appends a CRC16 checksum at the packet
970    /// end.
971    pub fn new_tc_with_checksum(
972        sp_header: SpHeader,
973        payload_len: usize,
974        buf: &'buf mut [u8],
975    ) -> Result<Self, CcsdsPacketCreationError> {
976        Self::new(
977            sp_header,
978            PacketType::Tc,
979            payload_len,
980            buf,
981            Some(ChecksumType::WithCrc16),
982        )
983    }
984}
985
986impl CcsdsPacketCreatorWithReservedData<'_> {
987    /// Raw full buffer this packet is constructed in.
988    #[inline]
989    pub fn raw_buffer(&self) -> &[u8] {
990        self.buf
991    }
992
993    /// Full packet length.
994    #[inline]
995    pub fn packet_len(&self) -> usize {
996        <Self as CcsdsPacket>::packet_len(self)
997    }
998
999    /// Space packet header.
1000    #[inline]
1001    pub fn sp_header(&self) -> &SpHeader {
1002        &self.sp_header
1003    }
1004
1005    /// [CcsdsPacketIdAndPsc] structure for this packet.
1006    #[inline]
1007    pub fn ccsds_packet_id_and_psc(&self) -> CcsdsPacketIdAndPsc {
1008        CcsdsPacketIdAndPsc::new_from_ccsds_packet(self)
1009    }
1010
1011    /// Mutable access to the packet data field.
1012    #[inline]
1013    pub fn packet_data_mut(&mut self) -> &mut [u8] {
1014        let len = self.packet_len();
1015        match self.checksum {
1016            Some(ChecksumType::WithCrc16) | Some(ChecksumType::WithCrc16ButIgnored) => {
1017                &mut self.buf[CCSDS_HEADER_LEN..len - 2]
1018            }
1019            None => &mut self.buf[CCSDS_HEADER_LEN..len],
1020        }
1021    }
1022
1023    /// Read-only access to the packet data field.
1024    #[inline]
1025    pub fn packet_data(&mut self) -> &[u8] {
1026        let len = self.packet_len();
1027        match self.checksum {
1028            Some(ChecksumType::WithCrc16) | Some(ChecksumType::WithCrc16ButIgnored) => {
1029                &self.buf[CCSDS_HEADER_LEN..len - 2]
1030            }
1031            None => &self.buf[CCSDS_HEADER_LEN..len],
1032        }
1033    }
1034
1035    /// Finish the packet generation process.
1036    ///
1037    /// This packet writes the space packet header. It also calculates and appends the CRC
1038    /// checksum when configured to do so.
1039    pub fn finish(self) -> usize {
1040        self.sp_header
1041            .write_to_be_bytes(&mut self.buf[0..CCSDS_HEADER_LEN])
1042            .unwrap();
1043        let len = self.packet_len();
1044        match self.checksum {
1045            Some(ChecksumType::WithCrc16) => {
1046                let crc16 = CRC_CCITT_FALSE.checksum(&self.buf[0..len - 2]);
1047                self.buf[len - 2..len].copy_from_slice(&crc16.to_be_bytes());
1048            }
1049            None | Some(ChecksumType::WithCrc16ButIgnored) => (),
1050        };
1051        len
1052    }
1053}
1054
1055impl CcsdsPacket for CcsdsPacketCreatorWithReservedData<'_> {
1056    /// CCSDS version field.
1057    #[inline]
1058    fn ccsds_version(&self) -> arbitrary_int::u3 {
1059        self.sp_header.ccsds_version()
1060    }
1061
1062    /// CCSDS packet ID field.
1063    #[inline]
1064    fn packet_id(&self) -> PacketId {
1065        self.sp_header.packet_id()
1066    }
1067
1068    /// CCSDS packet sequence control field.
1069    #[inline]
1070    fn psc(&self) -> PacketSequenceControl {
1071        self.sp_header.psc()
1072    }
1073
1074    /// CCSDS data length field.
1075    #[inline]
1076    fn data_len(&self) -> u16 {
1077        self.sp_header.data_len()
1078    }
1079}
1080
1081/// Simple combination of [PacketId] and [PacketSequenceControl] field of this packet.
1082///
1083/// This is not a standardized structure and should not be confused with the [PacketId] field.
1084/// It can be used for something like CCSDS packet identification in a hashmap or supplying
1085/// the ID of a telecommand for verifiation purposes.
1086#[derive(Debug, PartialEq, Eq, Clone, Copy)]
1087#[cfg_attr(feature = "defmt", derive(defmt::Format))]
1088#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1089pub struct CcsdsPacketIdAndPsc {
1090    /// CCSDS Packet ID.
1091    pub packet_id: PacketId,
1092    /// CCSDS Packet Sequence Control.
1093    pub psc: PacketSequenceControl,
1094}
1095
1096impl Hash for CcsdsPacketIdAndPsc {
1097    fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
1098        self.packet_id.hash(state);
1099        self.psc.raw().hash(state);
1100    }
1101}
1102
1103impl CcsdsPacketIdAndPsc {
1104    /// Generic constructor.
1105    #[inline]
1106    pub const fn new(packet_id: PacketId, psc: PacketSequenceControl) -> Self {
1107        Self { packet_id, psc }
1108    }
1109
1110    /// Extract the CCSDS packet ID from the given [CcsdsPacket].
1111    #[inline]
1112    pub fn new_from_ccsds_packet<P: CcsdsPacket>(packet: &P) -> Self {
1113        Self {
1114            packet_id: packet.packet_id(),
1115            psc: packet.psc(),
1116        }
1117    }
1118
1119    /// Raw numeric value.
1120    #[inline]
1121    pub const fn raw(&self) -> u32 {
1122        ((self.packet_id.raw() as u32) << 16) | self.psc.raw() as u32
1123    }
1124}
1125
1126impl From<SpacePacketHeader> for CcsdsPacketIdAndPsc {
1127    #[inline]
1128    fn from(header: SpacePacketHeader) -> Self {
1129        Self {
1130            packet_id: header.packet_id,
1131            psc: header.psc,
1132        }
1133    }
1134}
1135
1136impl From<&SpacePacketHeader> for CcsdsPacketIdAndPsc {
1137    #[inline]
1138    fn from(header: &SpacePacketHeader) -> Self {
1139        Self {
1140            packet_id: header.packet_id,
1141            psc: header.psc,
1142        }
1143    }
1144}
1145
1146#[derive(Debug)]
1147#[cfg_attr(feature = "defmt", derive(defmt::Format))]
1148#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1149struct CcsdsPacketCreatorCommon {
1150    sp_header: SpHeader,
1151    checksum: Option<ChecksumType>,
1152}
1153
1154impl CcsdsPacketCreatorCommon {
1155    #[inline]
1156    pub fn len_written(&self, packet_data_len: usize) -> usize {
1157        ccsds_packet_len_for_user_data_len(packet_data_len, self.checksum).unwrap()
1158    }
1159
1160    /// [CcsdsPacketIdAndPsc] structure for this packet.
1161    #[inline]
1162    pub fn ccsds_packet_id_and_psc(&self) -> CcsdsPacketIdAndPsc {
1163        CcsdsPacketIdAndPsc::from(self.sp_header)
1164    }
1165
1166    pub fn calculate_data_len_field(
1167        packet_data_len: usize,
1168        checksum: Option<ChecksumType>,
1169    ) -> Result<usize, InvalidPayloadLengthError> {
1170        let sp_data_len = (packet_data_len
1171            + match checksum {
1172                Some(ChecksumType::WithCrc16) | Some(ChecksumType::WithCrc16ButIgnored) => 2,
1173                None => 0,
1174            }
1175            - 1) as u16;
1176        let full_packet_len = match checksum {
1177            Some(crc_type) => match crc_type {
1178                ChecksumType::WithCrc16 | ChecksumType::WithCrc16ButIgnored => {
1179                    CCSDS_HEADER_LEN + packet_data_len + 2
1180                }
1181            },
1182            None => {
1183                // Special case: At least one byte of user data is required.
1184                if packet_data_len == 0 {
1185                    CCSDS_HEADER_LEN + 1
1186                } else {
1187                    CCSDS_HEADER_LEN + packet_data_len
1188                }
1189            }
1190        };
1191        if full_packet_len - CCSDS_HEADER_LEN - 1 > u16::MAX as usize {
1192            return Err(InvalidPayloadLengthError(packet_data_len));
1193        }
1194        Ok(sp_data_len as usize)
1195    }
1196
1197    pub fn new(
1198        mut sp_header: SpHeader,
1199        packet_type: PacketType,
1200        packet_data_len: usize,
1201        checksum: Option<ChecksumType>,
1202    ) -> Result<Self, InvalidPayloadLengthError> {
1203        sp_header.data_len = Self::calculate_data_len_field(packet_data_len, checksum)? as u16;
1204        sp_header.packet_id.packet_type = packet_type;
1205        Ok(Self {
1206            sp_header,
1207            checksum,
1208        })
1209    }
1210
1211    /// Write the CCSDS packet to the provided buffer.
1212    pub fn write_to_bytes(
1213        &self,
1214        buf: &mut [u8],
1215        len_written: usize,
1216        packet_data: &[u8],
1217    ) -> Result<usize, ByteConversionError> {
1218        if len_written > buf.len() {
1219            return Err(ByteConversionError::ToSliceTooSmall {
1220                found: buf.len(),
1221                expected: len_written,
1222            });
1223        }
1224        self.sp_header
1225            .write_to_be_bytes(&mut buf[0..CCSDS_HEADER_LEN])?;
1226        buf[CCSDS_HEADER_LEN..CCSDS_HEADER_LEN + packet_data.len()].copy_from_slice(packet_data);
1227        match self.checksum {
1228            Some(ChecksumType::WithCrc16) => {
1229                let crc16 = CRC_CCITT_FALSE.checksum(&buf[0..len_written - 2]);
1230                buf[len_written - 2..len_written].copy_from_slice(&crc16.to_be_bytes());
1231            }
1232            None | Some(ChecksumType::WithCrc16ButIgnored) => (),
1233        };
1234        Ok(len_written)
1235    }
1236
1237    /// Create a CCSDS packet as a vector.
1238    #[cfg(feature = "alloc")]
1239    pub fn to_vec(&self, len_written: usize, packet_data: &[u8]) -> alloc::vec::Vec<u8> {
1240        let mut vec = alloc::vec![0u8; len_written];
1241        // Can not fail, unless we messed up the len_written method..
1242        self.write_to_bytes(&mut vec, len_written, packet_data)
1243            .unwrap();
1244        vec
1245    }
1246}
1247
1248/// CCSDS packet creator with optional support for a CRC16 CCITT checksum appended to the
1249/// end of the packet.
1250#[derive(Debug)]
1251#[cfg_attr(feature = "defmt", derive(defmt::Format))]
1252#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1253pub struct CcsdsPacketCreator<'app_data> {
1254    common: CcsdsPacketCreatorCommon,
1255    packet_data: &'app_data [u8],
1256}
1257
1258impl<'app_data> CcsdsPacketCreator<'app_data> {
1259    /// CCSDS header length.
1260    pub const HEADER_LEN: usize = CCSDS_HEADER_LEN;
1261
1262    /// Helper function which can be used to determine the full packet length from the user
1263    /// data length, assuming there is a CRC16 appended at the packet.
1264    #[inline]
1265    pub fn packet_len_for_user_data_with_checksum(user_data_len: usize) -> Option<usize> {
1266        ccsds_packet_len_for_user_data_len(user_data_len, Some(ChecksumType::WithCrc16))
1267    }
1268
1269    /// Generic constructor.
1270    pub fn new(
1271        sp_header: SpHeader,
1272        packet_type: PacketType,
1273        packet_data: &'app_data [u8],
1274        checksum: Option<ChecksumType>,
1275    ) -> Result<Self, CcsdsPacketCreationError> {
1276        let common =
1277            CcsdsPacketCreatorCommon::new(sp_header, packet_type, packet_data.len(), checksum)?;
1278        Ok(Self {
1279            packet_data,
1280            common,
1281        })
1282    }
1283
1284    /// Constructor which always appends a CRC16 checksum at the packet end.
1285    pub fn new_with_checksum(
1286        sp_header: SpHeader,
1287        packet_type: PacketType,
1288        app_data: &'app_data [u8],
1289    ) -> Result<Self, CcsdsPacketCreationError> {
1290        Self::new(
1291            sp_header,
1292            packet_type,
1293            app_data,
1294            Some(ChecksumType::WithCrc16),
1295        )
1296    }
1297
1298    /// Constructor for telemetry which always appends a CRC16 checksum at the packet end.
1299    pub fn new_tm_with_checksum(
1300        sp_header: SpHeader,
1301        app_data: &'app_data [u8],
1302    ) -> Result<Self, CcsdsPacketCreationError> {
1303        Self::new(
1304            sp_header,
1305            PacketType::Tm,
1306            app_data,
1307            Some(ChecksumType::WithCrc16),
1308        )
1309    }
1310
1311    /// Constructor for telecommands which always appends a CRC16 checksum at the packet end.
1312    pub fn new_tc_with_checksum(
1313        sp_header: SpHeader,
1314        app_data: &'app_data [u8],
1315    ) -> Result<Self, CcsdsPacketCreationError> {
1316        Self::new(
1317            sp_header,
1318            PacketType::Tc,
1319            app_data,
1320            Some(ChecksumType::WithCrc16),
1321        )
1322    }
1323}
1324
1325impl CcsdsPacketCreator<'_> {
1326    /// Full length when written to bytes.
1327    #[inline]
1328    pub fn len_written(&self) -> usize {
1329        self.common.len_written(self.packet_data.len())
1330    }
1331
1332    /// Write the CCSDS packet to the provided buffer.
1333    pub fn write_to_bytes(&self, buf: &mut [u8]) -> Result<usize, ByteConversionError> {
1334        self.common
1335            .write_to_bytes(buf, self.len_written(), self.packet_data)
1336    }
1337
1338    /// CCSDS space packet header.
1339    #[inline]
1340    pub fn sp_header(&self) -> &SpHeader {
1341        &self.common.sp_header
1342    }
1343
1344    /// [CcsdsPacketIdAndPsc] of this packet.
1345    #[inline]
1346    pub fn ccsds_packet_id_and_psc(&self) -> CcsdsPacketIdAndPsc {
1347        self.common.ccsds_packet_id_and_psc()
1348    }
1349
1350    /// Create a CCSDS packet as a vector.
1351    #[cfg(feature = "alloc")]
1352    pub fn to_vec(&self) -> alloc::vec::Vec<u8> {
1353        self.common.to_vec(self.len_written(), self.packet_data)
1354    }
1355}
1356
1357impl CcsdsPacket for CcsdsPacketCreator<'_> {
1358    /// CCSDS version field.
1359    #[inline]
1360    fn ccsds_version(&self) -> arbitrary_int::u3 {
1361        self.common.sp_header.ccsds_version()
1362    }
1363
1364    /// CCSDS packet ID field.
1365    #[inline]
1366    fn packet_id(&self) -> PacketId {
1367        self.common.sp_header.packet_id()
1368    }
1369
1370    /// CCSDS packet sequence control field.
1371    #[inline]
1372    fn psc(&self) -> PacketSequenceControl {
1373        self.common.sp_header.psc()
1374    }
1375
1376    /// CCSDS data length field.
1377    #[inline]
1378    fn data_len(&self) -> u16 {
1379        self.common.sp_header.data_len()
1380    }
1381}
1382
1383/// CCSDS packet creator variant which owns the packet data.
1384#[cfg(feature = "alloc")]
1385#[derive(Debug)]
1386#[cfg_attr(feature = "defmt", derive(defmt::Format))]
1387#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1388pub struct CcsdsPacketCreatorOwned {
1389    common: CcsdsPacketCreatorCommon,
1390    packet_data: alloc::vec::Vec<u8>,
1391}
1392
1393#[cfg(feature = "alloc")]
1394impl CcsdsPacketCreatorOwned {
1395    /// CCSDS header length.
1396    pub const HEADER_LEN: usize = CCSDS_HEADER_LEN;
1397
1398    /// Helper function which can be used to determine the full packet length from the user
1399    /// data length, assuming there is a CRC16 appended at the packet.
1400    #[inline]
1401    pub fn packet_len_for_user_data_with_checksum(user_data_len: usize) -> Option<usize> {
1402        ccsds_packet_len_for_user_data_len(user_data_len, Some(ChecksumType::WithCrc16))
1403    }
1404
1405    /// Generic constructor.
1406    pub fn new(
1407        sp_header: SpHeader,
1408        packet_type: PacketType,
1409        packet_data: &[u8],
1410        checksum: Option<ChecksumType>,
1411    ) -> Result<Self, CcsdsPacketCreationError> {
1412        let common =
1413            CcsdsPacketCreatorCommon::new(sp_header, packet_type, packet_data.len(), checksum)?;
1414        Ok(Self {
1415            common,
1416            packet_data: packet_data.to_vec(),
1417        })
1418    }
1419
1420    /// Constructor which always appends a CRC16 checksum at the packet end.
1421    pub fn new_with_checksum(
1422        sp_header: SpHeader,
1423        packet_type: PacketType,
1424        packet_data: &[u8],
1425    ) -> Result<Self, CcsdsPacketCreationError> {
1426        Self::new(
1427            sp_header,
1428            packet_type,
1429            packet_data,
1430            Some(ChecksumType::WithCrc16),
1431        )
1432    }
1433
1434    /// Constructor for telemetry which always appends a CRC16 checksum at the packet end.
1435    pub fn new_tm_with_checksum(
1436        sp_header: SpHeader,
1437        packet_data: &[u8],
1438    ) -> Result<Self, CcsdsPacketCreationError> {
1439        Self::new(
1440            sp_header,
1441            PacketType::Tm,
1442            packet_data,
1443            Some(ChecksumType::WithCrc16),
1444        )
1445    }
1446
1447    /// Constructor for telecommands which always appends a CRC16 checksum at the packet end.
1448    pub fn new_tc_with_checksum(
1449        sp_header: SpHeader,
1450        packet_data: &[u8],
1451    ) -> Result<Self, CcsdsPacketCreationError> {
1452        Self::new(
1453            sp_header,
1454            PacketType::Tc,
1455            packet_data,
1456            Some(ChecksumType::WithCrc16),
1457        )
1458    }
1459
1460    /// Full length when written to bytes.
1461    pub fn len_written(&self) -> usize {
1462        self.common.len_written(self.packet_data.len())
1463    }
1464
1465    /// Write the CCSDS packet to the provided buffer.
1466    pub fn write_to_bytes(&self, buf: &mut [u8]) -> Result<usize, ByteConversionError> {
1467        self.common
1468            .write_to_bytes(buf, self.len_written(), &self.packet_data)
1469    }
1470
1471    /// CCSDS space packet header.
1472    #[inline]
1473    pub fn sp_header(&self) -> &SpHeader {
1474        &self.common.sp_header
1475    }
1476
1477    /// [CcsdsPacketIdAndPsc] of this packet.
1478    #[inline]
1479    pub fn ccsds_packet_id_and_psc(&self) -> CcsdsPacketIdAndPsc {
1480        self.common.ccsds_packet_id_and_psc()
1481    }
1482
1483    /// Create a CCSDS packet as a vector.
1484    #[cfg(feature = "alloc")]
1485    pub fn to_vec(&self) -> alloc::vec::Vec<u8> {
1486        self.common.to_vec(self.len_written(), &self.packet_data)
1487    }
1488}
1489
1490#[cfg(feature = "alloc")]
1491impl CcsdsPacket for CcsdsPacketCreatorOwned {
1492    /// CCSDS version field.
1493    #[inline]
1494    fn ccsds_version(&self) -> arbitrary_int::u3 {
1495        self.common.sp_header.ccsds_version()
1496    }
1497
1498    /// CCSDS packet ID field.
1499    #[inline]
1500    fn packet_id(&self) -> PacketId {
1501        self.common.sp_header.packet_id()
1502    }
1503
1504    /// CCSDS packet sequence control field.
1505    #[inline]
1506    fn psc(&self) -> PacketSequenceControl {
1507        self.common.sp_header.psc()
1508    }
1509
1510    /// CCSDS data length field.
1511    #[inline]
1512    fn data_len(&self) -> u16 {
1513        self.common.sp_header.data_len()
1514    }
1515}
1516
1517/// CCSDS packet read error.
1518#[derive(thiserror::Error, Debug, PartialEq, Eq)]
1519#[cfg_attr(feature = "defmt", derive(defmt::Format))]
1520#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1521pub enum CcsdsPacketReadError {
1522    /// Byte conversion error.
1523    #[error("byte conversion: {0}")]
1524    ByteConversion(#[from] ByteConversionError),
1525    /// CRC error.
1526    #[error("CRC error")]
1527    CrcError,
1528}
1529
1530/// CCSDS packet reader structure.
1531#[derive(Debug)]
1532#[cfg_attr(feature = "defmt", derive(defmt::Format))]
1533#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1534pub struct CcsdsPacketReader<'buf> {
1535    sp_header: SpHeader,
1536    packet_data: &'buf [u8],
1537}
1538
1539impl<'buf> CcsdsPacketReader<'buf> {
1540    /// CCSDS header length.
1541    pub const HEADER_LEN: usize = CCSDS_HEADER_LEN;
1542
1543    /// Constructor which expects a CRC16 checksum.
1544    pub fn new_with_checksum(
1545        buf: &'buf [u8],
1546    ) -> Result<CcsdsPacketReader<'buf>, CcsdsPacketReadError> {
1547        Self::new(buf, Some(ChecksumType::WithCrc16))
1548    }
1549
1550    /// Generic constructor.
1551    pub fn new(
1552        buf: &'buf [u8],
1553        checksum: Option<ChecksumType>,
1554    ) -> Result<Self, CcsdsPacketReadError> {
1555        let sp_header = SpHeader::from_be_bytes(&buf[0..CCSDS_HEADER_LEN])?.0;
1556        if sp_header.packet_len() > buf.len() {
1557            return Err(ByteConversionError::FromSliceTooSmall {
1558                found: buf.len(),
1559                expected: sp_header.packet_len(),
1560            }
1561            .into());
1562        }
1563        let user_data = match checksum {
1564            Some(ChecksumType::WithCrc16) => {
1565                if CRC_CCITT_FALSE.checksum(&buf[0..sp_header.packet_len()]) != 0 {
1566                    return Err(CcsdsPacketReadError::CrcError);
1567                }
1568                &buf[CCSDS_HEADER_LEN..sp_header.packet_len() - 2]
1569            }
1570            Some(ChecksumType::WithCrc16ButIgnored) => {
1571                &buf[CCSDS_HEADER_LEN..sp_header.packet_len() - 2]
1572            }
1573            None => &buf[CCSDS_HEADER_LEN..sp_header.packet_len()],
1574        };
1575        Ok(Self {
1576            sp_header,
1577            packet_data: user_data,
1578        })
1579    }
1580}
1581
1582impl CcsdsPacketReader<'_> {
1583    /// Space pacekt header.
1584    #[inline]
1585    pub fn sp_header(&self) -> &SpHeader {
1586        &self.sp_header
1587    }
1588
1589    /// [CcsdsPacketIdAndPsc] structure for this packet.
1590    #[inline]
1591    pub fn ccsds_packet_id_and_psc(&self) -> CcsdsPacketIdAndPsc {
1592        CcsdsPacketIdAndPsc::new_from_ccsds_packet(self)
1593    }
1594
1595    /// CCSDS packet type.
1596    #[inline]
1597    pub fn packet_type(&self) -> PacketType {
1598        self.sp_header.packet_id.packet_type
1599    }
1600
1601    /// Read-only access to the packet data field.
1602    #[inline]
1603    pub fn packet_data(&self) -> &[u8] {
1604        self.packet_data
1605    }
1606
1607    /// 11-bit Application Process ID field.
1608    #[inline]
1609    pub fn apid(&self) -> u11 {
1610        self.sp_header.apid()
1611    }
1612
1613    /// CCSDS packet ID field.
1614    #[inline]
1615    pub fn packet_id(&self) -> PacketId {
1616        self.sp_header.packet_id()
1617    }
1618
1619    /// Packet sequence control field.
1620    #[inline]
1621    pub fn psc(&self) -> PacketSequenceControl {
1622        self.sp_header.psc()
1623    }
1624
1625    /// Full packet length with the CCSDS header.
1626    #[inline]
1627    pub fn packet_len(&self) -> usize {
1628        <Self as CcsdsPacket>::packet_len(self)
1629    }
1630
1631    /// Packet data length field.
1632    #[inline]
1633    pub fn data_len(&self) -> u16 {
1634        self.sp_header.data_len()
1635    }
1636}
1637
1638impl CcsdsPacket for CcsdsPacketReader<'_> {
1639    /// CCSDS version field.
1640    #[inline]
1641    fn ccsds_version(&self) -> arbitrary_int::u3 {
1642        self.sp_header.ccsds_version()
1643    }
1644
1645    /// Packet ID field.
1646    #[inline]
1647    fn packet_id(&self) -> PacketId {
1648        self.packet_id()
1649    }
1650
1651    /// Packet sequence control field.
1652    #[inline]
1653    fn psc(&self) -> PacketSequenceControl {
1654        self.psc()
1655    }
1656
1657    /// Packet data length without the CCSDS header.
1658    #[inline]
1659    fn data_len(&self) -> u16 {
1660        self.data_len()
1661    }
1662}
1663
1664#[cfg(all(test, feature = "std"))]
1665pub(crate) mod tests {
1666    use std::collections::HashSet;
1667
1668    use super::*;
1669    use crate::crc::CRC_CCITT_FALSE;
1670    #[allow(unused_imports)]
1671    use crate::ByteConversionError;
1672    #[cfg(feature = "serde")]
1673    use crate::CcsdsPrimaryHeader;
1674    use crate::{SequenceFlags, SpHeader};
1675    use alloc::vec;
1676    use arbitrary_int::{u11, u14};
1677    #[cfg(feature = "serde")]
1678    use core::fmt::Debug;
1679    #[cfg(feature = "serde")]
1680    use postcard::{from_bytes, to_allocvec};
1681    #[cfg(feature = "serde")]
1682    use serde::{de::DeserializeOwned, Serialize};
1683    use zerocopy::FromBytes;
1684
1685    const CONST_SP: SpHeader = SpHeader::new(
1686        PacketId::new_for_tc(true, u11::new(0x36)),
1687        PacketSequenceControl::new(SequenceFlags::ContinuationSegment, u14::new(0x88)),
1688        0x90,
1689    );
1690
1691    const PACKET_ID_TM: PacketId = PacketId::new_for_tm(true, u11::new(0x22));
1692
1693    #[cfg(feature = "serde")]
1694    pub(crate) fn generic_serde_test<T: Serialize + DeserializeOwned + PartialEq + Debug>(
1695        value: T,
1696    ) {
1697        let output: alloc::vec::Vec<u8> = to_allocvec(&value).unwrap();
1698        let output_converted_back: T = from_bytes(&output).unwrap();
1699        assert_eq!(output_converted_back, value);
1700    }
1701
1702    #[test]
1703    #[allow(clippy::assertions_on_constants)]
1704    fn verify_const_packet_id() {
1705        assert_eq!(PACKET_ID_TM.apid().value(), 0x22);
1706        assert!(PACKET_ID_TM.sec_header_flag);
1707        assert_eq!(PACKET_ID_TM.packet_type, PacketType::Tm);
1708        let const_tc_id = PacketId::new_for_tc(true, u11::new(0x23));
1709        assert_eq!(const_tc_id.packet_type, PacketType::Tc);
1710    }
1711
1712    #[test]
1713    fn test_default_packet_id() {
1714        let id_default = PacketId::default();
1715        assert_eq!(id_default.packet_type, PacketType::Tm);
1716        assert_eq!(id_default.apid.value(), 0x000);
1717        assert!(!id_default.sec_header_flag);
1718    }
1719
1720    #[test]
1721    fn test_packet_id_ctors() {
1722        let packet_id = PacketId::new(PacketType::Tc, true, u11::new(0x1ff));
1723        assert_eq!(packet_id.apid().value(), 0x1ff);
1724        assert_eq!(packet_id.packet_type, PacketType::Tc);
1725        assert!(packet_id.sec_header_flag);
1726        let packet_id_tc = PacketId::new_for_tc(true, u11::new(0x1ff));
1727        assert_eq!(packet_id_tc, packet_id);
1728        let packet_id_tm = PacketId::new_for_tm(true, u11::new(0x2ff));
1729        assert!(packet_id_tm.sec_header_flag);
1730        assert_eq!(packet_id_tm.packet_type, PacketType::Tm);
1731        assert_eq!(packet_id_tm.apid, u11::new(0x2ff));
1732    }
1733
1734    #[test]
1735    fn verify_const_sp_header() {
1736        assert!(CONST_SP.sec_header_flag());
1737        assert_eq!(CONST_SP.apid().value(), 0x36);
1738        assert_eq!(
1739            CONST_SP.sequence_flags(),
1740            SequenceFlags::ContinuationSegment
1741        );
1742        assert_eq!(CONST_SP.seq_count().value(), 0x88);
1743        assert_eq!(CONST_SP.data_len, 0x90);
1744    }
1745
1746    #[test]
1747    fn test_seq_flag_helpers() {
1748        assert_eq!(
1749            SequenceFlags::try_from(0b00).expect("SEQ flag creation failed"),
1750            SequenceFlags::ContinuationSegment
1751        );
1752        assert_eq!(
1753            SequenceFlags::try_from(0b01).expect("SEQ flag creation failed"),
1754            SequenceFlags::FirstSegment
1755        );
1756        assert_eq!(
1757            SequenceFlags::try_from(0b10).expect("SEQ flag creation failed"),
1758            SequenceFlags::LastSegment
1759        );
1760        assert_eq!(
1761            SequenceFlags::try_from(0b11).expect("SEQ flag creation failed"),
1762            SequenceFlags::Unsegmented
1763        );
1764        assert!(SequenceFlags::try_from(0b100).is_err());
1765    }
1766
1767    #[test]
1768    fn test_packet_type_helper() {
1769        assert_eq!(PacketType::try_from(0b00).unwrap(), PacketType::Tm);
1770        assert_eq!(PacketType::try_from(0b01).unwrap(), PacketType::Tc);
1771        assert!(PacketType::try_from(0b10).is_err());
1772    }
1773
1774    #[test]
1775    fn test_packet_id() {
1776        let packet_id = PacketId::new(PacketType::Tm, false, u11::new(0x42));
1777        assert_eq!(packet_id.raw(), 0x0042);
1778        let packet_id_from_raw = PacketId::from(packet_id.raw());
1779        assert_eq!(
1780            packet_type_in_raw_packet_id(packet_id.raw()),
1781            PacketType::Tm
1782        );
1783        assert_eq!(packet_id_from_raw, packet_id);
1784        let packet_id_from_new = PacketId::new(PacketType::Tm, false, u11::new(0x42));
1785        assert_eq!(packet_id_from_new, packet_id);
1786    }
1787
1788    #[test]
1789    fn test_packet_seq_ctrl() {
1790        let psc = PacketSequenceControl::new(SequenceFlags::ContinuationSegment, u14::new(77));
1791        assert_eq!(psc.raw(), 77);
1792        let psc_from_raw = PacketSequenceControl::from(psc.raw());
1793        assert_eq!(psc_from_raw, psc);
1794    }
1795
1796    #[test]
1797    #[cfg(feature = "serde")]
1798    fn test_serde_sph() {
1799        let sp_header = SpHeader::new_for_unseg_tc(u11::new(0x42), u14::new(12), 0);
1800        assert_eq!(sp_header.ccsds_version().value(), 0b000);
1801        assert!(sp_header.is_tc());
1802        assert!(!sp_header.sec_header_flag());
1803        assert_eq!(sp_header.packet_type(), PacketType::Tc);
1804        assert_eq!(sp_header.seq_count().value(), 12);
1805        assert_eq!(sp_header.apid().value(), 0x42);
1806        assert_eq!(sp_header.sequence_flags(), SequenceFlags::Unsegmented);
1807        assert_eq!(sp_header.data_len(), 0);
1808        let output = to_allocvec(&sp_header).unwrap();
1809        let sp_header: SpHeader = from_bytes(&output).unwrap();
1810        assert_eq!(sp_header.version.value(), 0b000);
1811        assert!(!sp_header.packet_id.sec_header_flag);
1812        assert_eq!(sp_header.packet_type(), PacketType::Tc);
1813        assert_eq!(sp_header.seq_count().value(), 12);
1814        assert_eq!(sp_header.apid().value(), 0x42);
1815        assert_eq!(sp_header.sequence_flags(), SequenceFlags::Unsegmented);
1816        assert_eq!(sp_header.packet_id_raw(), 0x1042);
1817        assert_eq!(sp_header.psc_raw(), 0xC00C);
1818        assert_eq!(sp_header.ccsds_version().value(), 0b000);
1819        assert_eq!(sp_header.data_len, 0);
1820
1821        let sp_header = SpHeader::new_for_unseg_tm(u11::new(0x7), u14::new(22), 36);
1822        assert_eq!(sp_header.ccsds_version().value(), 0b000);
1823        assert!(sp_header.is_tm());
1824        assert!(!sp_header.sec_header_flag());
1825        assert_eq!(sp_header.packet_type(), PacketType::Tm);
1826        assert_eq!(sp_header.seq_count().value(), 22);
1827        assert_eq!(sp_header.apid().value(), 0x07);
1828        assert_eq!(sp_header.sequence_flags(), SequenceFlags::Unsegmented);
1829        assert_eq!(sp_header.packet_id_raw(), 0x0007);
1830        assert_eq!(sp_header.psc_raw(), 0xC016);
1831        assert_eq!(sp_header.data_len(), 36);
1832        assert_eq!(sp_header.ccsds_version().value(), 0b000);
1833
1834        let from_comp_fields = SpHeader::new_from_composite_fields(
1835            PacketId::new(PacketType::Tc, true, u11::new(0x42)),
1836            PacketSequenceControl::new(SequenceFlags::Unsegmented, u14::new(0x7)),
1837            0,
1838            None,
1839        );
1840        assert_eq!(from_comp_fields.packet_type(), PacketType::Tc);
1841        assert_eq!(from_comp_fields.apid().value(), 0x42);
1842        assert!(from_comp_fields.sec_header_flag());
1843        assert_eq!(
1844            from_comp_fields.sequence_flags(),
1845            SequenceFlags::Unsegmented
1846        );
1847        assert_eq!(from_comp_fields.seq_count().value(), 0x7);
1848        assert_eq!(from_comp_fields.data_len(), 0);
1849    }
1850
1851    #[test]
1852    fn test_setters() {
1853        let mut sp_header =
1854            SpHeader::new_for_tc(u11::new(0x42), SequenceFlags::Unsegmented, u14::new(25), 0);
1855        sp_header.set_apid(u11::new(0x12));
1856        assert_eq!(sp_header.apid().as_u16(), 0x12);
1857        sp_header.set_sec_header_flag();
1858        assert!(sp_header.sec_header_flag());
1859        sp_header.clear_sec_header_flag();
1860        assert!(!sp_header.sec_header_flag());
1861        assert_eq!(sp_header.packet_type(), PacketType::Tc);
1862        sp_header.set_packet_type(PacketType::Tm);
1863        assert_eq!(sp_header.packet_type(), PacketType::Tm);
1864        sp_header.set_seq_count(u14::new(0x45));
1865        assert_eq!(sp_header.seq_count().as_u16(), 0x45);
1866    }
1867
1868    #[test]
1869    fn test_tc_ctor() {
1870        let sp_header =
1871            SpHeader::new_for_tc(u11::new(0x42), SequenceFlags::Unsegmented, u14::new(25), 0);
1872        verify_sp_fields(PacketType::Tc, &sp_header);
1873    }
1874
1875    #[test]
1876    fn test_tc_ctor_unseg() {
1877        let sp_header = SpHeader::new_for_unseg_tc(u11::new(0x42), u14::new(25), 0);
1878        verify_sp_fields(PacketType::Tc, &sp_header);
1879    }
1880
1881    #[test]
1882    fn test_tc_ctor_unseg_const() {
1883        let sp_header = SpHeader::new_for_unseg_tc(u11::new(0x42), u14::new(25), 0);
1884        verify_sp_fields(PacketType::Tc, &sp_header);
1885    }
1886
1887    #[test]
1888    fn test_tm_ctor() {
1889        let sp_header =
1890            SpHeader::new_for_tm(u11::new(0x42), SequenceFlags::Unsegmented, u14::new(25), 0);
1891        verify_sp_fields(PacketType::Tm, &sp_header);
1892    }
1893
1894    #[test]
1895    fn test_tm_ctor_const() {
1896        let sp_header =
1897            SpHeader::new_for_tm(u11::new(0x42), SequenceFlags::Unsegmented, u14::new(25), 0);
1898        verify_sp_fields(PacketType::Tm, &sp_header);
1899    }
1900
1901    #[test]
1902    fn test_tm_ctor_unseg() {
1903        let sp_header = SpHeader::new_for_unseg_tm(u11::new(0x42), u14::new(25), 0);
1904        verify_sp_fields(PacketType::Tm, &sp_header);
1905    }
1906
1907    fn verify_sp_fields(ptype: PacketType, sp_header: &SpHeader) {
1908        assert_eq!(sp_header.packet_type(), ptype);
1909        assert_eq!(sp_header.sequence_flags(), SequenceFlags::Unsegmented);
1910        assert_eq!(sp_header.apid().value(), 0x42);
1911        assert_eq!(sp_header.seq_count(), u14::new(25));
1912        assert_eq!(sp_header.data_len(), 0);
1913    }
1914
1915    #[test]
1916    fn test_zc_sph() {
1917        use zerocopy::IntoBytes;
1918
1919        let sp_header = SpHeader::new_for_unseg_tc(u11::MAX, u14::MAX, 0);
1920        assert_eq!(sp_header.packet_type(), PacketType::Tc);
1921        assert_eq!(sp_header.apid().value(), 0x7FF);
1922        assert_eq!(sp_header.data_len(), 0);
1923        assert_eq!(sp_header.ccsds_version().value(), 0b000);
1924        assert!(sp_header.is_tc());
1925        let sp_header_zc = zc::SpHeader::from(sp_header);
1926        let slice = sp_header_zc.as_bytes();
1927        assert_eq!(slice.len(), 6);
1928        assert_eq!(slice[0], 0x17);
1929        assert_eq!(slice[1], 0xFF);
1930        assert_eq!(slice[2], 0xFF);
1931        assert_eq!(slice[3], 0xFF);
1932        assert_eq!(slice[4], 0x00);
1933        assert_eq!(slice[5], 0x00);
1934
1935        let mut slice = [0; 6];
1936        sp_header_zc.write_to(slice.as_mut_slice()).unwrap();
1937        assert_eq!(slice.len(), 6);
1938        assert_eq!(slice[0], 0x17);
1939        assert_eq!(slice[1], 0xFF);
1940        assert_eq!(slice[2], 0xFF);
1941        assert_eq!(slice[3], 0xFF);
1942        assert_eq!(slice[4], 0x00);
1943        assert_eq!(slice[5], 0x00);
1944
1945        let mut test_vec = vec![0_u8; 6];
1946        let slice = test_vec.as_mut_slice();
1947        sp_header_zc.write_to(slice).unwrap();
1948        let slice = test_vec.as_slice();
1949        assert_eq!(slice.len(), 6);
1950        assert_eq!(slice[0], 0x17);
1951        assert_eq!(slice[1], 0xFF);
1952        assert_eq!(slice[2], 0xFF);
1953        assert_eq!(slice[3], 0xFF);
1954        assert_eq!(slice[4], 0x00);
1955        assert_eq!(slice[5], 0x00);
1956
1957        let sp_header = zc::SpHeader::read_from_bytes(slice);
1958        assert!(sp_header.is_ok());
1959        let sp_header = sp_header.unwrap();
1960        assert_eq!(sp_header.ccsds_version().value(), 0b000);
1961        assert_eq!(sp_header.packet_id_raw(), 0x17FF);
1962        assert_eq!(sp_header.apid().value(), 0x7FF);
1963        assert_eq!(sp_header.packet_type(), PacketType::Tc);
1964        assert_eq!(sp_header.data_len(), 0);
1965    }
1966
1967    #[test]
1968    fn packet_id_ord_partial_ord() {
1969        let packet_id_small = PacketId::from(1_u16);
1970        let packet_id_larger = PacketId::from(2_u16);
1971        assert!(packet_id_small < packet_id_larger);
1972        assert!(packet_id_larger > packet_id_small);
1973        assert_eq!(
1974            packet_id_small.cmp(&packet_id_larger),
1975            core::cmp::Ordering::Less
1976        );
1977    }
1978
1979    #[test]
1980    fn packet_id_hashable() {
1981        let mut id_set = HashSet::new();
1982        id_set.insert(PacketId::from(1_u16));
1983    }
1984
1985    #[test]
1986    fn sp_header_from_apid() {
1987        let sp_header = SpHeader::new_from_apid(u11::new(0x03));
1988        assert_eq!(sp_header.apid().value(), 0x03);
1989        assert_eq!(sp_header.data_len(), 0);
1990    }
1991
1992    #[cfg(feature = "defmt")]
1993    fn is_defmt_format<T: defmt::Format>(_t: T) {}
1994
1995    #[test]
1996    #[cfg(feature = "defmt")]
1997    fn test_defmt_format() {
1998        is_defmt_format(ByteConversionError::ToSliceTooSmall {
1999            found: 1,
2000            expected: 2,
2001        });
2002    }
2003
2004    #[test]
2005    fn test_sp_header_as_vec() {
2006        let sp_header = SpHeader::new_for_unseg_tc(u11::new(0x42), u14::new(25), 1);
2007        let sp_header_as_vec = sp_header.to_vec();
2008        let sp_header_read_back = SpHeader::from_be_bytes(&sp_header_as_vec)
2009            .expect("Error reading back SP header")
2010            .0;
2011        assert_eq!(sp_header, sp_header_read_back);
2012    }
2013
2014    #[test]
2015    fn test_ccsds_size_function() {
2016        assert_eq!(ccsds_packet_len_for_user_data_len(1, None).unwrap(), 7);
2017        // Special case: One dummy byte is required.
2018        assert_eq!(ccsds_packet_len_for_user_data_len(0, None).unwrap(), 7);
2019        assert_eq!(
2020            ccsds_packet_len_for_user_data_len(1, Some(ChecksumType::WithCrc16)).unwrap(),
2021            9
2022        );
2023        assert_eq!(
2024            ccsds_packet_len_for_user_data_len_with_checksum(1).unwrap(),
2025            9
2026        );
2027    }
2028
2029    #[test]
2030    fn test_ccsds_size_function_invalid_size_no_checksum() {
2031        // This works, because the data field is the user data length minus 1.
2032        assert!(ccsds_packet_len_for_user_data_len(u16::MAX as usize + 1, None).is_some());
2033        // This does not work, data field length exceeded.
2034        assert!(ccsds_packet_len_for_user_data_len(u16::MAX as usize + 2, None).is_none());
2035    }
2036
2037    #[test]
2038    fn test_ccsds_size_function_invalid_size_with_checksum() {
2039        // 2 less bytes available because of the checksum.
2040        assert!(ccsds_packet_len_for_user_data_len(
2041            u16::MAX as usize - 1,
2042            Some(ChecksumType::WithCrc16)
2043        )
2044        .is_some());
2045        // This is too much.
2046        assert!(ccsds_packet_len_for_user_data_len(
2047            u16::MAX as usize,
2048            Some(ChecksumType::WithCrc16)
2049        )
2050        .is_none());
2051    }
2052
2053    #[test]
2054    fn test_ccsds_creator_api() {
2055        let mut buf: [u8; 32] = [0; 32];
2056        let apid = u11::new(0x1);
2057        let packet_type = PacketType::Tc;
2058        let mut packet_creator = CcsdsPacketCreatorWithReservedData::new(
2059            SpacePacketHeader::new_from_apid(apid),
2060            packet_type,
2061            4,
2062            &mut buf,
2063            Some(ChecksumType::WithCrc16),
2064        )
2065        .unwrap();
2066        assert_eq!(packet_creator.packet_len(), 12);
2067        assert_eq!(packet_creator.raw_buffer().len(), 12);
2068        assert_eq!(packet_creator.data_len(), 5);
2069        assert_eq!(packet_creator.apid().value(), 0x1);
2070        assert_eq!(
2071            packet_creator.packet_id(),
2072            PacketId::new(packet_type, false, apid)
2073        );
2074        assert_eq!(
2075            packet_creator.psc(),
2076            PacketSequenceControl::new(SequenceFlags::Unsegmented, u14::new(0))
2077        );
2078        assert_eq!(packet_creator.packet_data_mut(), &mut [0, 0, 0, 0]);
2079        assert_eq!(packet_creator.packet_data(), &[0, 0, 0, 0]);
2080        assert_eq!(packet_creator.ccsds_version(), u3::new(0b000));
2081    }
2082
2083    #[test]
2084    fn test_ccsds_creator_api_no_checksum() {
2085        let mut buf: [u8; 32] = [0; 32];
2086        let apid = u11::new(0x1);
2087        let packet_type = PacketType::Tm;
2088        let mut packet_creator = CcsdsPacketCreatorWithReservedData::new(
2089            SpacePacketHeader::new_from_apid(u11::new(0x1)),
2090            PacketType::Tm,
2091            4,
2092            &mut buf,
2093            None,
2094        )
2095        .unwrap();
2096        assert_eq!(packet_creator.packet_len(), 10);
2097        assert_eq!(packet_creator.data_len(), 3);
2098        assert_eq!(packet_creator.apid().value(), 0x1);
2099        assert_eq!(
2100            packet_creator.packet_id(),
2101            PacketId::new(packet_type, false, apid)
2102        );
2103        assert_eq!(
2104            packet_creator.psc(),
2105            PacketSequenceControl::new(SequenceFlags::Unsegmented, u14::new(0))
2106        );
2107        assert_eq!(packet_creator.packet_data_mut(), &mut [0, 0, 0, 0]);
2108        assert_eq!(packet_creator.packet_data(), &[0, 0, 0, 0]);
2109    }
2110
2111    #[test]
2112    fn test_ccsds_creator_creation_with_reserved_data_alt_ctor() {
2113        let mut buf: [u8; 32] = [0; 32];
2114        let data = [1, 2, 3, 4];
2115        let mut packet_creator = CcsdsPacketCreatorWithReservedData::new_with_checksum(
2116            SpacePacketHeader::new_from_apid(u11::new(0x1)),
2117            PacketType::Tc,
2118            4,
2119            &mut buf,
2120        )
2121        .unwrap();
2122        packet_creator.packet_data_mut().copy_from_slice(&data);
2123        let written_len = packet_creator.finish();
2124        assert_eq!(
2125            CcsdsPacketCreatorWithReservedData::packet_len_for_user_data_with_checksum(4).unwrap(),
2126            written_len
2127        );
2128        assert_eq!(CRC_CCITT_FALSE.checksum(&buf[0..written_len]), 0);
2129        let sp_header = SpacePacketHeader::from_be_bytes(
2130            &buf[0..CcsdsPacketCreatorWithReservedData::HEADER_LEN],
2131        )
2132        .unwrap()
2133        .0;
2134        assert_eq!(sp_header.apid().value(), 0x1);
2135        assert_eq!(buf[6], 1);
2136        assert_eq!(buf[7], 2);
2137        assert_eq!(buf[8], 3);
2138        assert_eq!(buf[9], 4);
2139        assert_eq!(buf[12], 0);
2140    }
2141
2142    #[test]
2143    fn test_ccsds_creator_creation_with_reserved_data() {
2144        let mut buf: [u8; 32] = [0; 32];
2145        let data = [1, 2, 3, 4];
2146        let mut packet_creator = CcsdsPacketCreatorWithReservedData::new(
2147            SpacePacketHeader::new_from_apid(u11::new(0x1)),
2148            PacketType::Tc,
2149            4,
2150            &mut buf,
2151            Some(ChecksumType::WithCrc16),
2152        )
2153        .unwrap();
2154        packet_creator.packet_data_mut().copy_from_slice(&data);
2155        let written_len = packet_creator.finish();
2156        assert_eq!(
2157            CcsdsPacketCreatorWithReservedData::packet_len_for_user_data_with_checksum(4).unwrap(),
2158            written_len
2159        );
2160        assert_eq!(CRC_CCITT_FALSE.checksum(&buf[0..written_len]), 0);
2161        let sp_header = SpacePacketHeader::from_be_bytes(
2162            &buf[0..CcsdsPacketCreatorWithReservedData::HEADER_LEN],
2163        )
2164        .unwrap()
2165        .0;
2166        assert_eq!(sp_header.apid().value(), 0x1);
2167        assert_eq!(sp_header.packet_type(), PacketType::Tc);
2168        assert_eq!(buf[6], 1);
2169        assert_eq!(buf[7], 2);
2170        assert_eq!(buf[8], 3);
2171        assert_eq!(buf[9], 4);
2172        assert_eq!(buf[12], 0);
2173    }
2174
2175    #[test]
2176    fn test_ccsds_creator_creation_empty_user_data_no_checksum() {
2177        let mut buf: [u8; 32] = [0; 32];
2178        let packet_creator = CcsdsPacketCreatorWithReservedData::new(
2179            SpacePacketHeader::new_from_apid(u11::new(0x1)),
2180            PacketType::Tc,
2181            0,
2182            &mut buf,
2183            None,
2184        )
2185        .unwrap();
2186        // Special case.
2187        assert_eq!(packet_creator.packet_len(), 7);
2188        packet_creator.finish();
2189        let reader = CcsdsPacketReader::new(&buf[0..7], None).unwrap();
2190        // Enforced 1 byte packet length.
2191        assert_eq!(reader.packet_data(), &[0]);
2192        assert_eq!(reader.packet_len(), 7);
2193    }
2194
2195    #[test]
2196    fn test_ccsds_creator_creation_ignored_checksum() {
2197        let mut buf: [u8; 32] = [0; 32];
2198        let data = [1, 2, 3, 4, 5];
2199        let mut packet_creator = CcsdsPacketCreatorWithReservedData::new(
2200            SpacePacketHeader::new_from_apid(u11::new(0x1)),
2201            PacketType::Tc,
2202            data.len(),
2203            &mut buf,
2204            Some(ChecksumType::WithCrc16ButIgnored),
2205        )
2206        .unwrap();
2207        packet_creator.packet_data_mut().copy_from_slice(&data);
2208        // Special case.
2209        assert_eq!(packet_creator.packet_len(), 13);
2210        packet_creator.finish();
2211        let reader =
2212            CcsdsPacketReader::new(&buf[0..13], Some(ChecksumType::WithCrc16ButIgnored)).unwrap();
2213        // Enforced 1 byte packet length.
2214        assert_eq!(reader.packet_data(), &data);
2215        assert_eq!(reader.packet_len(), 13);
2216    }
2217
2218    #[test]
2219    fn test_ccsds_creator_creation_buf_too_small() {
2220        let mut buf: [u8; 8] = [0; 8];
2221        let packet_creator = CcsdsPacketCreatorWithReservedData::new(
2222            SpacePacketHeader::new_from_apid(u11::new(0x1)),
2223            PacketType::Tc,
2224            4,
2225            &mut buf,
2226            None,
2227        );
2228        assert!(packet_creator.is_err());
2229        matches!(
2230            packet_creator.unwrap_err(),
2231            CcsdsPacketCreationError::ByteConversion(ByteConversionError::ToSliceTooSmall {
2232                found: 8,
2233                expected: 10
2234            })
2235        );
2236    }
2237
2238    #[test]
2239    fn test_ccsds_creator_creation_with_reserved_data_tc_api() {
2240        let mut buf: [u8; 32] = [0; 32];
2241        let data = [1, 2, 3, 4];
2242        let mut packet_creator = CcsdsPacketCreatorWithReservedData::new_tc_with_checksum(
2243            SpacePacketHeader::new_from_apid(u11::new(0x1)),
2244            4,
2245            &mut buf,
2246        )
2247        .unwrap();
2248        packet_creator.packet_data_mut().copy_from_slice(&data);
2249        let written_len = packet_creator.finish();
2250        assert_eq!(
2251            CcsdsPacketCreatorWithReservedData::packet_len_for_user_data_with_checksum(4).unwrap(),
2252            written_len
2253        );
2254        assert_eq!(CRC_CCITT_FALSE.checksum(&buf[0..written_len]), 0);
2255        let sp_header = SpacePacketHeader::from_be_bytes(
2256            &buf[0..CcsdsPacketCreatorWithReservedData::HEADER_LEN],
2257        )
2258        .unwrap()
2259        .0;
2260        assert_eq!(sp_header.apid().value(), 0x1);
2261        assert_eq!(sp_header.packet_type(), PacketType::Tc);
2262        assert_eq!(buf[6], 1);
2263        assert_eq!(buf[7], 2);
2264        assert_eq!(buf[8], 3);
2265        assert_eq!(buf[9], 4);
2266        assert_eq!(buf[12], 0);
2267    }
2268
2269    #[test]
2270    fn test_ccsds_creator_creation_with_reserved_data_tm_api() {
2271        let mut buf: [u8; 32] = [0; 32];
2272        let data = [1, 2, 3, 4];
2273        let mut packet_creator = CcsdsPacketCreatorWithReservedData::new_tm_with_checksum(
2274            SpacePacketHeader::new_from_apid(u11::new(0x1)),
2275            4,
2276            &mut buf,
2277        )
2278        .unwrap();
2279        packet_creator.packet_data_mut().copy_from_slice(&data);
2280        let written_len = packet_creator.finish();
2281        assert_eq!(
2282            CcsdsPacketCreatorWithReservedData::packet_len_for_user_data_with_checksum(4).unwrap(),
2283            written_len
2284        );
2285        assert_eq!(CRC_CCITT_FALSE.checksum(&buf[0..written_len]), 0);
2286        let sp_header = SpacePacketHeader::from_be_bytes(
2287            &buf[0..CcsdsPacketCreatorWithReservedData::HEADER_LEN],
2288        )
2289        .unwrap()
2290        .0;
2291        assert_eq!(sp_header.apid().value(), 0x1);
2292        assert_eq!(sp_header.packet_type(), PacketType::Tm);
2293        assert_eq!(buf[6], 1);
2294        assert_eq!(buf[7], 2);
2295        assert_eq!(buf[8], 3);
2296        assert_eq!(buf[9], 4);
2297        assert_eq!(buf[12], 0);
2298    }
2299
2300    #[test]
2301    fn test_ccsds_creator_creation_with_reserved_data_no_checksum() {
2302        let mut buf: [u8; 32] = [0; 32];
2303        let data = [1, 2, 3, 4];
2304        let mut packet_creator = CcsdsPacketCreatorWithReservedData::new(
2305            SpacePacketHeader::new_from_apid(u11::new(0x1)),
2306            PacketType::Tc,
2307            4,
2308            &mut buf,
2309            None,
2310        )
2311        .unwrap();
2312        let sph = *packet_creator.sp_header();
2313        packet_creator.packet_data_mut().copy_from_slice(&data);
2314        assert_eq!(
2315            packet_creator.ccsds_packet_id_and_psc(),
2316            CcsdsPacketIdAndPsc::from(sph)
2317        );
2318        let written_len = packet_creator.finish();
2319        assert_eq!(written_len, 10);
2320        let sp_header = SpacePacketHeader::from_be_bytes(
2321            &buf[0..CcsdsPacketCreatorWithReservedData::HEADER_LEN],
2322        )
2323        .unwrap()
2324        .0;
2325        assert_eq!(sp_header.apid().value(), 0x1);
2326        assert_eq!(buf[6], 1);
2327        assert_eq!(buf[7], 2);
2328        assert_eq!(buf[8], 3);
2329        assert_eq!(buf[9], 4);
2330        assert_eq!(buf[10], 0);
2331        assert_eq!(buf[11], 0);
2332    }
2333
2334    fn generic_ccsds_creator_test(alt_api: bool, owned: bool) {
2335        let data = [1, 2, 3, 4];
2336        let mut sp_header = SpacePacketHeader::new_from_apid(u11::new(0x1));
2337        sp_header.set_packet_type(PacketType::Tc);
2338
2339        let packet_raw = match (alt_api, owned) {
2340            (true, true) => CcsdsPacketCreatorOwned::new(
2341                sp_header,
2342                PacketType::Tc,
2343                &data,
2344                Some(ChecksumType::WithCrc16),
2345            )
2346            .unwrap()
2347            .to_vec(),
2348            (true, false) => CcsdsPacketCreator::new(
2349                sp_header,
2350                PacketType::Tc,
2351                &data,
2352                Some(ChecksumType::WithCrc16),
2353            )
2354            .unwrap()
2355            .to_vec(),
2356            (false, true) => {
2357                CcsdsPacketCreatorOwned::new_with_checksum(sp_header, PacketType::Tc, &data)
2358                    .unwrap()
2359                    .to_vec()
2360            }
2361            (false, false) => {
2362                CcsdsPacketCreator::new_with_checksum(sp_header, PacketType::Tc, &data)
2363                    .unwrap()
2364                    .to_vec()
2365            }
2366        };
2367        assert_eq!(CRC_CCITT_FALSE.checksum(&packet_raw), 0);
2368        let sp_header_from_raw = SpacePacketHeader::from_be_bytes(
2369            &packet_raw[0..CcsdsPacketCreatorWithReservedData::HEADER_LEN],
2370        )
2371        .unwrap()
2372        .0;
2373        assert_eq!(sp_header_from_raw.packet_id(), sp_header.packet_id());
2374        assert_eq!(sp_header_from_raw.psc(), sp_header.psc());
2375        assert_eq!(sp_header.apid().value(), 0x1);
2376        assert_eq!(sp_header.packet_type(), PacketType::Tc);
2377        assert_eq!(packet_raw[6], 1);
2378        assert_eq!(packet_raw[7], 2);
2379        assert_eq!(packet_raw[8], 3);
2380        assert_eq!(packet_raw[9], 4);
2381    }
2382
2383    #[test]
2384    fn test_ccsds_creator_creation_0() {
2385        generic_ccsds_creator_test(false, false);
2386    }
2387
2388    #[test]
2389    fn test_ccsds_creator_creation_1() {
2390        generic_ccsds_creator_test(false, true);
2391    }
2392
2393    #[test]
2394    fn test_ccsds_creator_creation_2() {
2395        generic_ccsds_creator_test(true, false);
2396    }
2397
2398    #[test]
2399    fn test_ccsds_creator_creation_3() {
2400        generic_ccsds_creator_test(true, true);
2401    }
2402
2403    #[test]
2404    fn test_ccsds_creator_ignored_checksum() {
2405        let data = [1, 2, 3, 4];
2406        let mut sp_header = SpacePacketHeader::new_from_apid(u11::new(0x1));
2407        sp_header.set_packet_type(PacketType::Tc);
2408        let packet_raw = CcsdsPacketCreatorOwned::new(
2409            sp_header,
2410            PacketType::Tc,
2411            &data,
2412            Some(ChecksumType::WithCrc16ButIgnored),
2413        )
2414        .unwrap()
2415        .to_vec();
2416        let reader =
2417            CcsdsPacketReader::new(&packet_raw, Some(ChecksumType::WithCrc16ButIgnored)).unwrap();
2418        assert_eq!(reader.packet_data(), data);
2419    }
2420
2421    fn generic_test_creator(packet_raw: &[u8], sp_header: &SpHeader, packet_type: PacketType) {
2422        assert_eq!(CRC_CCITT_FALSE.checksum(packet_raw), 0);
2423        let sp_header_from_raw = SpacePacketHeader::from_be_bytes(
2424            &packet_raw[0..CcsdsPacketCreatorWithReservedData::HEADER_LEN],
2425        )
2426        .unwrap()
2427        .0;
2428        assert_eq!(sp_header_from_raw, *sp_header);
2429        assert_eq!(sp_header.packet_type(), packet_type);
2430        assert_eq!(packet_raw[6], 1);
2431        assert_eq!(packet_raw[7], 2);
2432        assert_eq!(packet_raw[8], 3);
2433        assert_eq!(packet_raw[9], 4);
2434    }
2435
2436    #[test]
2437    fn test_ccsds_creator_creation_alt_tc() {
2438        let data = [1, 2, 3, 4];
2439        let packet_creator = CcsdsPacketCreator::new_tc_with_checksum(
2440            SpacePacketHeader::new_from_apid(u11::new(0x1)),
2441            &data,
2442        )
2443        .unwrap();
2444        let packet_raw = packet_creator.to_vec();
2445        generic_test_creator(&packet_raw, packet_creator.sp_header(), PacketType::Tc);
2446    }
2447
2448    #[test]
2449    fn test_ccsds_creator_creation_alt_tc_owned() {
2450        let data = [1, 2, 3, 4];
2451        let packet_creator = CcsdsPacketCreatorOwned::new_tc_with_checksum(
2452            SpacePacketHeader::new_from_apid(u11::new(0x1)),
2453            &data,
2454        )
2455        .unwrap();
2456        let packet_raw = packet_creator.to_vec();
2457        generic_test_creator(&packet_raw, packet_creator.sp_header(), PacketType::Tc);
2458    }
2459
2460    #[test]
2461    fn test_ccsds_creator_creation_alt_tm() {
2462        let data = [1, 2, 3, 4];
2463        let packet_creator = CcsdsPacketCreator::new_tm_with_checksum(
2464            SpacePacketHeader::new_from_apid(u11::new(0x1)),
2465            &data,
2466        )
2467        .unwrap();
2468        let packet_raw = packet_creator.to_vec();
2469        generic_test_creator(&packet_raw, packet_creator.sp_header(), PacketType::Tm);
2470    }
2471
2472    #[test]
2473    fn test_ccsds_creator_creation_alt_tm_owned() {
2474        let data = [1, 2, 3, 4];
2475        let packet_creator = CcsdsPacketCreatorOwned::new_tm_with_checksum(
2476            SpacePacketHeader::new_from_apid(u11::new(0x1)),
2477            &data,
2478        )
2479        .unwrap();
2480        let packet_raw = packet_creator.to_vec();
2481        generic_test_creator(&packet_raw, packet_creator.sp_header(), PacketType::Tm);
2482    }
2483
2484    fn generic_ccsds_reader_test(
2485        packet_data: &[u8],
2486        packet_raw: &[u8],
2487        packet_type: PacketType,
2488        sp_header: SpHeader,
2489    ) {
2490        assert_eq!(
2491            CcsdsPacketCreator::packet_len_for_user_data_with_checksum(4).unwrap(),
2492            packet_raw.len()
2493        );
2494        let reader = CcsdsPacketReader::new_with_checksum(packet_raw).unwrap();
2495        assert_eq!(*reader.sp_header(), sp_header);
2496        assert_eq!(reader.packet_data(), packet_data);
2497        assert_eq!(reader.apid(), u11::new(0x1));
2498        assert_eq!(
2499            reader.packet_id(),
2500            PacketId::new(packet_type, false, u11::new(0x1))
2501        );
2502        assert_eq!(
2503            reader.psc(),
2504            PacketSequenceControl::new(SequenceFlags::Unsegmented, u14::new(0x0))
2505        );
2506        assert_eq!(reader.packet_len(), packet_raw.len());
2507        assert_eq!(reader.packet_type(), packet_type);
2508        assert_eq!(reader.data_len() as usize, packet_raw.len() - 7);
2509    }
2510
2511    #[test]
2512    fn test_ccsds_reader_tc() {
2513        let data = [1, 2, 3, 4];
2514        let packet_type = PacketType::Tc;
2515        let packet_creator = CcsdsPacketCreator::new(
2516            SpacePacketHeader::new_from_apid(u11::new(0x1)),
2517            packet_type,
2518            &data,
2519            Some(ChecksumType::WithCrc16),
2520        )
2521        .unwrap();
2522        let sp_header = packet_creator.sp_header();
2523        generic_ccsds_reader_test(&data, &packet_creator.to_vec(), packet_type, *sp_header);
2524    }
2525
2526    #[test]
2527    fn test_ccsds_reader_tc_owned_creator() {
2528        let data = [1, 2, 3, 4];
2529        let packet_type = PacketType::Tc;
2530        let packet_creator = CcsdsPacketCreatorOwned::new(
2531            SpacePacketHeader::new_from_apid(u11::new(0x1)),
2532            packet_type,
2533            &data,
2534            Some(ChecksumType::WithCrc16),
2535        )
2536        .unwrap();
2537        let sp_header = packet_creator.sp_header();
2538        generic_ccsds_reader_test(&data, &packet_creator.to_vec(), packet_type, *sp_header);
2539    }
2540
2541    #[test]
2542    fn test_ccsds_reader_tm() {
2543        let data = [1, 2, 3, 4];
2544        let packet_type = PacketType::Tm;
2545        let packet_creator = CcsdsPacketCreator::new(
2546            SpacePacketHeader::new_from_apid(u11::new(0x1)),
2547            packet_type,
2548            &data,
2549            Some(ChecksumType::WithCrc16),
2550        )
2551        .unwrap();
2552        let sp_header = packet_creator.sp_header();
2553        generic_ccsds_reader_test(&data, &packet_creator.to_vec(), packet_type, *sp_header);
2554    }
2555
2556    #[test]
2557    fn test_ccsds_reader_tm_owned_creator() {
2558        let data = [1, 2, 3, 4];
2559        let packet_type = PacketType::Tm;
2560        let packet_creator = CcsdsPacketCreatorOwned::new(
2561            SpacePacketHeader::new_from_apid(u11::new(0x1)),
2562            packet_type,
2563            &data,
2564            Some(ChecksumType::WithCrc16),
2565        )
2566        .unwrap();
2567        let sp_header = packet_creator.sp_header();
2568        generic_ccsds_reader_test(&data, &packet_creator.to_vec(), packet_type, *sp_header);
2569    }
2570
2571    fn generic_test_no_checksum(packet_raw: &[u8], packet_data: &[u8], sp_header: SpHeader) {
2572        let reader = CcsdsPacketReader::new(packet_raw, None).unwrap();
2573        assert_eq!(*reader.sp_header(), sp_header);
2574        assert_eq!(reader.packet_data(), packet_data);
2575        assert_eq!(reader.apid(), u11::new(0x1));
2576        assert_eq!(
2577            reader.packet_id(),
2578            PacketId::new(PacketType::Tc, false, u11::new(0x1))
2579        );
2580        assert_eq!(
2581            reader.psc(),
2582            PacketSequenceControl::new(SequenceFlags::Unsegmented, u14::new(0x0))
2583        );
2584        assert_eq!(reader.packet_len(), packet_raw.len());
2585        assert_eq!(reader.packet_type(), PacketType::Tc);
2586        assert_eq!(reader.data_len() as usize, packet_raw.len() - 7);
2587    }
2588
2589    #[test]
2590    fn test_ccsds_reader_no_checksum() {
2591        let data = [1, 2, 3, 4];
2592        let packet_creator = CcsdsPacketCreator::new(
2593            SpacePacketHeader::new_from_apid(u11::new(0x1)),
2594            PacketType::Tc,
2595            &data,
2596            None,
2597        )
2598        .unwrap();
2599        let sp_header = packet_creator.sp_header();
2600        assert_eq!(
2601            packet_creator.ccsds_packet_id_and_psc(),
2602            CcsdsPacketIdAndPsc::from(*sp_header)
2603        );
2604        assert_eq!(
2605            packet_creator.ccsds_packet_id_and_psc(),
2606            CcsdsPacketIdAndPsc::from(sp_header)
2607        );
2608        let packet_raw = packet_creator.to_vec();
2609        generic_test_no_checksum(&packet_raw, &data, *sp_header);
2610    }
2611
2612    #[test]
2613    fn test_ccsds_reader_no_checksum_owned() {
2614        let data = [1, 2, 3, 4];
2615        let packet_creator = CcsdsPacketCreatorOwned::new(
2616            SpacePacketHeader::new_from_apid(u11::new(0x1)),
2617            PacketType::Tc,
2618            &data,
2619            None,
2620        )
2621        .unwrap();
2622        let sp_header = packet_creator.sp_header();
2623        assert_eq!(
2624            packet_creator.ccsds_packet_id_and_psc(),
2625            CcsdsPacketIdAndPsc::from(*sp_header)
2626        );
2627        assert_eq!(
2628            packet_creator.ccsds_packet_id_and_psc(),
2629            CcsdsPacketIdAndPsc::from(sp_header)
2630        );
2631        let packet_raw = packet_creator.to_vec();
2632        generic_test_no_checksum(&packet_raw, &data, *sp_header);
2633    }
2634
2635    #[test]
2636    fn test_ccsds_reader_buf_too_small() {
2637        let data = [1, 2, 3, 4];
2638        let packet_creator = CcsdsPacketCreator::new(
2639            SpacePacketHeader::new_from_apid(u11::new(0x1)),
2640            PacketType::Tc,
2641            &data,
2642            None,
2643        )
2644        .unwrap();
2645        let packet_raw = packet_creator.to_vec();
2646        let reader_error = CcsdsPacketReader::new(&packet_raw[0..8], None);
2647        assert!(reader_error.is_err());
2648        let error = reader_error.unwrap_err();
2649        matches!(
2650            error,
2651            CcsdsPacketReadError::ByteConversion(ByteConversionError::FromSliceTooSmall {
2652                found: 8,
2653                expected: 10
2654            })
2655        );
2656    }
2657
2658    #[test]
2659    fn test_ccsds_reader_buf_too_small_owned() {
2660        let data = [1, 2, 3, 4];
2661        let packet_creator = CcsdsPacketCreatorOwned::new(
2662            SpacePacketHeader::new_from_apid(u11::new(0x1)),
2663            PacketType::Tc,
2664            &data,
2665            None,
2666        )
2667        .unwrap();
2668        let packet_raw = packet_creator.to_vec();
2669        let reader_error = CcsdsPacketReader::new(&packet_raw[0..8], None);
2670        assert!(reader_error.is_err());
2671        let error = reader_error.unwrap_err();
2672        matches!(
2673            error,
2674            CcsdsPacketReadError::ByteConversion(ByteConversionError::FromSliceTooSmall {
2675                found: 8,
2676                expected: 10
2677            })
2678        );
2679    }
2680
2681    #[test]
2682    fn test_ccsds_checksum_error() {
2683        let data = [1, 2, 3, 4];
2684        let packet_creator = CcsdsPacketCreator::new_tc_with_checksum(
2685            SpacePacketHeader::new_from_apid(u11::new(0x1)),
2686            &data,
2687        )
2688        .unwrap();
2689        let mut packet_raw = packet_creator.to_vec();
2690        *packet_raw.last_mut().unwrap() = 0;
2691        let reader_error = CcsdsPacketReader::new_with_checksum(&packet_raw);
2692        assert!(reader_error.is_err());
2693        assert_eq!(reader_error.unwrap_err(), CcsdsPacketReadError::CrcError);
2694    }
2695    #[test]
2696    fn test_ccsds_checksum_ignored() {
2697        let data = [1, 2, 3, 4];
2698        let packet_creator = CcsdsPacketCreator::new_tc_with_checksum(
2699            SpacePacketHeader::new_from_apid(u11::new(0x1)),
2700            &data,
2701        )
2702        .unwrap();
2703        let mut packet_raw = packet_creator.to_vec();
2704        *packet_raw.last_mut().unwrap() = 0;
2705        let reader =
2706            CcsdsPacketReader::new(&packet_raw, Some(ChecksumType::WithCrc16ButIgnored)).unwrap();
2707        assert_eq!(reader.packet_data(), data);
2708    }
2709
2710    #[test]
2711    fn sp_header_to_buf_too_small() {
2712        let sph = SpacePacketHeader::new_from_apid(u11::new(0x01));
2713        let mut buf: [u8; 5] = [0; 5];
2714        assert_eq!(
2715            sph.write_to_be_bytes(&mut buf).unwrap_err(),
2716            ByteConversionError::ToSliceTooSmall {
2717                found: 5,
2718                expected: 6
2719            }
2720        );
2721    }
2722
2723    #[test]
2724    fn sp_header_from_buf_too_small() {
2725        let buf: [u8; 5] = [0; 5];
2726        let sph = SpacePacketHeader::from_be_bytes(&buf);
2727        assert_eq!(
2728            sph.unwrap_err(),
2729            ByteConversionError::FromSliceTooSmall {
2730                found: 5,
2731                expected: 6
2732            }
2733        );
2734    }
2735
2736    #[test]
2737    fn sp_header_default() {
2738        let sph = SpacePacketHeader::default();
2739        assert_eq!(sph.packet_id(), PacketId::default());
2740        assert_eq!(sph.apid().value(), 0);
2741        assert_eq!(
2742            sph.psc(),
2743            PacketSequenceControl::new(SequenceFlags::Unsegmented, u14::new(0))
2744        );
2745        assert_eq!(sph.data_len(), 0);
2746    }
2747
2748    #[test]
2749    fn ccsds_packet_id() {
2750        let packet_id = PacketId::new_for_tc(false, u11::new(0x5));
2751        let psc = PacketSequenceControl::new(SequenceFlags::Unsegmented, u14::new(0));
2752        let sph = SpacePacketHeader::new(packet_id, psc, 0);
2753        let id = CcsdsPacketIdAndPsc::new_from_ccsds_packet(&sph);
2754
2755        assert_eq!(id.packet_id, packet_id);
2756        assert_eq!(id.psc, psc);
2757        assert_eq!(
2758            id.raw(),
2759            ((id.packet_id.raw() as u32) << 16) | id.psc.raw() as u32
2760        );
2761        let id_from = CcsdsPacketIdAndPsc::from(sph);
2762        assert_eq!(id_from, id);
2763
2764        // ID is hashable.
2765        use std::collections::hash_map::DefaultHasher;
2766        let mut hasher = DefaultHasher::new();
2767        id.hash(&mut hasher);
2768    }
2769}