1use crate::crc::{CRC_CCITT_FALSE, CRC_CCITT_FALSE_NO_TABLE};
54use crate::ecss::{
55 calc_pus_crc16, crc_from_raw_data, sp_header_impls, user_data_from_raw,
56 verify_crc16_ccitt_false_from_raw_to_pus_error, PusError, PusPacket, PusVersion,
57 WritablePusPacket,
58};
59pub use crate::ecss::{CreatorConfig, MessageTypeId};
60use crate::{
61 ByteConversionError, CcsdsPacket, PacketId, PacketSequenceControl, PacketType, SequenceFlags,
62 SpHeader, CCSDS_HEADER_LEN, MAX_APID,
63};
64use arbitrary_int::traits::Integer;
65use arbitrary_int::{u11, u14, u3, u4};
66use core::mem::size_of;
67#[cfg(feature = "serde")]
68use serde::{Deserialize, Serialize};
69use zerocopy::{FromBytes, IntoBytes};
70
71#[cfg(feature = "alloc")]
72use alloc::vec::Vec;
73use delegate::delegate;
74
75use crate::time::{TimeWriter, TimestampError};
76
77use self::zc::PusTmSecHeaderWithoutTimestamp;
78
79use super::verify_crc16_ccitt_false_from_raw_to_pus_error_no_table;
80
81pub trait IsPusTelemetry {}
83
84pub const PUS_TM_MIN_SEC_HEADER_LEN: usize = 7;
86pub const PUS_TM_MIN_LEN_WITHOUT_SOURCE_DATA: usize = CCSDS_HEADER_LEN + PUS_TM_MIN_SEC_HEADER_LEN;
88
89pub trait GenericPusTmSecondaryHeader {
91 fn pus_version(&self) -> Result<PusVersion, u4>;
93 fn sc_time_ref_status(&self) -> u4;
95 fn message_type_id(&self) -> MessageTypeId;
97 fn msg_type_counter(&self) -> u16;
99
100 fn dest_id(&self) -> u16;
102
103 #[inline]
105 fn service_type_id(&self) -> u8 {
106 self.message_type_id().type_id
107 }
108
109 #[inline]
111 fn message_subtype_id(&self) -> u8 {
112 self.message_type_id().subtype_id
113 }
114}
115
116pub mod zc {
118 use super::GenericPusTmSecondaryHeader;
119 use crate::ecss::{MessageTypeId, PusError, PusVersion};
120 use arbitrary_int::{traits::Integer as _, u4};
121 use zerocopy::{FromBytes, Immutable, IntoBytes, NetworkEndian, Unaligned, U16};
122
123 #[derive(FromBytes, IntoBytes, Immutable, Unaligned)]
125 #[repr(C)]
126 pub struct PusTmSecHeaderWithoutTimestamp {
127 pus_version_and_sc_time_ref_status: u8,
128 service_type_id: u8,
129 message_subtype_id: u8,
130 msg_counter: U16<NetworkEndian>,
131 dest_id: U16<NetworkEndian>,
132 }
133
134 pub struct PusTmSecHeader<'time> {
136 pub(crate) zc_header: PusTmSecHeaderWithoutTimestamp,
137 pub(crate) timestamp: &'time [u8],
138 }
139
140 impl TryFrom<crate::ecss::tm::PusTmSecondaryHeader<'_>> for PusTmSecHeaderWithoutTimestamp {
141 type Error = PusError;
142 fn try_from(header: crate::ecss::tm::PusTmSecondaryHeader) -> Result<Self, Self::Error> {
143 if header.pus_version != PusVersion::PusC {
144 return Err(PusError::VersionNotSupported(u4::new(
145 header.pus_version as u8,
146 )));
147 }
148 Ok(PusTmSecHeaderWithoutTimestamp {
149 pus_version_and_sc_time_ref_status: ((header.pus_version as u8) << 4)
150 | header.sc_time_ref_status.as_u8(),
151 service_type_id: header.service_type_id(),
152 message_subtype_id: header.message_subtype_id(),
153 msg_counter: U16::from(header.msg_counter),
154 dest_id: U16::from(header.dest_id),
155 })
156 }
157 }
158
159 impl GenericPusTmSecondaryHeader for PusTmSecHeaderWithoutTimestamp {
160 #[inline]
161 fn pus_version(&self) -> Result<PusVersion, u4> {
162 PusVersion::try_from(u4::new(
163 (self.pus_version_and_sc_time_ref_status >> 4) & 0b1111,
164 ))
165 }
166
167 #[inline]
168 fn sc_time_ref_status(&self) -> u4 {
169 u4::new(self.pus_version_and_sc_time_ref_status & 0b1111)
170 }
171
172 #[inline]
174 fn message_type_id(&self) -> MessageTypeId {
175 MessageTypeId {
176 type_id: self.service_type_id,
177 subtype_id: self.message_subtype_id,
178 }
179 }
180
181 #[inline]
182 fn service_type_id(&self) -> u8 {
183 self.service_type_id
184 }
185
186 #[inline]
187 fn message_subtype_id(&self) -> u8 {
188 self.message_subtype_id
189 }
190
191 #[inline]
192 fn msg_type_counter(&self) -> u16 {
193 self.msg_counter.get()
194 }
195
196 #[inline]
197 fn dest_id(&self) -> u16 {
198 self.dest_id.get()
199 }
200 }
201}
202
203#[derive(PartialEq, Eq, Copy, Clone, Debug)]
205#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
206#[cfg_attr(feature = "defmt", derive(defmt::Format))]
207pub struct PusTmSecondaryHeader<'stamp> {
208 pus_version: PusVersion,
209 pub sc_time_ref_status: u4,
211 pub message_type_id: MessageTypeId,
213 pub msg_counter: u16,
215 pub dest_id: u16,
217 pub timestamp: &'stamp [u8],
219}
220
221impl<'stamp> PusTmSecondaryHeader<'stamp> {
222 #[inline]
225 pub fn new_simple(message_type_id: MessageTypeId, timestamp: &'stamp [u8]) -> Self {
226 Self::new(message_type_id, 0, 0, timestamp)
227 }
228
229 #[inline]
231 pub fn new_simple_no_timestamp(message_type_id: MessageTypeId) -> Self {
232 Self::new(message_type_id, 0, 0, &[])
233 }
234
235 #[inline]
237 pub fn new(
238 message_type_id: MessageTypeId,
239 msg_counter: u16,
240 dest_id: u16,
241 timestamp: &'stamp [u8],
242 ) -> Self {
243 PusTmSecondaryHeader {
244 pus_version: PusVersion::PusC,
245 sc_time_ref_status: u4::new(0),
246 message_type_id,
247 msg_counter,
248 dest_id,
249 timestamp,
250 }
251 }
252}
253
254impl GenericPusTmSecondaryHeader for PusTmSecondaryHeader<'_> {
255 #[inline]
256 fn pus_version(&self) -> Result<PusVersion, u4> {
257 Ok(self.pus_version)
258 }
259
260 #[inline]
261 fn sc_time_ref_status(&self) -> u4 {
262 self.sc_time_ref_status
263 }
264
265 #[inline]
266 fn message_type_id(&self) -> MessageTypeId {
267 self.message_type_id
268 }
269
270 #[inline]
271 fn msg_type_counter(&self) -> u16 {
272 self.msg_counter
273 }
274
275 #[inline]
276 fn dest_id(&self) -> u16 {
277 self.dest_id
278 }
279}
280
281impl<'slice> TryFrom<zc::PusTmSecHeader<'slice>> for PusTmSecondaryHeader<'slice> {
282 type Error = PusError;
283
284 #[inline]
285 fn try_from(sec_header: zc::PusTmSecHeader<'slice>) -> Result<Self, Self::Error> {
286 let version = sec_header.zc_header.pus_version();
287 if let Err(e) = version {
288 return Err(PusError::VersionNotSupported(e));
289 }
290 Ok(PusTmSecondaryHeader {
291 pus_version: version.unwrap(),
292 sc_time_ref_status: sec_header.zc_header.sc_time_ref_status(),
293 message_type_id: sec_header.zc_header.message_type_id(),
294 msg_counter: sec_header.zc_header.msg_type_counter(),
295 dest_id: sec_header.zc_header.dest_id(),
296 timestamp: sec_header.timestamp,
297 })
298 }
299}
300
301#[derive(Eq, Debug, Copy, Clone)]
315#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
316#[cfg_attr(feature = "defmt", derive(defmt::Format))]
317pub struct PusTmCreator<'time, 'src_data> {
318 pub sp_header: SpHeader,
320 #[cfg_attr(feature = "serde", serde(borrow))]
322 pub sec_header: PusTmSecondaryHeader<'time>,
323 source_data: &'src_data [u8],
324 pub calc_crc_on_serialization: bool,
327 has_checksum: bool,
328}
329
330impl<'time, 'src_data> PusTmCreator<'time, 'src_data> {
331 #[inline]
342 pub fn new(
343 mut sp_header: SpHeader,
344 sec_header: PusTmSecondaryHeader<'time>,
345 source_data: &'src_data [u8],
346 packet_config: CreatorConfig,
347 ) -> Self {
348 sp_header.set_packet_type(PacketType::Tm);
349 sp_header.set_sec_header_flag();
350 let mut pus_tm = Self {
351 sp_header,
352 source_data,
353 sec_header,
354 calc_crc_on_serialization: true,
355 has_checksum: packet_config.has_checksum,
356 };
357 if packet_config.set_ccsds_len {
358 pus_tm.update_ccsds_data_len();
359 }
360 pus_tm
361 }
362
363 #[inline]
366 pub fn new_simple(
367 sp_header: SpHeader,
368 message_type_id: MessageTypeId,
369 time_provider: &impl TimeWriter,
370 stamp_buf: &'time mut [u8],
371 source_data: &'src_data [u8],
372 packet_config: CreatorConfig,
373 ) -> Result<Self, TimestampError> {
374 let stamp_size = time_provider.write_to_bytes(stamp_buf)?;
375 let sec_header =
376 PusTmSecondaryHeader::new_simple(message_type_id, &stamp_buf[0..stamp_size]);
377 Ok(Self::new(sp_header, sec_header, source_data, packet_config))
378 }
379
380 #[inline]
382 pub fn new_no_source_data(
383 sp_header: SpHeader,
384 sec_header: PusTmSecondaryHeader<'time>,
385 packet_config: CreatorConfig,
386 ) -> Self {
387 Self::new(sp_header, sec_header, &[], packet_config)
388 }
389
390 pub fn builder() -> PusTmBuilder<'time, 'src_data> {
392 PusTmBuilder::new()
393 }
394
395 #[inline]
397 pub fn has_checksum(&self) -> bool {
398 self.has_checksum
399 }
400
401 #[inline]
403 pub fn timestamp(&self) -> &[u8] {
404 self.sec_header.timestamp
405 }
406
407 #[inline]
409 pub fn source_data(&self) -> &[u8] {
410 self.source_data
411 }
412
413 #[inline]
415 pub fn service_type_id(&self) -> u8 {
416 self.sec_header.service_type_id()
417 }
418
419 #[inline]
421 pub fn message_subtype_id(&self) -> u8 {
422 self.sec_header.message_subtype_id()
423 }
424
425 #[inline]
427 pub fn apid(&self) -> u11 {
428 self.sp_header.packet_id.apid
429 }
430
431 #[inline]
433 pub fn set_dest_id(&mut self, dest_id: u16) {
434 self.sec_header.dest_id = dest_id;
435 }
436
437 #[inline]
439 pub fn set_msg_counter(&mut self, msg_counter: u16) {
440 self.sec_header.msg_counter = msg_counter
441 }
442
443 #[inline]
445 pub fn set_sc_time_ref_status(&mut self, sc_time_ref_status: u4) {
446 self.sec_header.sc_time_ref_status = sc_time_ref_status;
447 }
448
449 sp_header_impls!();
450
451 #[inline]
457 pub fn update_ccsds_data_len(&mut self) {
458 self.sp_header.data_len =
459 self.len_written() as u16 - size_of::<crate::zc::SpHeader>() as u16 - 1;
460 }
461
462 pub fn calc_own_crc16(&self) -> u16 {
465 let mut digest = CRC_CCITT_FALSE.digest();
466 let sph_zc = crate::zc::SpHeader::from(self.sp_header);
467 digest.update(sph_zc.as_bytes());
468 let pus_tc_header = zc::PusTmSecHeaderWithoutTimestamp::try_from(self.sec_header).unwrap();
469 digest.update(pus_tc_header.as_bytes());
470 digest.update(self.sec_header.timestamp);
471 digest.update(self.source_data);
472 digest.finalize()
473 }
474
475 #[inline]
477 pub fn update_packet_fields(&mut self) {
478 self.update_ccsds_data_len();
479 }
480
481 pub fn write_to_bytes(&self, slice: &mut [u8]) -> Result<usize, ByteConversionError> {
483 let writer_unfinalized = self.common_write(slice)?;
484 Ok(writer_unfinalized.finalize())
485 }
486
487 pub fn write_to_bytes_crc_no_table(
489 &self,
490 slice: &mut [u8],
491 ) -> Result<usize, ByteConversionError> {
492 let writer_unfinalized = self.common_write(slice)?;
493 Ok(writer_unfinalized.finalize_checksum_no_table())
494 }
495
496 pub fn write_to_bytes_no_crc(&self, slice: &mut [u8]) -> Result<usize, ByteConversionError> {
498 let writer_unfinalized = self.common_write(slice)?;
499 Ok(writer_unfinalized.finalize_no_checksum())
500 }
501
502 fn common_write<'a>(
503 &self,
504 slice: &'a mut [u8],
505 ) -> Result<PusTmCreatorWithReservedSourceData<'a>, ByteConversionError> {
506 if self.len_written() > slice.len() {
507 return Err(ByteConversionError::ToSliceTooSmall {
508 found: slice.len(),
509 expected: self.len_written(),
510 });
511 }
512 let mut writer_unfinalized = PusTmCreatorWithReservedSourceData::write_to_bytes_partially(
513 slice,
514 self.sp_header,
515 self.sec_header,
516 self.source_data.len(),
517 self.has_checksum,
518 )?;
519 writer_unfinalized
520 .source_data_mut()
521 .copy_from_slice(self.source_data);
522 Ok(writer_unfinalized)
523 }
524
525 #[cfg(feature = "alloc")]
527 pub fn append_to_vec(&self, vec: &mut Vec<u8>) -> Result<usize, PusError> {
528 let sph_zc = crate::zc::SpHeader::from(self.sp_header);
529 let mut appended_len = PUS_TM_MIN_LEN_WITHOUT_SOURCE_DATA + self.sec_header.timestamp.len();
530 if self.has_checksum {
531 appended_len += 2;
532 }
533 appended_len += self.source_data.len();
534 let start_idx = vec.len();
535 vec.extend_from_slice(sph_zc.as_bytes());
536 let sec_header = zc::PusTmSecHeaderWithoutTimestamp::try_from(self.sec_header).unwrap();
538 vec.extend_from_slice(sec_header.as_bytes());
539 vec.extend_from_slice(self.sec_header.timestamp);
540 vec.extend_from_slice(self.source_data);
541 if self.has_checksum {
542 let mut digest = CRC_CCITT_FALSE.digest();
543 digest.update(&vec[start_idx..start_idx + appended_len - 2]);
544 vec.extend_from_slice(&digest.finalize().to_be_bytes());
545 }
546 Ok(appended_len)
547 }
548}
549
550impl WritablePusPacket for PusTmCreator<'_, '_> {
551 #[inline]
552 fn len_written(&self) -> usize {
553 let mut len = PUS_TM_MIN_LEN_WITHOUT_SOURCE_DATA
554 + self.sec_header.timestamp.len()
555 + self.source_data.len();
556 if self.has_checksum {
557 len += 2
558 }
559 len
560 }
561
562 fn has_checksum(&self) -> bool {
564 self.has_checksum
565 }
566
567 fn write_to_bytes_no_checksum(&self, slice: &mut [u8]) -> Result<usize, PusError> {
569 Ok(Self::write_to_bytes_no_crc(self, slice)?)
570 }
571
572 fn write_to_bytes(&self, slice: &mut [u8]) -> Result<usize, PusError> {
573 Ok(Self::write_to_bytes(self, slice)?)
574 }
575
576 fn write_to_bytes_checksum_no_table(&self, slice: &mut [u8]) -> Result<usize, PusError> {
577 Ok(Self::write_to_bytes_crc_no_table(self, slice)?)
578 }
579}
580
581impl PartialEq for PusTmCreator<'_, '_> {
582 #[inline]
583 fn eq(&self, other: &Self) -> bool {
584 self.sp_header == other.sp_header
585 && self.sec_header == other.sec_header
586 && self.source_data == other.source_data
587 }
588}
589
590impl CcsdsPacket for PusTmCreator<'_, '_> {
591 delegate!(to self.sp_header {
592 #[inline]
593 fn ccsds_version(&self) -> u3;
594 #[inline]
595 fn packet_id(&self) -> crate::PacketId;
596 #[inline]
597 fn psc(&self) -> crate::PacketSequenceControl;
598 #[inline]
599 fn data_len(&self) -> u16;
600 });
601}
602
603impl PusPacket for PusTmCreator<'_, '_> {
604 #[inline]
605 fn pus_version(&self) -> Result<PusVersion, u4> {
606 Ok(self.sec_header.pus_version)
607 }
608
609 #[inline]
610 fn has_checksum(&self) -> bool {
611 self.has_checksum()
612 }
613
614 delegate!(to self.sec_header {
615 #[inline]
616 fn message_type_id(&self) -> MessageTypeId;
617 });
618
619 #[inline]
620 fn user_data(&self) -> &[u8] {
621 self.source_data
622 }
623
624 #[inline]
625 fn checksum(&self) -> Option<u16> {
626 if !self.has_checksum {
627 return None;
628 }
629 Some(self.calc_own_crc16())
630 }
631}
632
633impl GenericPusTmSecondaryHeader for PusTmCreator<'_, '_> {
634 delegate!(to self.sec_header {
635 #[inline]
636 fn pus_version(&self) -> Result<PusVersion, u4>;
637 fn message_type_id(&self) -> MessageTypeId;
639
640 #[inline]
642 fn service_type_id(&self) -> u8;
643
644 #[inline]
646 fn message_subtype_id(&self) -> u8;
647
648 #[inline]
649 fn dest_id(&self) -> u16;
650 #[inline]
651 fn msg_type_counter(&self) -> u16;
652 #[inline]
653 fn sc_time_ref_status(&self) -> u4;
654 });
655}
656
657impl IsPusTelemetry for PusTmCreator<'_, '_> {}
658
659#[derive(Debug)]
661pub struct PusTmBuilder<'time, 'src_data> {
662 sp_header: SpHeader,
663 sec_header: PusTmSecondaryHeader<'time>,
664 source_data: &'src_data [u8],
665 has_checksum: bool,
666}
667
668impl Default for PusTmBuilder<'_, '_> {
669 fn default() -> Self {
670 Self::new()
671 }
672}
673
674impl PusTmBuilder<'_, '_> {
675 pub fn new() -> Self {
677 Self {
678 sp_header: SpHeader::new(
679 PacketId::new_for_tm(true, u11::new(0)),
680 PacketSequenceControl::new(SequenceFlags::Unsegmented, u14::new(0)),
681 0,
682 ),
683 sec_header: PusTmSecondaryHeader::new(
684 MessageTypeId {
685 type_id: 0,
686 subtype_id: 0,
687 },
688 0,
689 0,
690 &[],
691 ),
692 source_data: &[],
693 has_checksum: true,
694 }
695 }
696
697 #[inline]
699 pub fn with_apid(mut self, apid: u11) -> Self {
700 self.sp_header.packet_id.set_apid(apid);
701 self
702 }
703
704 #[inline]
706 pub fn with_packet_id(mut self, mut packet_id: PacketId) -> Self {
707 packet_id.packet_type = PacketType::Tc;
708 self.sp_header.packet_id = packet_id;
709 self
710 }
711
712 #[inline]
714 pub fn with_packet_sequence_control(mut self, psc: PacketSequenceControl) -> Self {
715 self.sp_header.psc = psc;
716 self
717 }
718
719 #[inline]
721 pub fn with_sequence_count(mut self, seq_count: u14) -> Self {
722 self.sp_header.psc.seq_count = seq_count;
723 self
724 }
725
726 #[inline]
728 pub fn with_message_type_id(mut self, message_type_id: MessageTypeId) -> Self {
729 self.sec_header.message_type_id = message_type_id;
730 self
731 }
732
733 #[inline]
735 pub fn with_service_type_id(mut self, type_id: u8) -> Self {
736 self.sec_header.message_type_id.type_id = type_id;
737 self
738 }
739
740 #[inline]
742 pub fn with_message_subtype_id(mut self, subtype_id: u8) -> Self {
743 self.sec_header.message_type_id.subtype_id = subtype_id;
744 self
745 }
746
747 #[inline]
749 pub fn with_dest_id(mut self, dest_id: u16) -> Self {
750 self.sec_header.dest_id = dest_id;
751 self
752 }
753
754 #[inline]
756 pub fn with_msg_counter(mut self, msg_counter: u16) -> Self {
757 self.sec_header.msg_counter = msg_counter;
758 self
759 }
760
761 #[inline]
763 pub fn with_sc_time_ref_status(mut self, sc_time_ref_status: u4) -> Self {
764 self.sec_header.sc_time_ref_status = sc_time_ref_status;
765 self
766 }
767
768 #[inline]
770 pub fn with_checksum(mut self, has_checksum: bool) -> Self {
771 self.has_checksum = has_checksum;
772 self
773 }
774}
775
776impl<'src_data> PusTmBuilder<'_, 'src_data> {
777 #[inline]
779 pub fn with_source_data(mut self, source_data: &'src_data [u8]) -> Self {
780 self.source_data = source_data;
781 self
782 }
783}
784
785impl<'time> PusTmBuilder<'time, '_> {
786 #[inline]
788 pub fn with_timestamp(mut self, timestamp: &'time [u8]) -> Self {
789 self.sec_header.timestamp = timestamp;
790 self
791 }
792}
793
794impl<'time, 'src_data> PusTmBuilder<'time, 'src_data> {
795 pub fn build(self) -> PusTmCreator<'time, 'src_data> {
797 PusTmCreator::new(
798 self.sp_header,
799 self.sec_header,
800 self.source_data,
801 CreatorConfig {
802 has_checksum: self.has_checksum,
803 set_ccsds_len: true,
804 },
805 )
806 }
807}
808
809pub struct PusTmCreatorWithReservedSourceData<'buf> {
823 buf: &'buf mut [u8],
824 source_data_offset: usize,
825 full_len: usize,
826 has_checksum: bool,
827}
828
829impl<'buf> PusTmCreatorWithReservedSourceData<'buf> {
830 #[inline]
840 pub fn new(
841 buf: &'buf mut [u8],
842 mut sp_header: SpHeader,
843 sec_header: PusTmSecondaryHeader,
844 src_data_len: usize,
845 has_checksum: bool,
846 ) -> Result<Self, ByteConversionError> {
847 sp_header.set_packet_type(PacketType::Tm);
848 sp_header.set_sec_header_flag();
849 let mut len_written =
850 PUS_TM_MIN_LEN_WITHOUT_SOURCE_DATA + sec_header.timestamp.len() + src_data_len;
851 if has_checksum {
852 len_written += 2;
853 }
854 if len_written > buf.len() {
855 return Err(ByteConversionError::ToSliceTooSmall {
856 found: buf.len(),
857 expected: len_written,
858 });
859 }
860 sp_header.data_len = len_written as u16 - size_of::<crate::zc::SpHeader>() as u16 - 1;
861 Self::write_to_bytes_partially(buf, sp_header, sec_header, src_data_len, has_checksum)
862 }
863
864 fn write_to_bytes_partially(
865 buf: &'buf mut [u8],
866 sp_header: SpHeader,
867 sec_header: PusTmSecondaryHeader,
868 src_data_len: usize,
869 has_checksum: bool,
870 ) -> Result<Self, ByteConversionError> {
871 let mut curr_idx = 0;
872 sp_header.write_to_be_bytes(&mut buf[0..CCSDS_HEADER_LEN])?;
873 curr_idx += CCSDS_HEADER_LEN;
874 let sec_header_len = size_of::<zc::PusTmSecHeaderWithoutTimestamp>();
875 let sec_header_zc = zc::PusTmSecHeaderWithoutTimestamp::try_from(sec_header).unwrap();
876 sec_header_zc
878 .write_to(&mut buf[curr_idx..curr_idx + sec_header_len])
879 .unwrap();
880 curr_idx += sec_header_len;
881 buf[curr_idx..curr_idx + sec_header.timestamp.len()].copy_from_slice(sec_header.timestamp);
882 curr_idx += sec_header.timestamp.len();
883 let source_data_offset = curr_idx;
884 curr_idx += src_data_len;
885 if has_checksum {
886 curr_idx += 2;
887 }
888 Ok(Self {
889 buf,
890 source_data_offset,
891 full_len: curr_idx,
892 has_checksum,
893 })
894 }
895
896 #[inline]
898 pub const fn len_written(&self) -> usize {
899 self.full_len
900 }
901
902 #[inline]
904 pub fn source_data_mut(&mut self) -> &mut [u8] {
905 if self.has_checksum {
906 &mut self.buf[self.source_data_offset..self.full_len - 2]
907 } else {
908 &mut self.buf[self.source_data_offset..self.full_len]
909 }
910 }
911
912 #[inline]
914 pub fn source_data(&self) -> &[u8] {
915 if self.has_checksum {
916 &self.buf[self.source_data_offset..self.full_len - 2]
917 } else {
918 &self.buf[self.source_data_offset..self.full_len]
919 }
920 }
921
922 #[inline]
924 pub fn source_data_len(&self) -> usize {
925 let mut len = self.full_len - self.source_data_offset;
926 if self.has_checksum {
927 len -= 2;
928 }
929 len
930 }
931
932 pub fn finalize(self) -> usize {
936 if self.has_checksum {
937 let mut digest = CRC_CCITT_FALSE.digest();
938 digest.update(&self.buf[0..self.full_len - 2]);
939 self.buf[self.full_len - 2..self.full_len]
940 .copy_from_slice(&digest.finalize().to_be_bytes());
941 }
942 self.full_len
943 }
944
945 pub fn finalize_checksum_no_table(self) -> usize {
950 if self.has_checksum {
951 let mut digest = CRC_CCITT_FALSE_NO_TABLE.digest();
952 digest.update(&self.buf[0..self.full_len - 2]);
953 self.buf[self.full_len - 2..self.full_len]
954 .copy_from_slice(&digest.finalize().to_be_bytes());
955 }
956 self.full_len
957 }
958
959 #[inline]
963 pub fn finalize_no_checksum(self) -> usize {
964 if self.has_checksum {
965 self.full_len - 2
966 } else {
967 self.full_len
968 }
969 }
970}
971
972#[derive(Debug, Clone, Copy, PartialEq, Eq)]
976#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
977#[cfg_attr(feature = "defmt", derive(defmt::Format))]
978pub struct ReaderConfig {
979 pub timestamp_len: usize,
981 pub has_checksum: bool,
983}
984
985#[derive(Eq, Debug, Copy, Clone)]
998#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
999#[cfg_attr(feature = "defmt", derive(defmt::Format))]
1000pub struct PusTmReader<'raw_data> {
1001 pub sp_header: SpHeader,
1003 pub sec_header: PusTmSecondaryHeader<'raw_data>,
1005 #[cfg_attr(feature = "serde", serde(skip))]
1006 raw_data: &'raw_data [u8],
1007 source_data: &'raw_data [u8],
1008 checksum: Option<u16>,
1010}
1011
1012impl<'raw_data> PusTmReader<'raw_data> {
1013 pub fn new(slice: &'raw_data [u8], timestamp_len: usize) -> Result<Self, PusError> {
1019 let tc = Self::new_no_checksum_verification(
1020 slice,
1021 ReaderConfig {
1022 timestamp_len,
1023 has_checksum: true,
1024 },
1025 )?;
1026 verify_crc16_ccitt_false_from_raw_to_pus_error(tc.raw_data(), tc.checksum().unwrap())?;
1027 Ok(tc)
1028 }
1029
1030 pub fn new_checksum_no_table(
1032 slice: &'raw_data [u8],
1033 timestamp_len: usize,
1034 ) -> Result<Self, PusError> {
1035 let tc = Self::new_no_checksum_verification(
1036 slice,
1037 ReaderConfig {
1038 timestamp_len,
1039 has_checksum: true,
1040 },
1041 )?;
1042 verify_crc16_ccitt_false_from_raw_to_pus_error_no_table(
1043 tc.raw_data(),
1044 tc.checksum().unwrap(),
1045 )?;
1046 Ok(tc)
1047 }
1048
1049 pub fn new_no_checksum(slice: &'raw_data [u8], timestamp_len: usize) -> Result<Self, PusError> {
1052 Self::new_no_checksum_verification(
1053 slice,
1054 ReaderConfig {
1055 timestamp_len,
1056 has_checksum: false,
1057 },
1058 )
1059 }
1060
1061 pub fn new_no_checksum_verification(
1063 slice: &'raw_data [u8],
1064 reader_config: ReaderConfig,
1065 ) -> Result<Self, PusError> {
1066 let raw_data_len = slice.len();
1067 if raw_data_len < PUS_TM_MIN_LEN_WITHOUT_SOURCE_DATA {
1068 return Err(ByteConversionError::FromSliceTooSmall {
1069 found: raw_data_len,
1070 expected: PUS_TM_MIN_LEN_WITHOUT_SOURCE_DATA,
1071 }
1072 .into());
1073 }
1074 let mut current_idx = 0;
1075 let (sp_header, _) = SpHeader::from_be_bytes(&slice[0..CCSDS_HEADER_LEN])?;
1076 current_idx += 6;
1077 let total_len = sp_header.packet_len();
1078 if raw_data_len < total_len {
1079 return Err(ByteConversionError::FromSliceTooSmall {
1080 found: raw_data_len,
1081 expected: total_len,
1082 }
1083 .into());
1084 }
1085 if total_len < PUS_TM_MIN_LEN_WITHOUT_SOURCE_DATA {
1086 return Err(ByteConversionError::FromSliceTooSmall {
1087 found: total_len,
1088 expected: PUS_TM_MIN_LEN_WITHOUT_SOURCE_DATA,
1089 }
1090 .into());
1091 }
1092 let sec_header_len = core::mem::size_of::<zc::PusTmSecHeaderWithoutTimestamp>();
1093 let sec_header_zc = zc::PusTmSecHeaderWithoutTimestamp::read_from_bytes(
1095 &slice[current_idx..current_idx + sec_header_len],
1096 )
1097 .unwrap();
1098 current_idx += PUS_TM_MIN_SEC_HEADER_LEN;
1099 let zc_sec_header_wrapper = zc::PusTmSecHeader {
1100 zc_header: sec_header_zc,
1101 timestamp: &slice[current_idx..current_idx + reader_config.timestamp_len],
1102 };
1103 current_idx += reader_config.timestamp_len;
1104 let raw_data = &slice[0..total_len];
1105 let mut crc16 = None;
1106 if reader_config.has_checksum {
1107 crc16 = Some(crc_from_raw_data(raw_data)?);
1108 }
1109 Ok(Self {
1110 sp_header,
1111 sec_header: PusTmSecondaryHeader::try_from(zc_sec_header_wrapper).unwrap(),
1112 raw_data,
1113 source_data: user_data_from_raw(
1114 current_idx,
1115 total_len,
1116 slice,
1117 reader_config.has_checksum,
1118 )?,
1119 checksum: crc16,
1120 })
1121 }
1122
1123 #[inline]
1125 pub fn len_packed(&self) -> usize {
1126 self.sp_header.packet_len()
1127 }
1128
1129 #[inline]
1131 pub fn source_data(&self) -> &[u8] {
1132 self.user_data()
1133 }
1134
1135 #[inline]
1137 pub fn service_type_id(&self) -> u8 {
1138 self.sec_header.service_type_id()
1139 }
1140
1141 #[inline]
1143 pub fn message_subtype_id(&self) -> u8 {
1144 self.sec_header.message_subtype_id()
1145 }
1146
1147 #[inline]
1149 pub fn packet_len(&self) -> usize {
1150 self.sp_header.packet_len()
1151 }
1152
1153 #[inline]
1155 pub fn apid(&self) -> u11 {
1156 self.sp_header.packet_id.apid
1157 }
1158
1159 #[inline]
1161 pub fn timestamp(&self) -> &[u8] {
1162 self.sec_header.timestamp
1163 }
1164
1165 #[inline]
1167 pub fn checksum(&self) -> Option<u16> {
1168 self.checksum
1169 }
1170
1171 #[inline]
1173 pub fn raw_data(&self) -> &[u8] {
1174 self.raw_data
1175 }
1176}
1177
1178impl PartialEq for PusTmReader<'_> {
1179 fn eq(&self, other: &Self) -> bool {
1180 self.sec_header == other.sec_header
1181 && self.source_data == other.source_data
1182 && self.sp_header == other.sp_header
1183 && self.checksum == other.checksum
1184 }
1185}
1186
1187impl CcsdsPacket for PusTmReader<'_> {
1188 delegate!(to self.sp_header {
1189 #[inline]
1190 fn ccsds_version(&self) -> u3;
1191 #[inline]
1192 fn packet_id(&self) -> crate::PacketId;
1193 #[inline]
1194 fn psc(&self) -> crate::PacketSequenceControl;
1195 #[inline]
1196 fn data_len(&self) -> u16;
1197 });
1198}
1199
1200impl PusPacket for PusTmReader<'_> {
1201 delegate!(to self.sec_header {
1202 #[inline]
1203 fn pus_version(&self) -> Result<PusVersion, u4>;
1204
1205 #[inline]
1206 fn message_type_id(&self) -> MessageTypeId;
1207
1208 #[inline]
1209 fn service_type_id(&self) -> u8;
1210
1211 #[inline]
1212 fn message_subtype_id(&self) -> u8;
1213 });
1214
1215 #[inline]
1216 fn has_checksum(&self) -> bool {
1217 self.checksum.is_some()
1218 }
1219
1220 #[inline]
1221 fn user_data(&self) -> &[u8] {
1222 self.source_data
1223 }
1224
1225 #[inline]
1226 fn checksum(&self) -> Option<u16> {
1227 self.checksum()
1228 }
1229}
1230
1231impl GenericPusTmSecondaryHeader for PusTmReader<'_> {
1232 delegate!(to self.sec_header {
1233 #[inline]
1234 fn pus_version(&self) -> Result<PusVersion, u4>;
1235 #[inline]
1236 fn message_type_id(&self) -> MessageTypeId;
1237 #[inline]
1238 fn service_type_id(&self) -> u8;
1239 #[inline]
1240 fn message_subtype_id(&self) -> u8;
1241 #[inline]
1242 fn dest_id(&self) -> u16;
1243 #[inline]
1244 fn msg_type_counter(&self) -> u16;
1245 #[inline]
1246 fn sc_time_ref_status(&self) -> u4;
1247 });
1248}
1249
1250impl IsPusTelemetry for PusTmReader<'_> {}
1251
1252impl PartialEq<PusTmCreator<'_, '_>> for PusTmReader<'_> {
1253 fn eq(&self, other: &PusTmCreator<'_, '_>) -> bool {
1254 self.sp_header == other.sp_header
1255 && self.sec_header == other.sec_header
1256 && self.source_data == other.source_data
1257 }
1258}
1259
1260impl PartialEq<PusTmReader<'_>> for PusTmCreator<'_, '_> {
1261 fn eq(&self, other: &PusTmReader<'_>) -> bool {
1262 self.sp_header == other.sp_header
1263 && self.sec_header == other.sec_header
1264 && self.source_data == other.source_data
1265 }
1266}
1267
1268pub struct PusTmZeroCopyWriter<'raw> {
1279 raw_tm: &'raw mut [u8],
1280 timestamp_len: usize,
1281 has_checksum: bool,
1282}
1283
1284impl<'raw> PusTmZeroCopyWriter<'raw> {
1285 pub fn new(raw_tm: &'raw mut [u8], timestamp_len: usize, has_checksum: bool) -> Option<Self> {
1291 let raw_tm_len = raw_tm.len();
1292 let min_len = CCSDS_HEADER_LEN
1293 + PUS_TM_MIN_SEC_HEADER_LEN
1294 + timestamp_len
1295 + if has_checksum { 2 } else { 0 };
1296 if raw_tm_len < min_len {
1297 return None;
1298 }
1299 let sp_header = crate::zc::SpHeader::read_from_bytes(&raw_tm[0..CCSDS_HEADER_LEN]).unwrap();
1300 if raw_tm_len < sp_header.packet_len() {
1301 return None;
1302 }
1303 let writer = Self {
1304 raw_tm: &mut raw_tm[..sp_header.packet_len()],
1305 timestamp_len,
1306 has_checksum,
1307 };
1308 Some(writer)
1309 }
1310
1311 #[inline]
1313 pub fn set_apid(&mut self, apid: u11) {
1314 let updated_apid = ((((self.raw_tm[0] as u16) << 8) | self.raw_tm[1] as u16)
1316 & !MAX_APID.as_u16())
1317 | apid.as_u16();
1318 self.raw_tm[0..2].copy_from_slice(&updated_apid.to_be_bytes());
1319 }
1320
1321 #[inline]
1323 pub fn set_msg_count(&mut self, msg_count: u16) {
1324 self.raw_tm[9..11].copy_from_slice(&msg_count.to_be_bytes());
1325 }
1326
1327 #[inline]
1329 pub fn set_destination_id(&mut self, dest_id: u16) {
1330 self.raw_tm[11..13].copy_from_slice(&dest_id.to_be_bytes())
1331 }
1332
1333 #[inline]
1335 pub fn sp_header(&self) -> crate::zc::SpHeader {
1336 crate::zc::SpHeader::read_from_bytes(&self.raw_tm[0..CCSDS_HEADER_LEN]).unwrap()
1338 }
1339
1340 #[inline]
1343 pub fn sec_header_without_timestamp(&self) -> PusTmSecHeaderWithoutTimestamp {
1344 PusTmSecHeaderWithoutTimestamp::read_from_bytes(
1346 &self.raw_tm[CCSDS_HEADER_LEN..CCSDS_HEADER_LEN + PUS_TM_MIN_SEC_HEADER_LEN],
1347 )
1348 .unwrap()
1349 }
1350
1351 #[inline]
1353 pub fn set_seq_count(&mut self, seq_count: u14) {
1354 let new_psc = (u16::from_be_bytes(self.raw_tm[2..4].try_into().unwrap()) & 0xC000)
1355 | seq_count.as_u16();
1356 self.raw_tm[2..4].copy_from_slice(&new_psc.to_be_bytes());
1357 }
1358
1359 pub fn finish(self) {
1362 if self.has_checksum {
1363 let slice_len = self.raw_tm.len();
1364 let crc16 = calc_pus_crc16(&self.raw_tm[..slice_len - 2]);
1365 self.raw_tm[slice_len - 2..].copy_from_slice(&crc16.to_be_bytes());
1366 }
1367 }
1368
1369 #[inline]
1370 fn service_type_id(&self) -> u8 {
1371 self.raw_tm[7]
1372 }
1373
1374 #[inline]
1375 fn message_subtype_id(&self) -> u8 {
1376 self.raw_tm[8]
1377 }
1378
1379 #[inline]
1380 fn message_type_id(&self) -> MessageTypeId {
1381 MessageTypeId {
1382 type_id: self.service_type_id(),
1383 subtype_id: self.message_subtype_id(),
1384 }
1385 }
1386}
1387
1388impl CcsdsPacket for PusTmZeroCopyWriter<'_> {
1389 #[inline]
1390 fn ccsds_version(&self) -> u3 {
1391 self.sp_header().ccsds_version()
1392 }
1393
1394 #[inline]
1395 fn packet_id(&self) -> crate::PacketId {
1396 self.sp_header().packet_id()
1397 }
1398
1399 #[inline]
1400 fn psc(&self) -> crate::PacketSequenceControl {
1401 self.sp_header().psc()
1402 }
1403
1404 #[inline]
1405 fn data_len(&self) -> u16 {
1406 self.sp_header().data_len()
1407 }
1408}
1409
1410impl PusPacket for PusTmZeroCopyWriter<'_> {
1411 #[inline]
1412 fn pus_version(&self) -> Result<PusVersion, u4> {
1413 self.sec_header_without_timestamp().pus_version()
1414 }
1415
1416 #[inline]
1417 fn has_checksum(&self) -> bool {
1418 self.has_checksum
1419 }
1420
1421 #[inline]
1422 fn service_type_id(&self) -> u8 {
1423 self.service_type_id()
1424 }
1425
1426 #[inline]
1427 fn message_subtype_id(&self) -> u8 {
1428 self.message_subtype_id()
1429 }
1430
1431 #[inline]
1432 fn message_type_id(&self) -> MessageTypeId {
1433 self.message_type_id()
1434 }
1435
1436 #[inline]
1437 fn user_data(&self) -> &[u8] {
1438 if self.has_checksum {
1439 &self.raw_tm[CCSDS_HEADER_LEN + PUS_TM_MIN_SEC_HEADER_LEN + self.timestamp_len
1440 ..self.sp_header().packet_len() - 2]
1441 } else {
1442 &self.raw_tm[CCSDS_HEADER_LEN + PUS_TM_MIN_SEC_HEADER_LEN + self.timestamp_len
1443 ..self.sp_header().packet_len()]
1444 }
1445 }
1446
1447 #[inline]
1448 fn checksum(&self) -> Option<u16> {
1449 if !self.has_checksum {
1450 return None;
1451 }
1452 Some(u16::from_be_bytes(
1453 self.raw_tm[self.sp_header().packet_len() - 2..self.sp_header().packet_len()]
1454 .try_into()
1455 .unwrap(),
1456 ))
1457 }
1458}
1459
1460impl GenericPusTmSecondaryHeader for PusTmZeroCopyWriter<'_> {
1461 delegate! {
1462 to self.sec_header_without_timestamp() {
1463 #[inline]
1464 fn pus_version(&self) -> Result<PusVersion, u4>;
1465 #[inline]
1466 fn sc_time_ref_status(&self) -> u4;
1467 #[inline]
1468 fn msg_type_counter(&self) -> u16;
1469 #[inline]
1470 fn dest_id(&self) -> u16;
1471 }
1472 }
1473
1474 #[inline]
1475 fn service_type_id(&self) -> u8 {
1476 self.service_type_id()
1477 }
1478
1479 #[inline]
1480 fn message_subtype_id(&self) -> u8 {
1481 self.message_subtype_id()
1482 }
1483
1484 #[inline]
1485 fn message_type_id(&self) -> MessageTypeId {
1486 self.message_type_id()
1487 }
1488}
1489
1490#[cfg(test)]
1491mod tests {
1492 use super::*;
1493 use crate::time::cds::CdsTime;
1494 #[cfg(feature = "serde")]
1495 use crate::time::CcsdsTimeProvider;
1496 use crate::SpHeader;
1497 use crate::{ecss::PusVersion::PusC, MAX_SEQ_COUNT};
1498 use alloc::string::ToString;
1499 #[cfg(feature = "serde")]
1500 use postcard::{from_bytes, to_allocvec};
1501
1502 const DUMMY_DATA: &[u8] = &[0, 1, 2];
1503
1504 fn base_ping_reply_full_ctor<'a, 'b>(timestamp: &'a [u8]) -> PusTmCreator<'a, 'b> {
1505 let sph = SpHeader::new_for_unseg_tm(u11::new(0x123), u14::new(0x234), 0);
1506 let tm_header = PusTmSecondaryHeader::new_simple(MessageTypeId::new(17, 2), timestamp);
1507 PusTmCreator::new_no_source_data(sph, tm_header, CreatorConfig::default())
1508 }
1509
1510 fn base_ping_reply_full_ctor_builder<'a, 'b>(
1511 timestamp: &'a [u8],
1512 alt_api: bool,
1513 ) -> PusTmCreator<'a, 'b> {
1514 if alt_api {
1515 return PusTmCreator::builder()
1516 .with_apid(u11::new(0x123))
1517 .with_sequence_count(u14::new(0x234))
1518 .with_service_type_id(17)
1519 .with_message_subtype_id(2)
1520 .with_timestamp(timestamp)
1521 .build();
1522 }
1523 PusTmBuilder::new()
1524 .with_apid(u11::new(0x123))
1525 .with_sequence_count(u14::new(0x234))
1526 .with_service_type_id(17)
1527 .with_message_subtype_id(2)
1528 .with_timestamp(timestamp)
1529 .build()
1530 }
1531
1532 fn base_ping_reply_full_ctor_no_checksum<'a, 'b>(timestamp: &'a [u8]) -> PusTmCreator<'a, 'b> {
1533 let sph = SpHeader::new_for_unseg_tm(u11::new(0x123), u14::new(0x234), 0);
1534 let tm_header = PusTmSecondaryHeader::new_simple(MessageTypeId::new(17, 2), timestamp);
1535 PusTmCreator::new_no_source_data(
1536 sph,
1537 tm_header,
1538 CreatorConfig {
1539 set_ccsds_len: true,
1540 has_checksum: false,
1541 },
1542 )
1543 }
1544 fn ping_reply_with_data<'a, 'b>(timestamp: &'a [u8]) -> PusTmCreator<'a, 'b> {
1545 let sph = SpHeader::new_for_unseg_tm(u11::new(0x123), u14::new(0x234), 0);
1546 let tm_header = PusTmSecondaryHeader::new_simple(MessageTypeId::new(17, 2), timestamp);
1547 PusTmCreator::new(sph, tm_header, DUMMY_DATA, CreatorConfig::default())
1548 }
1549
1550 fn base_hk_reply<'a, 'b>(timestamp: &'a [u8], src_data: &'b [u8]) -> PusTmCreator<'a, 'b> {
1551 let sph = SpHeader::new_for_unseg_tm(u11::new(0x123), u14::new(0x234), 0);
1552 let tc_header = PusTmSecondaryHeader::new_simple(MessageTypeId::new(3, 5), timestamp);
1553 PusTmCreator::new(sph, tc_header, src_data, CreatorConfig::default())
1554 }
1555
1556 fn base_hk_reply_no_checksum<'a, 'b>(
1557 timestamp: &'a [u8],
1558 src_data: &'b [u8],
1559 ) -> PusTmCreator<'a, 'b> {
1560 let sph = SpHeader::new_for_unseg_tm(u11::new(0x123), u14::new(0x234), 0);
1561 let tc_header = PusTmSecondaryHeader::new_simple(MessageTypeId::new(3, 5), timestamp);
1562 PusTmCreator::new(
1563 sph,
1564 tc_header,
1565 src_data,
1566 CreatorConfig {
1567 set_ccsds_len: true,
1568 has_checksum: false,
1569 },
1570 )
1571 }
1572
1573 fn dummy_timestamp() -> &'static [u8] {
1574 &[0, 1, 2, 3, 4, 5, 6]
1575 }
1576
1577 #[test]
1578 fn test_basic() {
1579 let timestamp = dummy_timestamp();
1580 let pus_tm = base_ping_reply_full_ctor(timestamp);
1581 verify_ping_reply(&pus_tm, false, 22, dummy_timestamp(), true);
1582 }
1583
1584 #[test]
1585 fn test_basic_no_checksum() {
1586 let timestamp = dummy_timestamp();
1587 let pus_tm = base_ping_reply_full_ctor_no_checksum(timestamp);
1588 verify_ping_reply(&pus_tm, false, 20, dummy_timestamp(), false);
1589 }
1590
1591 #[test]
1592 fn test_basic_simple_api() {
1593 let sph = SpHeader::new_for_unseg_tm(u11::new(0x123), u14::new(0x234), 0);
1594 let time_provider = CdsTime::new_with_u16_days(0, 0);
1595 let mut stamp_buf: [u8; 8] = [0; 8];
1596 let pus_tm = PusTmCreator::new_simple(
1597 sph,
1598 MessageTypeId::new(17, 2),
1599 &time_provider,
1600 &mut stamp_buf,
1601 &[],
1602 CreatorConfig::default(),
1603 )
1604 .unwrap();
1605 verify_ping_reply(&pus_tm, false, 22, &[64, 0, 0, 0, 0, 0, 0], true);
1606 }
1607
1608 #[test]
1609 fn test_serialization_no_source_data() {
1610 let timestamp = dummy_timestamp();
1611 let pus_tm = base_ping_reply_full_ctor(timestamp);
1612 let mut buf: [u8; 32] = [0; 32];
1613 let ser_len = pus_tm
1614 .write_to_bytes(&mut buf)
1615 .expect("Serialization failed");
1616 assert_eq!(ser_len, 22);
1617 verify_raw_ping_reply(pus_tm.checksum(), &buf, true);
1618 }
1619
1620 #[test]
1621 fn test_serialization_no_source_data_alt_ctor() {
1622 let timestamp = dummy_timestamp();
1623 let sph = SpHeader::new_for_unseg_tm(u11::new(0x123), u14::new(0x234), 0);
1624 let tm_header = PusTmSecondaryHeader::new_simple(MessageTypeId::new(17, 2), timestamp);
1625 let mut buf: [u8; 32] = [0; 32];
1626 let mut pus_tm =
1627 PusTmCreatorWithReservedSourceData::new(&mut buf, sph, tm_header, 0, true).unwrap();
1628 assert_eq!(pus_tm.source_data_len(), 0);
1629 assert_eq!(pus_tm.source_data(), &[]);
1630 assert_eq!(pus_tm.source_data_mut(), &[]);
1631 let ser_len = pus_tm.finalize();
1632 assert_eq!(ser_len, 22);
1633 verify_raw_ping_reply(None, &buf, true);
1634 }
1635
1636 #[test]
1637 fn test_serialization_no_source_data_alt_ctor_no_checksum_verification() {
1638 let timestamp = dummy_timestamp();
1639 let sph = SpHeader::new_for_unseg_tm(u11::new(0x123), u14::new(0x234), 0);
1640 let tm_header = PusTmSecondaryHeader::new_simple(MessageTypeId::new(17, 2), timestamp);
1641 let mut buf: [u8; 32] = [0; 32];
1642 let mut pus_tm =
1643 PusTmCreatorWithReservedSourceData::new(&mut buf, sph, tm_header, 0, true).unwrap();
1644 assert_eq!(pus_tm.source_data_len(), 0);
1645 assert_eq!(pus_tm.source_data(), &[]);
1646 assert_eq!(pus_tm.source_data_mut(), &[]);
1647 let ser_len = pus_tm.finalize_no_checksum();
1648 assert_eq!(ser_len, 20);
1649 verify_raw_ping_reply_no_checksum(&buf, 22);
1650 assert_eq!(buf[20], 0);
1651 assert_eq!(buf[21], 0);
1652 }
1653
1654 #[test]
1655 fn test_serialization_no_source_data_alt_ctor_no_checksum() {
1656 let timestamp = dummy_timestamp();
1657 let sph = SpHeader::new_for_unseg_tm(u11::new(0x123), u14::new(0x234), 0);
1658 let tm_header = PusTmSecondaryHeader::new_simple(MessageTypeId::new(17, 2), timestamp);
1659 let mut buf: [u8; 32] = [0; 32];
1660 let mut pus_tm =
1661 PusTmCreatorWithReservedSourceData::new(&mut buf, sph, tm_header, 0, false).unwrap();
1662 assert_eq!(pus_tm.source_data_len(), 0);
1663 assert_eq!(pus_tm.source_data(), &[]);
1664 assert_eq!(pus_tm.source_data_mut(), &[]);
1665 let ser_len = pus_tm.finalize_no_checksum();
1666 assert_eq!(ser_len, 20);
1667 verify_raw_ping_reply_no_checksum(&buf, 20);
1668 assert_eq!(buf[20], 0);
1669 assert_eq!(buf[21], 0);
1670 }
1671
1672 #[test]
1673 fn test_serialization_no_source_data_no_table() {
1674 let timestamp = dummy_timestamp();
1675 let pus_tm = base_ping_reply_full_ctor(timestamp);
1676 let mut buf: [u8; 32] = [0; 32];
1677 let ser_len = pus_tm
1678 .write_to_bytes_crc_no_table(&mut buf)
1679 .expect("Serialization failed");
1680 assert_eq!(ser_len, 22);
1681 verify_raw_ping_reply(pus_tm.checksum(), &buf, true);
1682 }
1683
1684 #[test]
1685 fn test_serialization_no_source_data_no_crc() {
1686 let timestamp = dummy_timestamp();
1687 let pus_tm = base_ping_reply_full_ctor(timestamp);
1688 let mut buf: [u8; 32] = [0; 32];
1689 let ser_len = pus_tm
1690 .write_to_bytes_no_crc(&mut buf)
1691 .expect("Serialization failed");
1692 assert_eq!(ser_len, 20);
1693 assert_eq!(buf[20], 0);
1694 assert_eq!(buf[21], 0);
1695 }
1696
1697 #[test]
1698 fn test_serialization_with_source_data() {
1699 let src_data = [1, 2, 3];
1700 let hk_reply = base_hk_reply(dummy_timestamp(), &src_data);
1701 let mut buf: [u8; 32] = [0; 32];
1702 let ser_len = hk_reply
1703 .write_to_bytes(&mut buf)
1704 .expect("Serialization failed");
1705 assert_eq!(ser_len, 25);
1706 assert_eq!(buf[20], 1);
1707 assert_eq!(buf[21], 2);
1708 assert_eq!(buf[22], 3);
1709 let crc16 = u16::from_be_bytes([buf[23], buf[24]]);
1710 assert_eq!(crc16, hk_reply.checksum().unwrap());
1711 }
1712
1713 #[test]
1714 fn test_serialization_with_source_data_no_checksum() {
1715 let src_data = [1, 2, 3];
1716 let hk_reply = base_hk_reply_no_checksum(dummy_timestamp(), &src_data);
1717 let mut buf: [u8; 32] = [0; 32];
1718 let ser_len = hk_reply
1719 .write_to_bytes(&mut buf)
1720 .expect("Serialization failed");
1721 assert_eq!(ser_len, 23);
1722 assert_eq!(buf[20], 1);
1723 assert_eq!(buf[21], 2);
1724 assert_eq!(buf[22], 3);
1725 let crc16 = u16::from_be_bytes([buf[23], buf[24]]);
1726 assert_eq!(crc16, 0);
1727 }
1728
1729 #[test]
1730 fn test_serialization_with_source_data_alt_ctor() {
1731 let src_data = &[1, 2, 3];
1732 let mut buf: [u8; 32] = [0; 32];
1733 let sph = SpHeader::new_for_unseg_tm(u11::new(0x123), u14::new(0x234), 0);
1734 let tc_header =
1735 PusTmSecondaryHeader::new_simple(MessageTypeId::new(3, 5), dummy_timestamp());
1736 let mut hk_reply_unwritten =
1737 PusTmCreatorWithReservedSourceData::new(&mut buf, sph, tc_header, 3, true).unwrap();
1738 assert_eq!(hk_reply_unwritten.source_data_len(), 3);
1739 assert_eq!(hk_reply_unwritten.source_data(), &[0, 0, 0]);
1740 assert_eq!(hk_reply_unwritten.source_data_mut(), &[0, 0, 0]);
1741 let source_data_mut = hk_reply_unwritten.source_data_mut();
1742 source_data_mut.copy_from_slice(src_data);
1743 let ser_len = hk_reply_unwritten.finalize();
1744 assert_eq!(ser_len, 25);
1745 assert_eq!(buf[20], 1);
1746 assert_eq!(buf[21], 2);
1747 assert_eq!(buf[22], 3);
1748 }
1749
1750 #[test]
1751 fn test_serialization_with_source_data_alt_ctor_no_table() {
1752 let src_data = &[1, 2, 3];
1753 let mut buf: [u8; 32] = [0; 32];
1754 let sph = SpHeader::new_for_unseg_tm(u11::new(0x123), u14::new(0x234), 0);
1755 let tc_header =
1756 PusTmSecondaryHeader::new_simple(MessageTypeId::new(3, 5), dummy_timestamp());
1757 let mut hk_reply_unwritten =
1758 PusTmCreatorWithReservedSourceData::new(&mut buf, sph, tc_header, 3, true).unwrap();
1759 assert_eq!(hk_reply_unwritten.source_data_len(), 3);
1760 assert_eq!(hk_reply_unwritten.source_data(), &[0, 0, 0]);
1761 assert_eq!(hk_reply_unwritten.source_data_mut(), &[0, 0, 0]);
1762 let source_data_mut = hk_reply_unwritten.source_data_mut();
1763 source_data_mut.copy_from_slice(src_data);
1764 let ser_len = hk_reply_unwritten.finalize_checksum_no_table();
1765 assert_eq!(ser_len, 25);
1766 assert_eq!(buf[20], 1);
1767 assert_eq!(buf[21], 2);
1768 assert_eq!(buf[22], 3);
1769 }
1770
1771 #[test]
1772 fn test_setters() {
1773 let timestamp = dummy_timestamp();
1774 let mut pus_tm = base_ping_reply_full_ctor(timestamp);
1775 pus_tm.set_sc_time_ref_status(u4::new(0b1010));
1776 pus_tm.set_dest_id(0x7fff);
1777 pus_tm.set_msg_counter(0x1f1f);
1778 assert_eq!(pus_tm.sc_time_ref_status().value(), 0b1010);
1779 assert_eq!(pus_tm.dest_id(), 0x7fff);
1780 assert_eq!(pus_tm.msg_type_counter(), 0x1f1f);
1781 pus_tm.set_apid(u11::new(0x7ff));
1782 assert_eq!(pus_tm.apid().value(), 0x7ff);
1783 }
1784
1785 #[test]
1786 fn test_write_into_vec() {
1787 let timestamp = dummy_timestamp();
1788 let pus_tm = base_ping_reply_full_ctor(timestamp);
1789 let tm_vec = pus_tm.to_vec().expect("Serialization failed");
1790 assert_eq!(tm_vec.len(), 22);
1791 let tm_deserialized =
1792 PusTmReader::new(tm_vec.as_slice(), 7).expect("Deserialization failed");
1793 assert_eq!(tm_vec.len(), tm_deserialized.packet_len());
1794 verify_ping_reply_with_reader(&tm_deserialized, false, 22, dummy_timestamp());
1795 }
1796
1797 #[test]
1798 fn test_deserialization_no_source_data() {
1799 let timestamp = dummy_timestamp();
1800 let pus_tm = base_ping_reply_full_ctor(timestamp);
1801 let mut buf: [u8; 32] = [0; 32];
1802 let ser_len = pus_tm
1803 .write_to_bytes(&mut buf)
1804 .expect("Serialization failed");
1805 assert_eq!(ser_len, 22);
1806 let tm_deserialized = PusTmReader::new(&buf, 7).expect("Deserialization failed");
1807 assert_eq!(ser_len, tm_deserialized.packet_len());
1808 assert_eq!(tm_deserialized.user_data(), tm_deserialized.source_data());
1809 assert_eq!(tm_deserialized.raw_data(), &buf[..ser_len]);
1810 assert_eq!(
1811 tm_deserialized.checksum().unwrap(),
1812 pus_tm.checksum().unwrap()
1813 );
1814 verify_ping_reply_with_reader(&tm_deserialized, false, 22, dummy_timestamp());
1815 }
1816
1817 #[test]
1818 fn test_deserialization_no_source_data_with_trait() {
1819 let timestamp = dummy_timestamp();
1820 let pus_tm = base_ping_reply_full_ctor(timestamp);
1821 let mut buf: [u8; 32] = [0; 32];
1822 let ser_len =
1823 WritablePusPacket::write_to_bytes(&pus_tm, &mut buf).expect("Serialization failed");
1824 assert_eq!(ser_len, 22);
1825 let tm_deserialized = PusTmReader::new(&buf, 7).expect("Deserialization failed");
1826 assert_eq!(ser_len, tm_deserialized.packet_len());
1827 assert_eq!(tm_deserialized.user_data(), tm_deserialized.source_data());
1828 assert_eq!(tm_deserialized.raw_data(), &buf[..ser_len]);
1829 assert_eq!(
1830 tm_deserialized.checksum().unwrap(),
1831 pus_tm.checksum().unwrap()
1832 );
1833 verify_ping_reply_with_reader(&tm_deserialized, false, 22, dummy_timestamp());
1834 }
1835
1836 #[test]
1837 fn test_deserialization_with_source_data() {
1838 let src_data = [4, 3, 2, 1];
1839 let reply = base_hk_reply(dummy_timestamp(), &src_data);
1840 let mut buf: [u8; 32] = [0; 32];
1841 let ser_len =
1842 WritablePusPacket::write_to_bytes(&reply, &mut buf).expect("Serialization failed");
1843 assert_eq!(ser_len, 26);
1844 let tm_deserialized = PusTmReader::new(&buf, 7).expect("Deserialization failed");
1845 assert_eq!(ser_len, tm_deserialized.packet_len());
1846 assert_eq!(tm_deserialized.user_data(), src_data);
1847 assert_eq!(reply.checksum(), tm_deserialized.checksum());
1848 }
1849
1850 #[test]
1851 fn test_deserialization_with_source_data_no_checksum() {
1852 let src_data = [4, 3, 2, 1];
1853 let reply = base_hk_reply_no_checksum(dummy_timestamp(), &src_data);
1854 let mut buf: [u8; 32] = [0; 32];
1855 let ser_len =
1856 WritablePusPacket::write_to_bytes(&reply, &mut buf).expect("Serialization failed");
1857 assert_eq!(ser_len, 24);
1858 let tm_deserialized =
1859 PusTmReader::new_no_checksum(&buf, 7).expect("Deserialization failed");
1860 assert_eq!(ser_len, tm_deserialized.packet_len());
1861 assert_eq!(tm_deserialized.user_data(), src_data);
1862 assert_eq!(reply.checksum(), tm_deserialized.checksum());
1863 }
1864
1865 #[test]
1866 fn test_deserialization_no_table() {
1867 let timestamp = dummy_timestamp();
1868 let pus_tm = base_ping_reply_full_ctor(timestamp);
1869 let mut buf: [u8; 32] = [0; 32];
1870 let ser_len = pus_tm
1871 .write_to_bytes(&mut buf)
1872 .expect("Serialization failed");
1873 assert_eq!(ser_len, 22);
1874 let tm_deserialized =
1875 PusTmReader::new_checksum_no_table(&buf, 7).expect("Deserialization failed");
1876 assert_eq!(ser_len, tm_deserialized.packet_len());
1877 assert_eq!(tm_deserialized.user_data(), tm_deserialized.source_data());
1878 assert_eq!(tm_deserialized.raw_data(), &buf[..ser_len]);
1879 assert_eq!(
1880 tm_deserialized.checksum().unwrap(),
1881 pus_tm.checksum().unwrap()
1882 );
1883 verify_ping_reply_with_reader(&tm_deserialized, false, 22, dummy_timestamp());
1884 }
1885
1886 #[test]
1887 fn test_deserialization_faulty_crc() {
1888 let timestamp = dummy_timestamp();
1889 let pus_tm = base_ping_reply_full_ctor(timestamp);
1890 let mut buf: [u8; 32] = [0; 32];
1891 let ser_len = pus_tm
1892 .write_to_bytes(&mut buf)
1893 .expect("Serialization failed");
1894 assert_eq!(ser_len, 22);
1895 buf[ser_len - 2] = 0;
1896 buf[ser_len - 1] = 0;
1897 let tm_error = PusTmReader::new(&buf, 7);
1898 assert!(tm_error.is_err());
1899 let tm_error = tm_error.unwrap_err();
1900 if let PusError::ChecksumFailure(crc) = tm_error {
1901 assert_eq!(crc, 0);
1902 assert_eq!(
1903 tm_error.to_string(),
1904 "checksum verification for crc16 0x0000 failed"
1905 );
1906 }
1907 }
1908
1909 #[test]
1910 fn test_manual_field_update() {
1911 let sph = SpHeader::new_for_unseg_tm(u11::new(0x123), u14::new(0x234), 0);
1912 let tc_header =
1913 PusTmSecondaryHeader::new_simple(MessageTypeId::new(17, 2), dummy_timestamp());
1914 let mut tm = PusTmCreator::new_no_source_data(
1915 sph,
1916 tc_header,
1917 CreatorConfig {
1918 set_ccsds_len: false,
1919 has_checksum: true,
1920 },
1921 );
1922 tm.calc_crc_on_serialization = false;
1923 assert_eq!(tm.data_len(), 0x00);
1924 let mut buf: [u8; 32] = [0; 32];
1925 tm.update_ccsds_data_len();
1926 assert_eq!(tm.data_len(), 15);
1927 tm.calc_own_crc16();
1928 let res = tm.write_to_bytes(&mut buf);
1929 assert!(res.is_ok());
1930 tm.sp_header.data_len = 0;
1931 tm.update_packet_fields();
1932 assert_eq!(tm.data_len(), 15);
1933 }
1934
1935 #[test]
1936 fn test_target_buf_too_small() {
1937 let timestamp = dummy_timestamp();
1938 let pus_tm = base_ping_reply_full_ctor(timestamp);
1939 let mut buf: [u8; 16] = [0; 16];
1940 let res = pus_tm.write_to_bytes(&mut buf);
1941 assert!(res.is_err());
1942 let error = res.unwrap_err();
1943 if let ByteConversionError::ToSliceTooSmall { found, expected } = error {
1944 assert_eq!(expected, 22);
1945 assert_eq!(found, 16);
1946 } else {
1947 panic!("Invalid error {:?}", error);
1948 }
1949 }
1950
1951 #[test]
1952 #[cfg(feature = "alloc")]
1953 fn test_append_to_vec() {
1954 let timestamp = dummy_timestamp();
1955 let pus_tm = base_ping_reply_full_ctor(timestamp);
1956 let mut vec = Vec::new();
1957 let res = pus_tm.append_to_vec(&mut vec);
1958 assert!(res.is_ok());
1959 assert_eq!(res.unwrap(), 22);
1960 verify_raw_ping_reply(pus_tm.checksum(), vec.as_slice(), true);
1961 }
1962
1963 #[test]
1964 #[cfg(feature = "alloc")]
1965 fn test_append_to_vec_no_checksum() {
1966 let timestamp = dummy_timestamp();
1967 let pus_tm = base_ping_reply_full_ctor_no_checksum(timestamp);
1968 let mut vec = Vec::new();
1969 let res = pus_tm.append_to_vec(&mut vec);
1970 assert!(res.is_ok());
1971 assert_eq!(res.unwrap(), 20);
1972 verify_raw_ping_reply(pus_tm.checksum(), vec.as_slice(), false);
1973 }
1974
1975 #[test]
1976 #[cfg(feature = "alloc")]
1977 fn test_append_to_vec_with_src_data() {
1978 let src_data = [1, 2, 3];
1979 let hk_reply = base_hk_reply(dummy_timestamp(), &src_data);
1980 let mut vec = Vec::new();
1981 vec.push(4);
1982 let res = hk_reply.append_to_vec(&mut vec);
1983 assert!(res.is_ok());
1984 assert_eq!(res.unwrap(), 25);
1985 assert_eq!(vec.len(), 26);
1986 }
1987
1988 fn verify_raw_ping_reply_no_checksum(buf: &[u8], expected_len: usize) {
1989 assert_eq!(buf[0], 0x09);
1991 assert_eq!(buf[1], 0x23);
1993 assert_eq!(buf[2], 0xc2);
1995 assert_eq!(buf[3], 0x34);
1996 assert_eq!(
1997 (((buf[4] as u16) << 8) | buf[5] as u16) as usize,
1998 expected_len - 7
1999 );
2000 assert_eq!(buf[6], (PusC as u8) << 4);
2002 assert_eq!(buf[7], 17);
2003 assert_eq!(buf[8], 2);
2004 assert_eq!(buf[9], 0x00);
2006 assert_eq!(buf[10], 0x00);
2007 assert_eq!(buf[11], 0x00);
2009 assert_eq!(buf[12], 0x00);
2010 assert_eq!(&buf[13..20], dummy_timestamp());
2012 }
2013
2014 fn verify_raw_ping_reply(crc16: Option<u16>, buf: &[u8], has_checksum: bool) {
2015 if !has_checksum {
2016 verify_raw_ping_reply_no_checksum(buf, 20);
2017 if buf.len() > 20 {
2018 let crc16_read = u16::from_be_bytes([buf[20], buf[21]]);
2019 assert_eq!(crc16_read, 0);
2020 }
2021 return;
2022 }
2023 verify_raw_ping_reply_no_checksum(buf, 22);
2024 if let Some(crc16) = crc16 {
2025 let mut digest = CRC_CCITT_FALSE.digest();
2026 digest.update(&buf[0..20]);
2027 let crc16_calced = digest.finalize();
2028 let crc16_read = u16::from_be_bytes([buf[20], buf[21]]);
2029 assert_eq!(crc16_read, crc16_calced);
2030 assert_eq!(((crc16 >> 8) & 0xff) as u8, buf[20]);
2031 assert_eq!((crc16 & 0xff) as u8, buf[21]);
2032 }
2033 }
2034
2035 fn verify_ping_reply(
2036 tm: &PusTmCreator,
2037 has_user_data: bool,
2038 exp_full_len: usize,
2039 exp_timestamp: &[u8],
2040 has_checksum: bool,
2041 ) {
2042 assert_eq!(tm.len_written(), exp_full_len);
2043 assert_eq!(tm.timestamp(), exp_timestamp);
2044 assert_eq!(tm.source_data(), tm.user_data());
2045 verify_ping_reply_generic(tm, has_user_data, exp_full_len);
2046 assert_eq!(tm.has_checksum(), has_checksum);
2047 assert_eq!(tm.checksum().is_some(), has_checksum);
2048 assert_eq!(PusPacket::has_checksum(tm), has_checksum);
2049 assert_eq!(WritablePusPacket::has_checksum(tm), has_checksum);
2050 }
2051
2052 fn verify_ping_reply_with_reader(
2053 tm: &PusTmReader,
2054 has_user_data: bool,
2055 exp_full_len: usize,
2056 exp_timestamp: &[u8],
2057 ) {
2058 assert_eq!(tm.len_packed(), exp_full_len);
2059 assert_eq!(tm.timestamp(), exp_timestamp);
2060 verify_ping_reply_generic(tm, has_user_data, exp_full_len);
2061 }
2062
2063 fn verify_ping_reply_generic(
2064 tm: &(impl GenericPusTmSecondaryHeader + PusPacket),
2065 has_user_data: bool,
2066 exp_full_len: usize,
2067 ) {
2068 assert!(tm.is_tm());
2069 assert_eq!(PusPacket::service_type_id(tm), 17);
2070 assert_eq!(GenericPusTmSecondaryHeader::service_type_id(tm), 17);
2071 assert_eq!(PusPacket::message_subtype_id(tm), 2);
2072 assert_eq!(GenericPusTmSecondaryHeader::message_subtype_id(tm), 2);
2073 assert!(tm.sec_header_flag());
2074 if has_user_data {
2075 assert!(!tm.user_data().is_empty());
2076 }
2077 assert_eq!(PusPacket::pus_version(tm).unwrap(), PusC);
2078 assert_eq!(tm.apid().value(), 0x123);
2079 assert_eq!(tm.seq_count().value(), 0x234);
2080 assert_eq!(PusPacket::pus_version(tm).unwrap(), PusVersion::PusC);
2081 assert_eq!(
2082 GenericPusTmSecondaryHeader::pus_version(tm).unwrap(),
2083 PusVersion::PusC
2084 );
2085 assert_eq!(tm.data_len(), exp_full_len as u16 - 7);
2086 assert_eq!(tm.dest_id(), 0x0000);
2087 assert_eq!(tm.msg_type_counter(), 0x0000);
2088 assert_eq!(tm.sc_time_ref_status().value(), 0b0000);
2089 }
2090
2091 #[test]
2092 fn partial_eq_pus_tm() {
2093 let timestamp = dummy_timestamp();
2094 let pus_tm_1 = base_ping_reply_full_ctor(timestamp);
2095 let pus_tm_2 = base_ping_reply_full_ctor(timestamp);
2096 assert_eq!(pus_tm_1, pus_tm_2);
2097 }
2098
2099 #[test]
2100 fn partial_eq_serialized_vs_derialized() {
2101 let timestamp = dummy_timestamp();
2102 let pus_tm = base_ping_reply_full_ctor(timestamp);
2103 let mut buf = [0; 32];
2104 pus_tm.write_to_bytes(&mut buf).unwrap();
2105 assert_eq!(pus_tm, PusTmReader::new(&buf, timestamp.len()).unwrap());
2106 }
2107
2108 #[test]
2109 fn test_zero_copy_writer() {
2110 let ping_tm = base_ping_reply_full_ctor(dummy_timestamp());
2111 let mut buf: [u8; 64] = [0; 64];
2112 let tm_size = ping_tm
2113 .write_to_bytes(&mut buf)
2114 .expect("writing PUS ping TM failed");
2115 let mut writer = PusTmZeroCopyWriter::new(&mut buf[..tm_size], 7, true)
2116 .expect("Creating zero copy writer failed");
2117 writer.set_destination_id(55);
2118 writer.set_msg_count(100);
2119 writer.set_seq_count(MAX_SEQ_COUNT);
2120 writer.set_apid(MAX_APID);
2121 writer.finish();
2122 let tm_read_back = PusTmReader::new(&buf, 7).expect("Re-creating PUS TM failed");
2124 assert_eq!(tm_read_back.packet_len(), tm_size);
2125 assert_eq!(tm_read_back.msg_type_counter(), 100);
2126 assert_eq!(tm_read_back.dest_id(), 55);
2127 assert_eq!(tm_read_back.seq_count(), MAX_SEQ_COUNT);
2128 assert_eq!(tm_read_back.apid(), MAX_APID);
2129 }
2130
2131 #[test]
2132 fn test_zero_copy_writer_ccsds_api() {
2133 let ping_tm = base_ping_reply_full_ctor(dummy_timestamp());
2134 let mut buf: [u8; 64] = [0; 64];
2135 let tm_size = ping_tm
2136 .write_to_bytes(&mut buf)
2137 .expect("writing PUS ping TM failed");
2138 let mut writer = PusTmZeroCopyWriter::new(&mut buf[..tm_size], 7, true)
2139 .expect("Creating zero copy writer failed");
2140 writer.set_destination_id(55);
2141 writer.set_msg_count(100);
2142 writer.set_seq_count(MAX_SEQ_COUNT);
2143 writer.set_apid(MAX_APID);
2144 assert_eq!(PusPacket::service_type_id(&writer), 17);
2145 assert_eq!(PusPacket::message_subtype_id(&writer), 2);
2146 assert_eq!(writer.apid(), MAX_APID);
2147 assert_eq!(writer.seq_count(), MAX_SEQ_COUNT);
2148 }
2149
2150 #[test]
2151 fn test_zero_copy_pus_api() {
2152 let ping_tm = ping_reply_with_data(dummy_timestamp());
2153 let mut buf: [u8; 64] = [0; 64];
2154 let tm_size = ping_tm
2155 .write_to_bytes(&mut buf)
2156 .expect("writing PUS ping TM failed");
2157 let crc16_raw = u16::from_be_bytes(buf[tm_size - 2..tm_size].try_into().unwrap());
2158 let mut writer = PusTmZeroCopyWriter::new(&mut buf[..tm_size], 7, true)
2159 .expect("Creating zero copy writer failed");
2160 writer.set_destination_id(55);
2161 writer.set_msg_count(100);
2162 writer.set_seq_count(MAX_SEQ_COUNT);
2163 writer.set_apid(MAX_APID);
2164 assert_eq!(PusPacket::service_type_id(&writer), 17);
2165 assert_eq!(PusPacket::message_subtype_id(&writer), 2);
2166 assert_eq!(writer.dest_id(), 55);
2167 assert_eq!(writer.msg_type_counter(), 100);
2168 assert_eq!(writer.sec_header_without_timestamp().dest_id(), 55);
2169 assert_eq!(
2170 writer.sec_header_without_timestamp().msg_type_counter(),
2171 100
2172 );
2173 assert_eq!(writer.user_data(), DUMMY_DATA);
2174 let crc16 = writer.checksum();
2176 assert!(crc16.is_some());
2177 assert_eq!(crc16.unwrap(), crc16_raw);
2178 writer.finish();
2179 }
2180
2181 #[test]
2182 fn test_sec_header_without_stamp() {
2183 let sec_header = PusTmSecondaryHeader::new_simple_no_timestamp(MessageTypeId::new(17, 1));
2184 assert_eq!(sec_header.timestamp, &[]);
2185 }
2186
2187 #[test]
2188 fn test_reader_partial_eq() {
2189 let timestamp = dummy_timestamp();
2190 let pus_tm = base_ping_reply_full_ctor(timestamp);
2191 let mut buf = [0; 32];
2192 pus_tm.write_to_bytes(&mut buf).unwrap();
2193 let tm_0 = PusTmReader::new(&buf, timestamp.len()).unwrap();
2194 let tm_1 = PusTmReader::new(&buf, timestamp.len()).unwrap();
2195 assert_eq!(tm_0, tm_1);
2196 }
2197 #[test]
2198 fn test_reader_buf_too_small_2() {
2199 let timestamp = dummy_timestamp();
2200 let pus_tm = base_ping_reply_full_ctor(timestamp);
2201 let mut buf = [0; 32];
2202 let written = pus_tm.write_to_bytes(&mut buf).unwrap();
2203 let tm_error = PusTmReader::new(
2204 &buf[0..PUS_TM_MIN_LEN_WITHOUT_SOURCE_DATA + 1],
2205 timestamp.len(),
2206 );
2207 assert!(tm_error.is_err());
2208 let tm_error = tm_error.unwrap_err();
2209 if let PusError::ByteConversion(ByteConversionError::FromSliceTooSmall {
2210 found,
2211 expected,
2212 }) = tm_error
2213 {
2214 assert_eq!(found, PUS_TM_MIN_LEN_WITHOUT_SOURCE_DATA + 1);
2215 assert_eq!(expected, written);
2216 } else {
2217 panic!("unexpected error {tm_error}")
2218 }
2219 }
2220 #[test]
2221 fn test_reader_buf_too_small() {
2222 let timestamp = dummy_timestamp();
2223 let pus_tm = base_ping_reply_full_ctor(timestamp);
2224 let mut buf = [0; 32];
2225 pus_tm.write_to_bytes(&mut buf).unwrap();
2226 let tm_error = PusTmReader::new(&buf[0..5], timestamp.len());
2227 assert!(tm_error.is_err());
2228 let tm_error = tm_error.unwrap_err();
2229 if let PusError::ByteConversion(ByteConversionError::FromSliceTooSmall {
2230 found,
2231 expected,
2232 }) = tm_error
2233 {
2234 assert_eq!(found, 5);
2235 assert_eq!(expected, PUS_TM_MIN_LEN_WITHOUT_SOURCE_DATA);
2236 } else {
2237 panic!("unexpected error {tm_error}")
2238 }
2239 }
2240
2241 #[test]
2242 #[cfg(feature = "serde")]
2243 fn test_serialization_creator_serde() {
2244 let sph = SpHeader::new_for_unseg_tm(u11::new(0x123), u14::new(0x234), 0);
2245 let time_provider = CdsTime::new_with_u16_days(0, 0);
2246 let mut stamp_buf: [u8; 8] = [0; 8];
2247 let pus_tm = PusTmCreator::new_simple(
2248 sph,
2249 MessageTypeId::new(17, 2),
2250 &time_provider,
2251 &mut stamp_buf,
2252 &[],
2253 CreatorConfig::default(),
2254 )
2255 .unwrap();
2256
2257 let output = to_allocvec(&pus_tm).unwrap();
2258 let output_converted_back: PusTmCreator = from_bytes(&output).unwrap();
2259 assert_eq!(output_converted_back, pus_tm);
2260 }
2261
2262 #[test]
2263 #[cfg(feature = "serde")]
2264 fn test_serialization_reader_serde() {
2265 let sph = SpHeader::new_for_unseg_tm(u11::new(0x123), u14::new(0x234), 0);
2266 let time_provider = CdsTime::new_with_u16_days(0, 0);
2267 let mut stamp_buf: [u8; 8] = [0; 8];
2268 let pus_tm = PusTmCreator::new_simple(
2269 sph,
2270 MessageTypeId::new(17, 2),
2271 &time_provider,
2272 &mut stamp_buf,
2273 &[],
2274 CreatorConfig::default(),
2275 )
2276 .unwrap();
2277 let pus_tm_vec = pus_tm.to_vec().unwrap();
2278 let tm_reader = PusTmReader::new(&pus_tm_vec, time_provider.len_as_bytes()).unwrap();
2279 let output = to_allocvec(&tm_reader).unwrap();
2280 let output_converted_back: PusTmReader = from_bytes(&output).unwrap();
2281 assert_eq!(output_converted_back, tm_reader);
2282 }
2283
2284 #[test]
2285 fn test_builder() {
2286 assert_eq!(
2287 base_ping_reply_full_ctor_builder(dummy_timestamp(), false),
2288 base_ping_reply_full_ctor(dummy_timestamp())
2289 );
2290 }
2291
2292 #[test]
2293 fn test_builder_2() {
2294 assert_eq!(
2295 base_ping_reply_full_ctor_builder(dummy_timestamp(), true),
2296 base_ping_reply_full_ctor(dummy_timestamp())
2297 );
2298 }
2299
2300 #[test]
2301 fn test_builder_3() {
2302 let tm = PusTmBuilder::new()
2303 .with_packet_id(PacketId::new_for_tc(true, u11::new(0x02)))
2304 .with_packet_sequence_control(PacketSequenceControl::new(
2305 SequenceFlags::Unsegmented,
2306 u14::new(0x34),
2307 ))
2308 .with_service_type_id(17)
2309 .with_message_subtype_id(2)
2310 .with_dest_id(0x2f2f)
2311 .with_checksum(false)
2312 .build();
2313 assert_eq!(tm.seq_count().value(), 0x34);
2314 assert_eq!(tm.sequence_flags(), SequenceFlags::Unsegmented);
2315 assert_eq!(tm.apid().value(), 0x02);
2316 assert_eq!(tm.packet_type(), PacketType::Tm);
2317 assert_eq!(tm.service_type_id(), 17);
2318 assert_eq!(tm.message_subtype_id(), 2);
2319 }
2320}