1use bon::bon;
5use core::fmt::Debug;
6use core::fmt::LowerHex;
7use core::mem::size_of;
8use core::ops::Deref;
9use core::ops::DerefMut;
10use zerocopy::ByteEq;
11use zerocopy::FromBytes;
12use zerocopy::Immutable;
13use zerocopy::IntoBytes;
14use zerocopy::KnownLayout;
15use zerocopy::Unaligned;
16use zerocopy::byteorder::network_endian;
17
18pub mod encapsulation;
20pub mod segmentation;
22
23pub use zerocopy;
25
26#[repr(C)]
59#[derive(ByteEq, FromBytes, IntoBytes, KnownLayout, Immutable, Unaligned)]
60pub struct SpacePacket {
61 pub primary_header: PrimaryHeader,
63 pub data_field: [u8],
65}
66
67pub trait SpacePacketData: FromBytes + IntoBytes + KnownLayout + Unaligned + Immutable {}
73impl<T> SpacePacketData for T where T: FromBytes + IntoBytes + KnownLayout + Unaligned + Immutable {}
74
75impl Debug for SpacePacket {
76 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
77 f.debug_struct("SpacePacket")
78 .field("header", &self.primary_header)
79 .field("data_field", &&self.data_field)
80 .finish()
81 }
82}
83
84#[repr(C)]
89#[derive(
90 Copy, Clone, Debug, Hash, ByteEq, FromBytes, IntoBytes, KnownLayout, Immutable, Unaligned,
91)]
92pub struct PrimaryHeader {
93 packet_version_and_id: network_endian::U16,
95 packet_sequence_control: network_endian::U16,
97 packet_data_length: network_endian::U16,
99}
100
101#[rustfmt::skip]
102mod bitmasks {
103 pub const PACKET_VERSION_MASK: u16 = 0b_11100000_00000000;
105 pub const PACKET_TYPE_MASK: u16 = 0b_00010000_00000000;
106 pub const SEC_HDR_MASK: u16 = 0b_00001000_00000000;
107 pub const APID_MASK: u16 = 0b_00000111_11111111;
108
109 pub const SEQ_FLAG_MASK: u16 = 0b_11000000_00000000;
111 pub const SEQ_COUNT_MASK: u16 = 0b_00111111_11111111;
112}
113use bitmasks::*;
114
115use crate::utils::get_bits_u16;
116use crate::utils::set_bits_u16;
117
118#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
122#[repr(transparent)]
123pub struct PacketVersion(u8);
124
125impl PacketVersion {
126 pub const VERSION_1: Self = Self(0);
128 pub fn is_supported(&self) -> bool {
130 *self == Self::VERSION_1
131 }
132}
133
134#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
139#[repr(u8)]
140pub enum PacketType {
141 Telemetry = 0,
143 Telecommand = 1,
145}
146
147#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug, Default)]
152#[repr(u8)]
153pub enum SecondaryHeaderFlag {
154 #[default]
156 Absent = 0,
157 Present = 1,
159}
160
161#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
167#[repr(transparent)]
168pub struct Apid(u16);
169
170impl LowerHex for Apid {
171 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
172 write!(f, "{:#05x}", self.0)
173 }
174}
175
176impl Apid {
177 pub const MAX: u16 = 0b_00000111_11111111;
179 pub const IDLE: Self = Self(Self::MAX);
183
184 pub const fn new(id: u16) -> Result<Self, BuildError> {
186 if id > Self::MAX {
187 Err(BuildError::InvalidApid { value: id })
188 } else {
189 Ok(Self(id))
190 }
191 }
192
193 pub fn is_idle(&self) -> bool {
195 *self == Self::IDLE
196 }
197
198 pub fn value(&self) -> u16 {
200 self.0
201 }
202}
203
204#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug, Default)]
209#[repr(u8)]
210pub enum SequenceFlag {
211 Continuation = 0b00,
213 First = 0b01,
215 Last = 0b10,
217 #[default]
219 Unsegmented = 0b11,
220}
221
222#[derive(Copy, Clone, PartialEq, Eq, Ord, PartialOrd, Hash, Debug, Default)]
227pub struct SequenceCount(u16);
228
229impl SequenceCount {
230 pub const MAX: u16 = 0b_00111111_11111111;
232
233 pub fn new() -> Self {
235 Self(0)
236 }
237
238 pub fn increment(&mut self) {
240 self.0 = (self.0 + 1) & Self::MAX;
241 }
242
243 pub fn value(&self) -> u16 {
245 self.0
246 }
247}
248
249#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug, thiserror::Error)]
251pub enum ParseError {
252 #[error(
254 "slice is too short for a primary header (expected at least {} bytes, got {actual})",
255 size_of::<PrimaryHeader>()
256 )]
257 TooShortForHeader {
258 actual: usize,
260 },
261 #[error(
263 "incomplete packet (header specifies {header_len} bytes, but buffer has only {buffer_len} bytes)"
264 )]
265 IncompletePacket {
266 header_len: usize,
268 buffer_len: usize,
270 },
271 #[error("packet validation failed: {0}")]
273 Invalid(#[from] ValidationError),
274}
275
276#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug, thiserror::Error)]
278pub enum ValidationError {
279 #[error("unsupported packet version: {0:?}")]
281 UnsupportedVersion(PacketVersion),
282 #[error("idle packets (APID 2047) must not have a secondary header")]
284 IdlePacketWithSecondaryHeader,
285}
286
287#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug, thiserror::Error)]
289pub enum BuildError {
290 #[error("buffer is too small to hold the packet")]
292 BufferTooSmall {
293 required: usize,
295 provided: usize,
297 },
298 #[error(
300 "payload too large: maximum allowed is {max} bytes, but {provided} bytes were provided"
301 )]
302 PayloadTooLarge {
303 max: usize,
305 provided: usize,
307 },
308 #[error("a packet data field length of zero is forbidden")]
310 EmptyDataField,
311 #[error("invalid APID value {value}")]
313 InvalidApid {
314 value: u16,
316 },
317}
318
319#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug, thiserror::Error)]
321pub enum DataFieldError {
322 #[error("size of provided data does not match the packet's data field size")]
324 SizeMismatch,
325 #[error("packet data field could not be cast to the target data type")]
328 InvalidLayout,
329 #[error("secondary header is not present in this packet")]
331 SecondaryHeaderAbsent,
332}
333
334impl Deref for SpacePacket {
335 type Target = PrimaryHeader;
337 fn deref(&self) -> &Self::Target {
338 &self.primary_header
339 }
340}
341
342impl DerefMut for SpacePacket {
343 fn deref_mut(&mut self) -> &mut Self::Target {
344 &mut self.primary_header
345 }
346}
347
348#[bon]
349impl SpacePacket {
350 #[builder]
352 pub fn new<'a, 'b>(
353 buffer: &'a mut [u8],
354 apid: Apid,
355 packet_type: PacketType,
356 sequence_count: SequenceCount,
357 secondary_header: SecondaryHeaderFlag,
358 sequence_flag: SequenceFlag,
359 data_len: usize,
360 ) -> Result<&'a mut Self, BuildError> {
361 if data_len > u16::MAX as usize {
362 return Err(BuildError::InvalidApid { value: apid.0 });
363 }
364 if data_len == 0 {
365 return Err(BuildError::EmptyDataField);
366 }
367 let required_len = data_len + size_of::<PrimaryHeader>();
368 let provided_len = buffer.len();
369 let (packet, _) = Self::mut_from_prefix_with_elems(buffer, data_len).map_err(|_| {
370 BuildError::BufferTooSmall {
371 required: required_len,
372 provided: provided_len,
373 }
374 })?;
375
376 packet.set_version(PacketVersion::VERSION_1);
377 packet.set_packet_type(packet_type);
378 packet.set_apid(apid);
379 packet.set_sequence_count(sequence_count);
380 packet.set_data_field_len(data_len as u16);
381 packet.set_secondary_header_flag(secondary_header);
382 packet.set_sequence_flag(sequence_flag);
383
384 Ok(packet)
385 }
386
387 pub fn parse(bytes: &[u8]) -> Result<&Self, ParseError> {
392 if bytes.len() < size_of::<PrimaryHeader>() {
393 return Err(ParseError::TooShortForHeader {
394 actual: bytes.len(),
395 });
396 }
397 let packet = Self::ref_from_bytes(bytes)
398 .expect("Should not fail due to prior length check and Unaligned trait");
399
400 packet.primary_header.validate()?;
401 let specified_len = packet.primary_header.packet_len();
402 if specified_len > bytes.len() {
403 return Err(ParseError::IncompletePacket {
404 header_len: specified_len,
405 buffer_len: bytes.len(),
406 });
407 }
408
409 let packet = Self::ref_from_bytes(&bytes[..specified_len])
410 .expect("Should not fail due to prior length checks");
411 Ok(packet)
412 }
413
414 pub fn set_data_field<T: SpacePacketData>(&mut self, data: &T) -> Result<(), DataFieldError> {
418 if self.data_field.len() != size_of::<T>() {
419 return Err(DataFieldError::SizeMismatch);
420 }
421 self.data_field_mut().copy_from_slice(data.as_bytes());
422 Ok(())
423 }
424
425 pub fn data_as<T: SpacePacketData>(&self) -> Result<&T, DataFieldError> {
431 if self.data_field.len() != size_of::<T>() {
432 return Err(DataFieldError::SizeMismatch);
433 }
434 T::ref_from_bytes(self.data_field()).map_err(|_| DataFieldError::InvalidLayout)
435 }
436
437 pub fn data_field(&self) -> &[u8] {
439 &self.data_field
440 }
441
442 pub fn data_field_mut(&mut self) -> &mut [u8] {
448 &mut self.data_field
449 }
450}
451
452impl PrimaryHeader {
453 fn validate(&self) -> Result<(), ValidationError> {
454 let version = self.version();
455 if !version.is_supported() {
456 return Err(ValidationError::UnsupportedVersion(version));
457 }
458 if self.apid().is_idle() && self.secondary_header_flag() == SecondaryHeaderFlag::Present {
459 return Err(ValidationError::IdlePacketWithSecondaryHeader);
460 }
461 Ok(())
462 }
463
464 pub fn version(&self) -> PacketVersion {
466 PacketVersion(get_bits_u16(self.packet_version_and_id, PACKET_VERSION_MASK) as u8)
467 }
468
469 pub fn set_version(&mut self, version: PacketVersion) {
471 set_bits_u16(
472 &mut self.packet_version_and_id,
473 PACKET_VERSION_MASK,
474 version.0 as u16,
475 );
476 }
477
478 pub fn packet_type(&self) -> PacketType {
480 if get_bits_u16(self.packet_version_and_id, PACKET_TYPE_MASK) == 0 {
481 PacketType::Telemetry
482 } else {
483 PacketType::Telecommand
484 }
485 }
486
487 pub fn set_packet_type(&mut self, packet_type: PacketType) {
489 set_bits_u16(
490 &mut self.packet_version_and_id,
491 PACKET_TYPE_MASK,
492 packet_type as u16,
493 );
494 }
495
496 pub fn secondary_header_flag(&self) -> SecondaryHeaderFlag {
498 if get_bits_u16(self.packet_version_and_id, SEC_HDR_MASK) == 0 {
499 SecondaryHeaderFlag::Absent
500 } else {
501 SecondaryHeaderFlag::Present
502 }
503 }
504
505 pub fn set_secondary_header_flag(&mut self, flag: SecondaryHeaderFlag) {
507 set_bits_u16(&mut self.packet_version_and_id, SEC_HDR_MASK, flag as u16);
508 }
509
510 pub fn apid(&self) -> Apid {
512 Apid(self.packet_version_and_id.get() & APID_MASK)
513 }
514
515 pub fn set_apid(&mut self, apid: Apid) {
517 let ident = self.packet_version_and_id.get();
518 self.packet_version_and_id
519 .set((ident & !APID_MASK) | apid.0);
520 }
521
522 pub fn sequence_flag(&self) -> SequenceFlag {
524 match get_bits_u16(self.packet_sequence_control, SEQ_FLAG_MASK) {
525 0b00 => SequenceFlag::Continuation,
526 0b01 => SequenceFlag::First,
527 0b10 => SequenceFlag::Last,
528 _ => SequenceFlag::Unsegmented,
529 }
530 }
531
532 pub fn set_sequence_flag(&mut self, flag: SequenceFlag) {
534 set_bits_u16(
535 &mut self.packet_sequence_control,
536 SEQ_FLAG_MASK,
537 flag as u16,
538 );
539 }
540
541 pub fn sequence_count(&self) -> SequenceCount {
543 SequenceCount(get_bits_u16(self.packet_sequence_control, SEQ_COUNT_MASK))
544 }
545
546 pub fn set_sequence_count(&mut self, count: SequenceCount) {
548 set_bits_u16(&mut self.packet_sequence_control, SEQ_COUNT_MASK, count.0);
549 }
550
551 pub fn data_field_len(&self) -> usize {
553 self.packet_data_length.get() as usize + 1
554 }
555
556 pub fn set_data_field_len(&mut self, len: u16) {
559 self.packet_data_length.set(len - 1);
560 }
561
562 pub fn packet_len(&self) -> usize {
564 self.data_field_len() + size_of::<PrimaryHeader>()
565 }
566
567 pub fn cfe_msg_id(&self) -> u16 {
586 const CFE_MSG_ID_BASE: u16 = 0b_00001000_00000000;
587 let type_bit = (self.packet_type() as u16) << 12;
588 self.apid().0 | type_bit | CFE_MSG_ID_BASE
589 }
590}
591
592impl From<u16> for SequenceCount {
593 fn from(value: u16) -> Self {
594 Self(value & Self::MAX)
595 }
596}
597
598#[cfg(test)]
599mod tests {
600 use super::*;
601 use zerocopy::byteorder::network_endian::{F32, U64};
602
603 #[repr(C)]
604 #[derive(FromBytes, IntoBytes, KnownLayout, Unaligned, Immutable, Debug, Default)]
605 struct TelemetryData {
606 timestamp: U64,
607 reading: F32,
608 status: u8,
609 }
610
611 #[test]
612 fn build_and_set_data() {
613 let telemetry_payload = TelemetryData {
614 timestamp: U64::new(1234567890),
615 reading: F32::new(3.14159),
616 status: 0xAB,
617 };
618
619 let apid = Apid::new(42).unwrap();
620 let packet_type = PacketType::Telemetry;
621 let mut buffer = [0u8; 100];
622 let data_len = size_of::<TelemetryData>();
623
624 let packet = SpacePacket::builder()
625 .buffer(&mut buffer)
626 .apid(apid)
627 .packet_type(packet_type)
628 .sequence_count(SequenceCount::new())
629 .secondary_header(SecondaryHeaderFlag::Absent)
630 .sequence_flag(SequenceFlag::Unsegmented)
631 .data_len(data_len)
632 .build()
633 .unwrap();
634
635 packet.set_data_field(&telemetry_payload).unwrap();
636
637 let parsed_packet = SpacePacket::parse(packet.as_bytes()).unwrap();
638 let extracted_data = parsed_packet.data_as::<TelemetryData>().unwrap();
639
640 assert_eq!(extracted_data.timestamp.get(), 1234567890);
641 assert!((extracted_data.reading.get() - 3.14159).abs() < f32::EPSILON);
642 assert_eq!(extracted_data.status, 0xAB);
643 }
644
645 #[test]
646 fn deserialize_trivial_packet() {
647 let bytes = &[
648 0b0000_1000u8,
649 0b0000_0000u8, 0b1100_0000u8,
651 0b0000_0000u8, 0b0000_0000u8,
653 0b0000_0000u8, 0xDEu8, ];
656 let packet = SpacePacket::parse(bytes).unwrap();
657
658 assert_eq!(packet.packet_len(), 7);
659 assert_eq!(packet.version(), PacketVersion::VERSION_1);
660 assert_eq!(packet.packet_type(), PacketType::Telemetry);
661 assert_eq!(packet.secondary_header_flag(), SecondaryHeaderFlag::Present);
662 assert_eq!(packet.apid(), Apid::new(0).unwrap());
663 assert_eq!(packet.sequence_flag(), SequenceFlag::Unsegmented);
664 assert_eq!(packet.sequence_count(), SequenceCount::from(0));
665 assert_eq!(packet.data_field_len(), 1);
666 assert_eq!(packet.data_field(), &[0xDE]);
667 }
668
669 #[test]
670 fn roundtrip_header_fields() {
671 use rand::{RngCore, SeedableRng};
672 let mut rng = rand::rngs::SmallRng::seed_from_u64(42);
673 let mut buffer = [0u8; 1024];
674
675 for _ in 0..10_000 {
676 let packet_type = if rng.next_u32() % 2 == 0 {
677 PacketType::Telemetry
678 } else {
679 PacketType::Telecommand
680 };
681 let apid = Apid::new((rng.next_u32() & Apid::MAX as u32) as u16).unwrap();
682 let sequence_count = SequenceCount::from(rng.next_u32() as u16);
683 let data_field_len = 1;
684
685 let packet = SpacePacket::builder()
686 .buffer(&mut buffer)
687 .apid(apid)
688 .packet_type(packet_type)
689 .sequence_count(sequence_count)
690 .secondary_header(SecondaryHeaderFlag::Absent)
691 .sequence_flag(SequenceFlag::Unsegmented)
692 .data_len(data_field_len)
693 .build()
694 .unwrap();
695
696 let parsed = SpacePacket::parse(packet.as_bytes()).unwrap();
697
698 assert_eq!(parsed.packet_type(), packet_type);
699 assert_eq!(parsed.apid(), apid);
700 assert_eq!(parsed.sequence_count(), sequence_count);
701 assert_eq!(parsed.data_field_len(), data_field_len as usize);
702 }
703 }
704
705 #[test]
706 fn error_on_empty_data_field() {
707 let mut buffer = [0u8; 7];
708 let result = SpacePacket::builder()
709 .buffer(&mut buffer)
710 .apid(Apid::new(0).unwrap())
711 .packet_type(PacketType::Telemetry)
712 .sequence_count(SequenceCount::new())
713 .secondary_header(SecondaryHeaderFlag::Absent)
714 .sequence_flag(SequenceFlag::Unsegmented)
715 .data_len(0)
716 .build();
717 assert_eq!(result, Err(BuildError::EmptyDataField));
718 }
719
720 #[test]
721 fn error_on_buffer_too_small() {
722 let mut buffer = [0u8; 128];
723 let data_field_len = 200; let result = SpacePacket::builder()
725 .buffer(&mut buffer)
726 .apid(Apid::new(0).unwrap())
727 .packet_type(PacketType::Telemetry)
728 .sequence_count(SequenceCount::new())
729 .secondary_header(SecondaryHeaderFlag::Absent)
730 .sequence_flag(SequenceFlag::Unsegmented)
731 .data_len(data_field_len)
732 .build();
733 assert_eq!(
734 result,
735 Err(BuildError::BufferTooSmall {
736 required: data_field_len as usize + size_of::<PrimaryHeader>(),
737 provided: 128
738 })
739 );
740 }
741
742 #[test]
743 fn error_on_incomplete_packet_parse() {
744 let mut buffer = [0u8; 256];
745 let data_field_len = 200;
746
747 let packet = SpacePacket::builder()
749 .buffer(&mut buffer)
750 .apid(Apid::new(0).expect("Valid APID"))
751 .packet_type(PacketType::Telemetry)
752 .sequence_count(SequenceCount::new())
753 .secondary_header(SecondaryHeaderFlag::Absent)
754 .sequence_flag(SequenceFlag::Unsegmented)
755 .data_len(data_field_len)
756 .build()
757 .expect("Should build successfully");
758
759 let truncated_bytes = &packet.as_bytes()[..127];
761 let result = SpacePacket::parse(truncated_bytes);
762
763 assert_eq!(
764 result,
765 Err(ParseError::IncompletePacket {
766 header_len: data_field_len as usize + size_of::<PrimaryHeader>(),
767 buffer_len: truncated_bytes.len(),
768 })
769 );
770 }
771
772 #[test]
773 fn error_on_data_field_size_mismatch() {
774 let mut buffer = [0u8; 100];
775 let packet = SpacePacket::builder()
777 .buffer(&mut buffer)
778 .apid(Apid::new(0).expect("Valid APID"))
779 .packet_type(PacketType::Telemetry)
780 .sequence_count(SequenceCount::new())
781 .secondary_header(SecondaryHeaderFlag::Absent)
782 .sequence_flag(SequenceFlag::Unsegmented)
783 .data_len(10)
784 .build()
785 .expect("Should build successfully");
786
787 let wrong_sized_data = TelemetryData::default(); assert_ne!(size_of::<TelemetryData>(), 10);
790
791 let result = packet.set_data_field(&wrong_sized_data);
792 assert_eq!(result, Err(DataFieldError::SizeMismatch));
793 }
794
795 #[test]
796 fn error_on_invalid_apid() {
797 let result = Apid::new(Apid::MAX + 1);
798 assert_eq!(
799 result,
800 Err(BuildError::InvalidApid {
801 value: Apid::MAX + 1,
802 })
803 );
804 }
805}