1use crate::crc::{CRC_CCITT_FALSE, CRC_CCITT_FALSE_NO_TABLE};
51use crate::ecss::tm::IsPusTelemetry;
52use crate::ecss::{
53 calc_pus_crc16, crc_from_raw_data, sp_header_impls, user_data_from_raw,
54 verify_crc16_ccitt_false_from_raw_to_pus_error, CrcType, MessageTypeId, PusError, PusPacket,
55 PusVersion, WritablePusPacket,
56};
57use crate::util::{UnsignedByteField, UnsignedEnum};
58use crate::{
59 ByteConversionError, CcsdsPacket, PacketType, SequenceFlags, SpHeader, CCSDS_HEADER_LEN,
60 MAX_APID,
61};
62use arbitrary_int::traits::Integer;
63use arbitrary_int::{u11, u14, u3, u4};
64use core::mem::size_of;
65#[cfg(feature = "serde")]
66use serde::{Deserialize, Serialize};
67use zerocopy::{FromBytes, IntoBytes};
68
69#[cfg(feature = "alloc")]
70use alloc::vec::Vec;
71use delegate::delegate;
72
73use crate::time::{TimeWriter, TimestampError};
74
75use super::verify_crc16_ccitt_false_from_raw_to_pus_error_no_table;
76
77pub const PUS_TM_MIN_SEC_HEADER_LEN: usize = 3;
79pub const PUS_TM_MIN_LEN_WITHOUT_SOURCE_DATA: usize =
81 CCSDS_HEADER_LEN + PUS_TM_MIN_SEC_HEADER_LEN + size_of::<CrcType>();
82
83pub trait GenericPusTmSecondaryHeader {
85 fn pus_version(&self) -> PusVersion;
87 fn service(&self) -> u8;
89 fn subservice(&self) -> u8;
91 fn msg_counter(&self) -> Option<u8>;
93 fn dest_id(&self) -> Option<UnsignedByteField>;
95 fn spare_bytes(&self) -> usize;
97}
98
99#[derive(Debug, Copy, Clone, Eq, PartialEq)]
101pub struct SecondaryHeaderParameters {
102 pub timestamp_len: usize,
104 pub has_msg_counter: bool,
106 pub opt_dest_id_len: Option<usize>,
108 pub spare_bytes: usize,
110}
111
112impl SecondaryHeaderParameters {
113 pub const fn new_minimal(timestamp_len: usize) -> Self {
115 Self {
116 timestamp_len,
117 has_msg_counter: false,
118 opt_dest_id_len: None,
119 spare_bytes: 0,
120 }
121 }
122}
123
124#[derive(PartialEq, Eq, Copy, Clone, Debug)]
126#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
127#[cfg_attr(feature = "defmt", derive(defmt::Format))]
128pub struct PusTmSecondaryHeader<'stamp> {
129 pus_version: PusVersion,
130 pub service: u8,
132 pub subservice: u8,
134 pub msg_counter: Option<u8>,
136 pub dest_id: Option<UnsignedByteField>,
138 pub timestamp: &'stamp [u8],
140 pub spare_bytes: usize,
142}
143
144impl<'stamp> PusTmSecondaryHeader<'stamp> {
145 #[inline]
150 pub fn new_simple(service: u8, subservice: u8, timestamp: &'stamp [u8]) -> Self {
151 Self::new(service, subservice, None, None, timestamp, 0)
152 }
153
154 #[inline]
156 pub fn new_simple_no_timestamp(service: u8, subservice: u8) -> Self {
157 Self::new(service, subservice, None, None, &[], 0)
158 }
159
160 #[inline]
162 pub fn new(
163 service: u8,
164 subservice: u8,
165 msg_counter: Option<u8>,
166 dest_id: Option<UnsignedByteField>,
167 timestamp: &'stamp [u8],
168 spare_bytes: usize,
169 ) -> Self {
170 PusTmSecondaryHeader {
171 pus_version: PusVersion::PusA,
172 service,
173 subservice,
174 msg_counter,
175 dest_id,
176 timestamp,
177 spare_bytes,
178 }
179 }
180
181 pub fn from_bytes(
183 buf: &'stamp [u8],
184 params: &SecondaryHeaderParameters,
185 ) -> Result<PusTmSecondaryHeader<'stamp>, PusError> {
186 let sec_header_len = Self::len_for_params(params);
187 if buf.len() < sec_header_len {
188 return Err(ByteConversionError::FromSliceTooSmall {
189 found: buf.len(),
190 expected: sec_header_len,
191 }
192 .into());
193 }
194 let pus_version = PusVersion::try_from(u4::new((buf[0] >> 4) & 0x0F));
195 if let Err(version_raw) = pus_version {
196 return Err(PusError::VersionNotSupported(version_raw));
197 }
198 let pus_version = pus_version.unwrap();
199 if pus_version != PusVersion::PusA {
200 return Err(PusError::VersionNotSupported(pus_version.raw_value()));
201 }
202 let mut msg_counter = None;
203 let mut current_idx = 3;
204 if params.has_msg_counter {
205 msg_counter = Some(buf[current_idx]);
206 current_idx += 1;
207 }
208 let mut dest_id = None;
209 if let Some(dest_id_len) = params.opt_dest_id_len {
210 dest_id = Some(
211 UnsignedByteField::new_from_be_bytes(
212 dest_id_len,
213 &buf[current_idx..current_idx + dest_id_len],
214 )
215 .unwrap(),
216 );
217 current_idx += dest_id_len;
218 }
219 Ok(Self {
220 pus_version,
221 service: buf[1],
222 subservice: buf[2],
223 msg_counter,
224 dest_id,
225 timestamp: &buf[current_idx..current_idx + params.timestamp_len],
226 spare_bytes: params.spare_bytes,
227 })
228 }
229
230 pub fn write_to_be_bytes(&self, buf: &mut [u8]) -> Result<usize, ByteConversionError> {
232 let written_len = self.written_len();
233 if buf.len() < written_len {
234 return Err(ByteConversionError::ToSliceTooSmall {
235 found: buf.len(),
236 expected: PUS_TM_MIN_SEC_HEADER_LEN,
237 });
238 }
239 buf[0] = (self.pus_version as u8) << 4;
240 buf[1] = self.service;
241 buf[2] = self.subservice;
242 let mut current_idx = 3;
243 if let Some(msg_counter) = self.msg_counter {
244 buf[current_idx] = msg_counter;
245 current_idx += 1;
246 }
247 if let Some(dest_id) = self.dest_id {
248 dest_id.write_to_be_bytes(&mut buf[current_idx..current_idx + dest_id.size()])?;
249 current_idx += dest_id.size();
250 }
251 buf[current_idx..current_idx + self.timestamp.len()].copy_from_slice(self.timestamp);
252 current_idx += self.timestamp.len();
253 if self.spare_bytes > 0 {
254 buf[current_idx..current_idx + self.spare_bytes].fill(0);
255 }
256 Ok(written_len)
257 }
258
259 #[cfg(feature = "alloc")]
261 pub fn to_vec(&self) -> Vec<u8> {
262 let mut vec = alloc::vec![0; self.written_len()];
263 self.write_to_be_bytes(&mut vec).unwrap();
264 vec
265 }
266
267 pub fn written_len(&self) -> usize {
269 let mut len = PUS_TM_MIN_SEC_HEADER_LEN + self.timestamp.len() + self.spare_bytes;
270 if let Some(dest_id) = self.dest_id {
271 len += dest_id.size();
272 }
273 if self.msg_counter.is_some() {
274 len += 1;
275 }
276 len
277 }
278
279 pub fn len_for_params(params: &SecondaryHeaderParameters) -> usize {
281 let mut len = PUS_TM_MIN_SEC_HEADER_LEN + params.timestamp_len + params.spare_bytes;
282 if let Some(dest_id) = params.opt_dest_id_len {
283 len += dest_id;
284 }
285 if params.has_msg_counter {
286 len += 1;
287 }
288 len
289 }
290}
291
292impl GenericPusTmSecondaryHeader for PusTmSecondaryHeader<'_> {
293 #[inline]
294 fn pus_version(&self) -> PusVersion {
295 self.pus_version
296 }
297
298 #[inline]
299 fn service(&self) -> u8 {
300 self.service
301 }
302
303 #[inline]
304 fn subservice(&self) -> u8 {
305 self.subservice
306 }
307
308 #[inline]
309 fn msg_counter(&self) -> Option<u8> {
310 self.msg_counter
311 }
312
313 #[inline]
314 fn dest_id(&self) -> Option<UnsignedByteField> {
315 self.dest_id
316 }
317
318 #[inline]
319 fn spare_bytes(&self) -> usize {
320 self.spare_bytes
321 }
322}
323
324#[derive(Eq, Debug, Copy, Clone)]
338#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
339#[cfg_attr(feature = "defmt", derive(defmt::Format))]
340pub struct PusTmCreator<'time, 'src_data> {
341 pub sp_header: SpHeader,
343 #[cfg_attr(feature = "serde", serde(borrow))]
345 pub sec_header: PusTmSecondaryHeader<'time>,
346 source_data: &'src_data [u8],
347 pub calc_crc_on_serialization: bool,
350}
351
352impl<'time, 'src_data> PusTmCreator<'time, 'src_data> {
353 #[inline]
366 pub fn new(
367 mut sp_header: SpHeader,
368 sec_header: PusTmSecondaryHeader<'time>,
369 source_data: &'src_data [u8],
370 set_ccsds_len: bool,
371 ) -> Self {
372 sp_header.set_packet_type(PacketType::Tm);
373 sp_header.set_sec_header_flag();
374 let mut pus_tm = Self {
375 sp_header,
376 source_data,
377 sec_header,
378 calc_crc_on_serialization: true,
379 };
380 if set_ccsds_len {
381 pus_tm.update_ccsds_data_len();
382 }
383 pus_tm
384 }
385
386 #[inline]
389 pub fn new_simple(
390 sp_header: SpHeader,
391 service: u8,
392 subservice: u8,
393 time_provider: &impl TimeWriter,
394 stamp_buf: &'time mut [u8],
395 source_data: &'src_data [u8],
396 set_ccsds_len: bool,
397 ) -> Result<Self, TimestampError> {
398 let stamp_size = time_provider.write_to_bytes(stamp_buf)?;
399 let sec_header =
400 PusTmSecondaryHeader::new_simple(service, subservice, &stamp_buf[0..stamp_size]);
401 Ok(Self::new(sp_header, sec_header, source_data, set_ccsds_len))
402 }
403
404 #[inline]
406 pub fn new_no_source_data(
407 sp_header: SpHeader,
408 sec_header: PusTmSecondaryHeader<'time>,
409 set_ccsds_len: bool,
410 ) -> Self {
411 Self::new(sp_header, sec_header, &[], set_ccsds_len)
412 }
413
414 #[inline]
416 pub fn timestamp(&self) -> &[u8] {
417 self.sec_header.timestamp
418 }
419
420 #[inline]
422 pub fn source_data(&self) -> &[u8] {
423 self.source_data
424 }
425
426 #[inline]
428 pub fn set_dest_id(&mut self, dest_id: Option<UnsignedByteField>) {
429 self.sec_header.dest_id = dest_id;
430 }
431
432 #[inline]
434 pub fn set_msg_counter(&mut self, msg_counter: Option<u8>) {
435 self.sec_header.msg_counter = msg_counter
436 }
437
438 sp_header_impls!();
439
440 #[inline]
446 pub fn update_ccsds_data_len(&mut self) {
447 self.sp_header.data_len =
448 self.len_written() as u16 - size_of::<crate::zc::SpHeader>() as u16 - 1;
449 }
450
451 pub fn calc_own_crc16(&self) -> u16 {
454 let mut digest = CRC_CCITT_FALSE.digest();
455 let sph_zc = crate::zc::SpHeader::from(self.sp_header);
456 digest.update(sph_zc.as_bytes());
457 let mut fixed_header_part: [u8; PUS_TM_MIN_SEC_HEADER_LEN] = [0; PUS_TM_MIN_SEC_HEADER_LEN];
458 fixed_header_part[0] = (self.sec_header.pus_version() as u8) << 4;
459 fixed_header_part[1] = self.sec_header.service;
460 fixed_header_part[2] = self.sec_header.subservice;
461
462 digest.update(fixed_header_part.as_slice());
463 if let Some(msg_counter) = self.sec_header.msg_counter {
464 digest.update(&[msg_counter]);
465 }
466 if let Some(dest_id) = self.sec_header.dest_id {
467 let mut dest_id_buf: [u8; core::mem::size_of::<u64>()] =
468 [0; core::mem::size_of::<u64>()];
469 let len = dest_id.write_to_be_bytes(&mut dest_id_buf).unwrap();
472 digest.update(&dest_id_buf[0..len]);
473 }
474 digest.update(self.sec_header.timestamp);
475 for _ in 0..self.sec_header.spare_bytes {
476 digest.update(&[0]);
477 }
478 digest.update(self.source_data);
479 digest.finalize()
480 }
481
482 #[inline]
484 pub fn update_packet_fields(&mut self) {
485 self.update_ccsds_data_len();
486 }
487
488 pub fn write_to_bytes(&self, slice: &mut [u8]) -> Result<usize, ByteConversionError> {
490 let writer_unfinalized = self.common_write(slice)?;
491 Ok(writer_unfinalized.finalize())
492 }
493
494 pub fn write_to_bytes_crc_no_table(
496 &self,
497 slice: &mut [u8],
498 ) -> Result<usize, ByteConversionError> {
499 let writer_unfinalized = self.common_write(slice)?;
500 Ok(writer_unfinalized.finalize_crc_no_table())
501 }
502
503 pub fn write_to_bytes_no_crc(&self, slice: &mut [u8]) -> Result<usize, ByteConversionError> {
505 let writer_unfinalized = self.common_write(slice)?;
506 Ok(writer_unfinalized.finalize_no_crc())
507 }
508
509 fn common_write<'a>(
510 &self,
511 slice: &'a mut [u8],
512 ) -> Result<PusTmCreatorWithReservedSourceData<'a>, ByteConversionError> {
513 if self.len_written() > slice.len() {
514 return Err(ByteConversionError::ToSliceTooSmall {
515 found: slice.len(),
516 expected: self.len_written(),
517 });
518 }
519 let mut writer_unfinalized = PusTmCreatorWithReservedSourceData::write_to_bytes_partially(
520 slice,
521 self.sp_header,
522 self.sec_header,
523 self.source_data.len(),
524 )?;
525 writer_unfinalized
526 .source_data_mut()
527 .copy_from_slice(self.source_data);
528 Ok(writer_unfinalized)
529 }
530
531 #[cfg(feature = "alloc")]
533 pub fn append_to_vec(&self, vec: &mut Vec<u8>) -> Result<usize, PusError> {
534 let sph_zc = crate::zc::SpHeader::from(self.sp_header);
535 let mut appended_len = PUS_TM_MIN_LEN_WITHOUT_SOURCE_DATA + self.sec_header.timestamp.len();
536 appended_len += self.source_data.len();
537 let start_idx = vec.len();
538 vec.extend_from_slice(sph_zc.as_bytes());
539 vec.extend_from_slice(&self.sec_header.to_vec());
540 vec.extend_from_slice(self.source_data);
541 let mut digest = CRC_CCITT_FALSE.digest();
542 digest.update(&vec[start_idx..start_idx + appended_len - 2]);
543 vec.extend_from_slice(&digest.finalize().to_be_bytes());
544 Ok(appended_len)
545 }
546}
547
548impl WritablePusPacket for PusTmCreator<'_, '_> {
549 #[inline]
550 fn len_written(&self) -> usize {
551 CCSDS_HEADER_LEN + self.sec_header.written_len() + self.source_data.len() + 2
552 }
553
554 fn has_checksum(&self) -> bool {
556 true
557 }
558
559 fn write_to_bytes_no_checksum(&self, slice: &mut [u8]) -> Result<usize, PusError> {
561 Ok(Self::write_to_bytes_no_crc(self, slice)?)
562 }
563
564 fn write_to_bytes(&self, slice: &mut [u8]) -> Result<usize, PusError> {
565 Ok(Self::write_to_bytes(self, slice)?)
566 }
567
568 fn write_to_bytes_checksum_no_table(&self, slice: &mut [u8]) -> Result<usize, PusError> {
569 Ok(Self::write_to_bytes_crc_no_table(self, slice)?)
570 }
571}
572
573impl PartialEq for PusTmCreator<'_, '_> {
574 #[inline]
575 fn eq(&self, other: &Self) -> bool {
576 self.sp_header == other.sp_header
577 && self.sec_header == other.sec_header
578 && self.source_data == other.source_data
579 }
580}
581
582impl CcsdsPacket for PusTmCreator<'_, '_> {
583 delegate!(to self.sp_header {
584 #[inline]
585 fn ccsds_version(&self) -> u3;
586 #[inline]
587 fn packet_id(&self) -> crate::PacketId;
588 #[inline]
589 fn psc(&self) -> crate::PacketSequenceControl;
590 #[inline]
591 fn data_len(&self) -> u16;
592 });
593}
594
595impl PusPacket for PusTmCreator<'_, '_> {
596 #[inline]
597 fn pus_version(&self) -> Result<PusVersion, u4> {
598 Ok(self.sec_header.pus_version)
599 }
600
601 #[inline]
602 fn message_type_id(&self) -> super::MessageTypeId {
603 super::MessageTypeId {
604 type_id: self.sec_header.service,
605 subtype_id: self.sec_header.subservice,
606 }
607 }
608
609 #[inline]
610 fn service_type_id(&self) -> u8 {
611 self.sec_header.service
612 }
613 #[inline]
614 fn message_subtype_id(&self) -> u8 {
615 self.sec_header.subservice
616 }
617
618 #[inline]
619 fn user_data(&self) -> &[u8] {
620 self.source_data
621 }
622
623 #[inline]
624 fn checksum(&self) -> Option<u16> {
625 Some(self.calc_own_crc16())
626 }
627}
628
629impl GenericPusTmSecondaryHeader for PusTmCreator<'_, '_> {
630 delegate!(to self.sec_header {
631 #[inline]
632 fn pus_version(&self) -> PusVersion;
633 #[inline]
634 fn service(&self) -> u8;
635 #[inline]
636 fn subservice(&self) -> u8;
637 #[inline]
638 fn dest_id(&self) -> Option<UnsignedByteField>;
639 #[inline]
640 fn msg_counter(&self) -> Option<u8>;
641 #[inline]
642 fn spare_bytes(&self) -> usize;
643 });
644}
645
646impl IsPusTelemetry for PusTmCreator<'_, '_> {}
647
648pub struct PusTmCreatorWithReservedSourceData<'buf> {
662 buf: &'buf mut [u8],
663 source_data_offset: usize,
664 full_len: usize,
665}
666
667impl<'buf> PusTmCreatorWithReservedSourceData<'buf> {
668 #[inline]
678 pub fn new(
679 buf: &'buf mut [u8],
680 mut sp_header: SpHeader,
681 sec_header: PusTmSecondaryHeader,
682 src_data_len: usize,
683 ) -> Result<Self, ByteConversionError> {
684 sp_header.set_packet_type(PacketType::Tm);
685 sp_header.set_sec_header_flag();
686 let len_written =
687 PUS_TM_MIN_LEN_WITHOUT_SOURCE_DATA + sec_header.timestamp.len() + src_data_len;
688 if len_written > buf.len() {
689 return Err(ByteConversionError::ToSliceTooSmall {
690 found: buf.len(),
691 expected: len_written,
692 });
693 }
694 sp_header.data_len = len_written as u16 - size_of::<crate::zc::SpHeader>() as u16 - 1;
695 Self::write_to_bytes_partially(buf, sp_header, sec_header, src_data_len)
696 }
697
698 fn write_to_bytes_partially(
699 buf: &'buf mut [u8],
700 sp_header: SpHeader,
701 sec_header: PusTmSecondaryHeader,
702 src_data_len: usize,
703 ) -> Result<Self, ByteConversionError> {
704 let mut curr_idx = 0;
705 sp_header.write_to_be_bytes(&mut buf[0..CCSDS_HEADER_LEN])?;
706 curr_idx += CCSDS_HEADER_LEN;
707 curr_idx += sec_header.write_to_be_bytes(&mut buf[CCSDS_HEADER_LEN..])?;
708 let source_data_offset = curr_idx;
709 curr_idx += src_data_len;
710 Ok(Self {
711 buf,
712 source_data_offset,
713 full_len: curr_idx + 2,
714 })
715 }
716
717 #[inline]
719 pub const fn len_written(&self) -> usize {
720 self.full_len
721 }
722
723 #[inline]
725 pub fn source_data_mut(&mut self) -> &mut [u8] {
726 &mut self.buf[self.source_data_offset..self.full_len - 2]
727 }
728
729 #[inline]
731 pub fn source_data(&self) -> &[u8] {
732 &self.buf[self.source_data_offset..self.full_len - 2]
733 }
734
735 #[inline]
737 pub fn source_data_len(&self) -> usize {
738 self.full_len - 2 - self.source_data_offset
739 }
740
741 pub fn finalize(self) -> usize {
745 let mut digest = CRC_CCITT_FALSE.digest();
746 digest.update(&self.buf[0..self.full_len - 2]);
747 self.buf[self.full_len - 2..self.full_len]
748 .copy_from_slice(&digest.finalize().to_be_bytes());
749 self.full_len
750 }
751
752 pub fn finalize_crc_no_table(self) -> usize {
757 let mut digest = CRC_CCITT_FALSE_NO_TABLE.digest();
758 digest.update(&self.buf[0..self.full_len - 2]);
759 self.buf[self.full_len - 2..self.full_len]
760 .copy_from_slice(&digest.finalize().to_be_bytes());
761 self.full_len
762 }
763
764 #[inline]
768 pub fn finalize_no_crc(self) -> usize {
769 self.full_len - 2
770 }
771}
772
773#[derive(Eq, Debug, Copy, Clone)]
786#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
787#[cfg_attr(feature = "defmt", derive(defmt::Format))]
788pub struct PusTmReader<'raw_data> {
789 pub sp_header: SpHeader,
791 pub sec_header: PusTmSecondaryHeader<'raw_data>,
793 #[cfg_attr(feature = "serde", serde(skip))]
794 raw_data: &'raw_data [u8],
795 source_data: &'raw_data [u8],
796 crc16: u16,
797}
798
799impl<'raw_data> PusTmReader<'raw_data> {
800 pub fn new(
807 slice: &'raw_data [u8],
808 sec_header_params: &SecondaryHeaderParameters,
809 ) -> Result<Self, PusError> {
810 let tc = Self::new_no_crc_check(slice, sec_header_params)?;
811 verify_crc16_ccitt_false_from_raw_to_pus_error(tc.raw_data(), tc.crc16)?;
812 Ok(tc)
813 }
814
815 pub fn new_crc_no_table(
817 slice: &'raw_data [u8],
818 sec_header_params: &SecondaryHeaderParameters,
819 ) -> Result<Self, PusError> {
820 let tc = Self::new_no_crc_check(slice, sec_header_params)?;
821 verify_crc16_ccitt_false_from_raw_to_pus_error_no_table(tc.raw_data(), tc.crc16)?;
822 Ok(tc)
823 }
824
825 pub fn new_no_crc_check(
827 slice: &'raw_data [u8],
828 sec_header_params: &SecondaryHeaderParameters,
829 ) -> Result<Self, PusError> {
830 let raw_data_len = slice.len();
831 if raw_data_len < PUS_TM_MIN_LEN_WITHOUT_SOURCE_DATA {
832 return Err(ByteConversionError::FromSliceTooSmall {
833 found: raw_data_len,
834 expected: PUS_TM_MIN_LEN_WITHOUT_SOURCE_DATA,
835 }
836 .into());
837 }
838 let mut current_idx = 0;
839 let (sp_header, _) = SpHeader::from_be_bytes(&slice[0..CCSDS_HEADER_LEN])?;
840 current_idx += CCSDS_HEADER_LEN;
841 let total_len = sp_header.packet_len();
842 if raw_data_len < total_len {
843 return Err(ByteConversionError::FromSliceTooSmall {
844 found: raw_data_len,
845 expected: total_len,
846 }
847 .into());
848 }
849 if total_len < PUS_TM_MIN_LEN_WITHOUT_SOURCE_DATA {
850 return Err(ByteConversionError::FromSliceTooSmall {
851 found: total_len,
852 expected: PUS_TM_MIN_LEN_WITHOUT_SOURCE_DATA,
853 }
854 .into());
855 }
856 let sec_header =
857 PusTmSecondaryHeader::from_bytes(&slice[current_idx..], sec_header_params)?;
858 current_idx += sec_header.written_len();
859 let raw_data = &slice[0..total_len];
860 Ok(Self {
861 sp_header,
862 sec_header,
863 raw_data: &slice[0..total_len],
864 source_data: user_data_from_raw(current_idx, total_len, slice, true)?,
865 crc16: crc_from_raw_data(raw_data)?,
866 })
867 }
868
869 #[inline]
871 pub fn len_packed(&self) -> usize {
872 self.sp_header.packet_len()
873 }
874
875 #[inline]
877 pub fn source_data(&self) -> &[u8] {
878 self.user_data()
879 }
880
881 #[inline]
883 pub fn timestamp(&self) -> &[u8] {
884 self.sec_header.timestamp
885 }
886
887 #[inline]
889 pub fn crc16(&self) -> u16 {
890 self.crc16
891 }
892
893 #[inline]
895 pub fn raw_data(&self) -> &[u8] {
896 self.raw_data
897 }
898}
899
900impl PartialEq for PusTmReader<'_> {
901 fn eq(&self, other: &Self) -> bool {
902 self.sec_header == other.sec_header
903 && self.source_data == other.source_data
904 && self.sp_header == other.sp_header
905 && self.crc16 == other.crc16
906 }
907}
908
909impl CcsdsPacket for PusTmReader<'_> {
910 delegate!(to self.sp_header {
911 #[inline]
912 fn ccsds_version(&self) -> u3;
913 #[inline]
914 fn packet_id(&self) -> crate::PacketId;
915 #[inline]
916 fn psc(&self) -> crate::PacketSequenceControl;
917 #[inline]
918 fn data_len(&self) -> u16;
919 });
920}
921
922impl PusPacket for PusTmReader<'_> {
923 #[inline]
924 fn pus_version(&self) -> Result<PusVersion, u4> {
925 Ok(self.sec_header.pus_version)
926 }
927
928 #[inline]
929 fn message_type_id(&self) -> super::MessageTypeId {
930 MessageTypeId {
931 type_id: self.sec_header.service,
932 subtype_id: self.sec_header.subservice,
933 }
934 }
935
936 #[inline]
937 fn service_type_id(&self) -> u8 {
938 self.sec_header.service
939 }
940
941 #[inline]
942 fn message_subtype_id(&self) -> u8 {
943 self.sec_header.subservice
944 }
945
946 #[inline]
947 fn user_data(&self) -> &[u8] {
948 self.source_data
949 }
950
951 #[inline]
952 fn checksum(&self) -> Option<u16> {
953 Some(self.crc16())
954 }
955}
956
957impl GenericPusTmSecondaryHeader for PusTmReader<'_> {
958 delegate!(to self.sec_header {
959 #[inline]
960 fn pus_version(&self) -> PusVersion;
961 #[inline]
962 fn service(&self) -> u8;
963 #[inline]
964 fn subservice(&self) -> u8;
965 #[inline]
966 fn dest_id(&self) -> Option<UnsignedByteField>;
967 #[inline]
968 fn msg_counter(&self) -> Option<u8>;
969 #[inline]
970 fn spare_bytes(&self) -> usize;
971 });
972}
973
974impl IsPusTelemetry for PusTmReader<'_> {}
975
976impl PartialEq<PusTmCreator<'_, '_>> for PusTmReader<'_> {
977 fn eq(&self, other: &PusTmCreator<'_, '_>) -> bool {
978 self.sp_header == other.sp_header
979 && self.sec_header == other.sec_header
980 && self.source_data == other.source_data
981 }
982}
983
984impl PartialEq<PusTmReader<'_>> for PusTmCreator<'_, '_> {
985 fn eq(&self, other: &PusTmReader<'_>) -> bool {
986 self.sp_header == other.sp_header
987 && self.sec_header == other.sec_header
988 && self.source_data == other.source_data
989 }
990}
991
992#[derive(Debug, thiserror::Error)]
994#[error("this field is not present in the secondary header")]
995pub struct SecondaryHeaderFieldNotPresentError;
996
997#[derive(Debug, thiserror::Error)]
999pub enum DestIdOperationError {
1000 #[error("this field is not present in the secondary header")]
1002 FieldNotPresent(#[from] SecondaryHeaderFieldNotPresentError),
1003 #[error("invalid byte field length")]
1005 InvalidFieldLen,
1006 #[error("byte conversion error")]
1008 ByteConversionError(#[from] ByteConversionError),
1009}
1010
1011pub struct PusTmZeroCopyWriter<'raw> {
1022 raw_tm: &'raw mut [u8],
1023 sec_header_params: SecondaryHeaderParameters,
1024}
1025
1026impl<'raw> PusTmZeroCopyWriter<'raw> {
1027 pub fn new(
1033 raw_tm: &'raw mut [u8],
1034 sec_header_params: &SecondaryHeaderParameters,
1035 ) -> Option<Self> {
1036 let raw_tm_len = raw_tm.len();
1037 if raw_tm_len
1038 < CCSDS_HEADER_LEN + PUS_TM_MIN_SEC_HEADER_LEN + sec_header_params.timestamp_len
1039 {
1040 return None;
1041 }
1042 let sp_header = crate::zc::SpHeader::read_from_bytes(&raw_tm[0..CCSDS_HEADER_LEN]).unwrap();
1043 if raw_tm_len < sp_header.packet_len() {
1044 return None;
1045 }
1046 let writer = Self {
1047 raw_tm: &mut raw_tm[..sp_header.packet_len()],
1048 sec_header_params: *sec_header_params,
1049 };
1050 Some(writer)
1051 }
1052
1053 #[inline]
1056 pub fn set_apid(&mut self, apid: u11) {
1057 let updated_apid = ((((self.raw_tm[0] as u16) << 8) | self.raw_tm[1] as u16)
1059 & !MAX_APID.as_u16())
1060 | apid.as_u16();
1061 self.raw_tm[0..2].copy_from_slice(&updated_apid.to_be_bytes());
1062 }
1063
1064 pub fn dest_id(&self) -> Result<Option<UnsignedByteField>, ByteConversionError> {
1066 if self.sec_header_params.opt_dest_id_len.is_none() {
1067 return Ok(None);
1068 }
1069 let mut base_idx = 10;
1070 if self.sec_header_params.has_msg_counter {
1071 base_idx += 1;
1072 }
1073 let dest_id_len = self.sec_header_params.opt_dest_id_len.unwrap();
1074 if self.raw_tm.len() < base_idx + dest_id_len {
1075 return Err(ByteConversionError::FromSliceTooSmall {
1076 found: self.raw_tm.len(),
1077 expected: base_idx + dest_id_len,
1078 });
1079 }
1080 Ok(Some(
1081 UnsignedByteField::new_from_be_bytes(
1082 dest_id_len,
1083 &self.raw_tm[base_idx..base_idx + dest_id_len],
1084 )
1085 .unwrap(),
1086 ))
1087 }
1088
1089 pub fn msg_counter(&self) -> Option<u8> {
1091 if !self.sec_header_params.has_msg_counter {
1092 return None;
1093 }
1094 Some(self.raw_tm[9])
1095 }
1096
1097 #[inline]
1102 pub fn set_msg_count(
1103 &mut self,
1104 msg_count: u8,
1105 ) -> Result<(), SecondaryHeaderFieldNotPresentError> {
1106 if !self.sec_header_params.has_msg_counter {
1107 return Err(SecondaryHeaderFieldNotPresentError);
1108 }
1109 self.raw_tm[9] = msg_count;
1110 Ok(())
1111 }
1112
1113 #[inline]
1115 pub fn set_destination_id(
1116 &mut self,
1117 dest_id: UnsignedByteField,
1118 ) -> Result<(), DestIdOperationError> {
1119 if self.sec_header_params.opt_dest_id_len.is_none() {
1120 return Err(SecondaryHeaderFieldNotPresentError.into());
1121 }
1122 let dest_id_len = self.sec_header_params.opt_dest_id_len.unwrap();
1123 if dest_id.size() != dest_id_len {
1124 return Err(DestIdOperationError::InvalidFieldLen);
1125 }
1126 let mut base_idx = 10;
1127 if self.sec_header_params.has_msg_counter {
1128 base_idx += 1;
1129 }
1130 if self.raw_tm.len() < base_idx + dest_id_len {
1131 return Err(DestIdOperationError::ByteConversionError(
1132 ByteConversionError::ToSliceTooSmall {
1133 found: self.raw_tm.len(),
1134 expected: base_idx + dest_id_len,
1135 },
1136 ));
1137 }
1138 dest_id
1139 .write_to_be_bytes(&mut self.raw_tm[base_idx..base_idx + dest_id_len])
1140 .unwrap();
1141 Ok(())
1142 }
1143
1144 #[inline]
1146 pub fn sp_header(&self) -> crate::zc::SpHeader {
1147 crate::zc::SpHeader::read_from_bytes(&self.raw_tm[0..CCSDS_HEADER_LEN]).unwrap()
1149 }
1150
1151 #[inline]
1153 pub fn set_seq_count(&mut self, seq_count: u14) {
1154 let new_psc = (u16::from_be_bytes(self.raw_tm[2..4].try_into().unwrap()) & 0xC000)
1155 | seq_count.as_u16();
1156 self.raw_tm[2..4].copy_from_slice(&new_psc.to_be_bytes());
1157 }
1158
1159 pub fn finish(self) {
1162 let slice_len = self.raw_tm.len();
1163 let crc16 = calc_pus_crc16(&self.raw_tm[..slice_len - 2]);
1164 self.raw_tm[slice_len - 2..].copy_from_slice(&crc16.to_be_bytes());
1165 }
1166}
1167
1168impl CcsdsPacket for PusTmZeroCopyWriter<'_> {
1169 #[inline]
1170 fn ccsds_version(&self) -> u3 {
1171 self.sp_header().ccsds_version()
1172 }
1173
1174 #[inline]
1175 fn packet_id(&self) -> crate::PacketId {
1176 self.sp_header().packet_id()
1177 }
1178
1179 #[inline]
1180 fn psc(&self) -> crate::PacketSequenceControl {
1181 self.sp_header().psc()
1182 }
1183
1184 #[inline]
1185 fn data_len(&self) -> u16 {
1186 self.sp_header().data_len()
1187 }
1188}
1189
1190impl PusPacket for PusTmZeroCopyWriter<'_> {
1191 #[inline]
1192 fn pus_version(&self) -> Result<PusVersion, u4> {
1193 PusVersion::try_from(u4::new((self.raw_tm[6] >> 4) & 0b1111))
1194 }
1195
1196 #[inline]
1197 fn message_type_id(&self) -> super::MessageTypeId {
1198 MessageTypeId {
1199 type_id: self.service_type_id(),
1200 subtype_id: self.message_subtype_id(),
1201 }
1202 }
1203
1204 #[inline]
1205 fn service_type_id(&self) -> u8 {
1206 self.raw_tm[7]
1207 }
1208
1209 #[inline]
1210 fn message_subtype_id(&self) -> u8 {
1211 self.raw_tm[8]
1212 }
1213
1214 #[inline]
1215 fn user_data(&self) -> &[u8] {
1216 &self.raw_tm[CCSDS_HEADER_LEN
1217 + PUS_TM_MIN_SEC_HEADER_LEN
1218 + self.sec_header_params.timestamp_len
1219 ..self.sp_header().packet_len() - 2]
1220 }
1221
1222 #[inline]
1223 fn checksum(&self) -> Option<u16> {
1224 Some(u16::from_be_bytes(
1225 self.raw_tm[self.sp_header().packet_len() - 2..self.sp_header().packet_len()]
1226 .try_into()
1227 .unwrap(),
1228 ))
1229 }
1230}
1231
1232#[cfg(test)]
1233mod tests {
1234 use alloc::string::ToString;
1235
1236 use super::*;
1237 use crate::time::cds::CdsTime;
1238 use crate::{ecss::PusVersion::PusA, util::UnsignedByteFieldU16};
1239 use crate::{SpHeader, MAX_SEQ_COUNT};
1240 #[cfg(feature = "serde")]
1241 use postcard::{from_bytes, to_allocvec};
1242
1243 const DUMMY_DATA: &[u8] = &[0, 1, 2];
1244 const MIN_SEC_HEADER_PARAMS: SecondaryHeaderParameters =
1245 SecondaryHeaderParameters::new_minimal(7);
1246
1247 fn ping_reply_no_data<'a, 'b>(
1248 timestamp: &'a [u8],
1249 dest_id: Option<UnsignedByteField>,
1250 ) -> PusTmCreator<'a, 'b> {
1251 let sph = SpHeader::new_for_unseg_tm(u11::new(0x123), u14::new(0x234), 0);
1252 let mut tm_header = PusTmSecondaryHeader::new_simple(17, 2, timestamp);
1253 tm_header.dest_id = dest_id;
1254 PusTmCreator::new_no_source_data(sph, tm_header, true)
1255 }
1256
1257 fn ping_reply_with_data_and_additional_fields<'a, 'b>(
1258 data: &'b [u8],
1259 msg_counter: Option<u8>,
1260 dest_id: Option<UnsignedByteField>,
1261 timestamp: &'a [u8],
1262 ) -> PusTmCreator<'a, 'b> {
1263 let sph = SpHeader::new_for_unseg_tm(u11::new(0x123), u14::new(0x234), 0);
1264 let tm_header = PusTmSecondaryHeader::new(17, 2, msg_counter, dest_id, timestamp, 0);
1265 PusTmCreator::new(sph, tm_header, data, true)
1266 }
1267
1268 fn ping_reply_with_data<'a, 'b>(data: &'b [u8], timestamp: &'a [u8]) -> PusTmCreator<'a, 'b> {
1269 let sph = SpHeader::new_for_unseg_tm(u11::new(0x123), u14::new(0x234), 0);
1270 let tm_header = PusTmSecondaryHeader::new_simple(17, 2, timestamp);
1271 PusTmCreator::new(sph, tm_header, data, true)
1272 }
1273
1274 fn base_hk_reply<'a, 'b>(timestamp: &'a [u8], src_data: &'b [u8]) -> PusTmCreator<'a, 'b> {
1275 let sph = SpHeader::new_for_unseg_tm(u11::new(0x123), u14::new(0x234), 0);
1276 let tc_header = PusTmSecondaryHeader::new_simple(3, 5, timestamp);
1277 PusTmCreator::new(sph, tc_header, src_data, true)
1278 }
1279
1280 fn dummy_timestamp() -> &'static [u8] {
1281 &[0, 1, 2, 3, 4, 5, 6]
1282 }
1283
1284 #[test]
1285 fn test_basic() {
1286 let timestamp = dummy_timestamp();
1287 let pus_tm = ping_reply_no_data(timestamp, None);
1288 verify_ping_reply(&pus_tm, false, 18, dummy_timestamp(), None, None);
1289 }
1290
1291 #[test]
1292 fn test_basic_simple_api() {
1293 let sph = SpHeader::new_for_unseg_tm(u11::new(0x123), u14::new(0x234), 0);
1294 let time_provider = CdsTime::new_with_u16_days(0, 0);
1295 let mut stamp_buf: [u8; 8] = [0; 8];
1296 let pus_tm =
1297 PusTmCreator::new_simple(sph, 17, 2, &time_provider, &mut stamp_buf, &[], true)
1298 .unwrap();
1299 verify_ping_reply(&pus_tm, false, 18, &[64, 0, 0, 0, 0, 0, 0], None, None);
1300 }
1301
1302 #[test]
1303 fn test_basic_simple_api_with_dest_id_msg_counter() {
1304 let msg_counter = Some(5);
1305 let dest_id = Some(UnsignedByteFieldU16::new(0x1f1f).into());
1306 let pus_tm = ping_reply_with_data_and_additional_fields(
1307 &[],
1308 msg_counter,
1309 dest_id,
1310 dummy_timestamp(),
1311 );
1312 verify_ping_reply(&pus_tm, false, 21, dummy_timestamp(), dest_id, msg_counter);
1313 }
1314
1315 #[test]
1316 fn test_basic_simple_api_with_dest_id() {
1317 let msg_counter = None;
1318 let dest_id = Some(UnsignedByteFieldU16::new(0x1f1f).into());
1319 let pus_tm = ping_reply_with_data_and_additional_fields(
1320 &[],
1321 msg_counter,
1322 dest_id,
1323 dummy_timestamp(),
1324 );
1325 verify_ping_reply(&pus_tm, false, 20, dummy_timestamp(), dest_id, msg_counter);
1326 }
1327
1328 #[test]
1329 fn test_basic_simple_api_with_msg_counter() {
1330 let msg_counter = Some(5);
1331 let dest_id = None;
1332 let pus_tm = ping_reply_with_data_and_additional_fields(
1333 &[],
1334 msg_counter,
1335 dest_id,
1336 dummy_timestamp(),
1337 );
1338 verify_ping_reply(&pus_tm, false, 19, dummy_timestamp(), dest_id, msg_counter);
1339 }
1340
1341 #[test]
1342 fn test_serialization_no_source_data() {
1343 let timestamp = dummy_timestamp();
1344 let pus_tm = ping_reply_no_data(timestamp, None);
1345 let mut buf: [u8; 32] = [0; 32];
1346 let ser_len = pus_tm
1347 .write_to_bytes(&mut buf)
1348 .expect("Serialization failed");
1349 assert_eq!(ser_len, 18);
1350 verify_raw_ping_reply(pus_tm.checksum(), &buf, ser_len, None, None);
1351 }
1352
1353 #[test]
1354 fn test_serialization_with_additional_fields() {
1355 let msg_counter = Some(5);
1356 let dest_id = Some(UnsignedByteFieldU16::new(0x1f1f).into());
1357 let pus_tm = ping_reply_with_data_and_additional_fields(
1358 &[],
1359 msg_counter,
1360 dest_id,
1361 dummy_timestamp(),
1362 );
1363 let mut buf: [u8; 32] = [0; 32];
1364 let ser_len = pus_tm
1365 .write_to_bytes(&mut buf)
1366 .expect("Serialization failed");
1367 assert_eq!(ser_len, 21);
1368 verify_raw_ping_reply(pus_tm.checksum(), &buf, ser_len, msg_counter, dest_id);
1369 }
1370
1371 #[test]
1372 fn test_serialization_with_dest_id() {
1373 let msg_counter = None;
1374 let dest_id = Some(UnsignedByteFieldU16::new(0x1f1f).into());
1375 let pus_tm = ping_reply_with_data_and_additional_fields(
1376 &[],
1377 msg_counter,
1378 dest_id,
1379 dummy_timestamp(),
1380 );
1381 let mut buf: [u8; 32] = [0; 32];
1382 let ser_len = pus_tm
1383 .write_to_bytes(&mut buf)
1384 .expect("Serialization failed");
1385 assert_eq!(ser_len, 20);
1386 verify_raw_ping_reply(pus_tm.checksum(), &buf, ser_len, msg_counter, dest_id);
1387 }
1388
1389 #[test]
1390 fn test_serialization_with_msg_counter() {
1391 let msg_counter = Some(5);
1392 let dest_id = None;
1393 let pus_tm = ping_reply_with_data_and_additional_fields(
1394 &[],
1395 msg_counter,
1396 dest_id,
1397 dummy_timestamp(),
1398 );
1399 let mut buf: [u8; 32] = [0; 32];
1400 let ser_len = pus_tm
1401 .write_to_bytes(&mut buf)
1402 .expect("Serialization failed");
1403 assert_eq!(ser_len, 19);
1404 verify_raw_ping_reply(pus_tm.checksum(), &buf, ser_len, msg_counter, dest_id);
1405 }
1406
1407 #[test]
1408 fn test_serialization_no_source_data_alt_ctor() {
1409 let timestamp = dummy_timestamp();
1410 let sph = SpHeader::new_for_unseg_tm(u11::new(0x123), u14::new(0x234), 0);
1411 let tm_header = PusTmSecondaryHeader::new_simple(17, 2, timestamp);
1412 let mut buf: [u8; 32] = [0; 32];
1413 let mut pus_tm =
1414 PusTmCreatorWithReservedSourceData::new(&mut buf, sph, tm_header, 0).unwrap();
1415 assert_eq!(pus_tm.source_data_len(), 0);
1416 assert_eq!(pus_tm.source_data(), &[]);
1417 assert_eq!(pus_tm.source_data_mut(), &[]);
1418 let ser_len = pus_tm.finalize();
1419 assert_eq!(ser_len, 18);
1420 verify_raw_ping_reply(None, &buf, ser_len, None, None);
1421 }
1422
1423 #[test]
1424 fn test_serialization_no_source_data_alt_ctor_no_crc() {
1425 let timestamp = dummy_timestamp();
1426 let sph = SpHeader::new_for_unseg_tm(u11::new(0x123), u14::new(0x234), 0);
1427 let tm_header = PusTmSecondaryHeader::new_simple(17, 2, timestamp);
1428 let mut buf: [u8; 32] = [0; 32];
1429 let mut pus_tm =
1430 PusTmCreatorWithReservedSourceData::new(&mut buf, sph, tm_header, 0).unwrap();
1431 assert_eq!(pus_tm.source_data_len(), 0);
1432 assert_eq!(pus_tm.source_data(), &[]);
1433 assert_eq!(pus_tm.source_data_mut(), &[]);
1434 let ser_len = pus_tm.finalize_no_crc();
1435 assert_eq!(ser_len, 16);
1436 verify_raw_ping_reply_no_crc(&buf, None, None);
1437 assert_eq!(buf[16], 0);
1438 assert_eq!(buf[17], 0);
1439 }
1440
1441 #[test]
1442 fn test_serialization_no_source_data_no_table() {
1443 let timestamp = dummy_timestamp();
1444 let pus_tm = ping_reply_no_data(timestamp, None);
1445 let mut buf: [u8; 32] = [0; 32];
1446 let ser_len = pus_tm
1447 .write_to_bytes_crc_no_table(&mut buf)
1448 .expect("Serialization failed");
1449 assert_eq!(ser_len, 18);
1450 verify_raw_ping_reply(pus_tm.checksum(), &buf, ser_len, None, None);
1451 }
1452
1453 #[test]
1454 fn test_serialization_no_source_data_no_crc() {
1455 let timestamp = dummy_timestamp();
1456 let pus_tm = ping_reply_no_data(timestamp, None);
1457 let mut buf: [u8; 32] = [0; 32];
1458 let ser_len = pus_tm
1459 .write_to_bytes_no_crc(&mut buf)
1460 .expect("Serialization failed");
1461 assert_eq!(ser_len, 16);
1462 assert_eq!(buf[16], 0);
1463 assert_eq!(buf[17], 0);
1464 }
1465
1466 #[test]
1467 fn test_serialization_with_source_data() {
1468 let src_data = [1, 2, 3];
1469 let hk_reply = base_hk_reply(dummy_timestamp(), &src_data);
1470 let mut buf: [u8; 32] = [0; 32];
1471 let ser_len = hk_reply
1472 .write_to_bytes(&mut buf)
1473 .expect("Serialization failed");
1474 assert_eq!(ser_len, 21);
1475 assert_eq!(buf[16], 1);
1476 assert_eq!(buf[17], 2);
1477 assert_eq!(buf[18], 3);
1478 }
1479
1480 #[test]
1481 fn test_serialization_with_source_data_alt_ctor() {
1482 let src_data = &[1, 2, 3];
1483 let mut buf: [u8; 32] = [0; 32];
1484 let sph = SpHeader::new_for_unseg_tm(u11::new(0x123), u14::new(0x234), 0);
1485 let tc_header = PusTmSecondaryHeader::new_simple(3, 5, dummy_timestamp());
1486 let mut hk_reply_unwritten =
1487 PusTmCreatorWithReservedSourceData::new(&mut buf, sph, tc_header, 3).unwrap();
1488 assert_eq!(hk_reply_unwritten.source_data_len(), 3);
1489 assert_eq!(hk_reply_unwritten.source_data(), &[0, 0, 0]);
1490 assert_eq!(hk_reply_unwritten.source_data_mut(), &[0, 0, 0]);
1491 let source_data_mut = hk_reply_unwritten.source_data_mut();
1492 source_data_mut.copy_from_slice(src_data);
1493 let ser_len = hk_reply_unwritten.finalize();
1494 assert_eq!(ser_len, 21);
1495 assert_eq!(buf[16], 1);
1496 assert_eq!(buf[17], 2);
1497 assert_eq!(buf[18], 3);
1498 }
1499
1500 #[test]
1501 fn test_serialization_with_source_data_alt_ctor_no_table() {
1502 let src_data = &[1, 2, 3];
1503 let mut buf: [u8; 32] = [0; 32];
1504 let sph = SpHeader::new_for_unseg_tm(u11::new(0x123), u14::new(0x234), 0);
1505 let tc_header = PusTmSecondaryHeader::new_simple(3, 5, dummy_timestamp());
1506 let mut hk_reply_unwritten =
1507 PusTmCreatorWithReservedSourceData::new(&mut buf, sph, tc_header, 3).unwrap();
1508 assert_eq!(hk_reply_unwritten.source_data_len(), 3);
1509 assert_eq!(hk_reply_unwritten.source_data(), &[0, 0, 0]);
1510 assert_eq!(hk_reply_unwritten.source_data_mut(), &[0, 0, 0]);
1511 let source_data_mut = hk_reply_unwritten.source_data_mut();
1512 source_data_mut.copy_from_slice(src_data);
1513 let ser_len = hk_reply_unwritten.finalize_crc_no_table();
1514 assert_eq!(ser_len, 21);
1515 assert_eq!(buf[16], 1);
1516 assert_eq!(buf[17], 2);
1517 assert_eq!(buf[18], 3);
1518 }
1519
1520 #[test]
1521 fn test_setters() {
1522 let timestamp = dummy_timestamp();
1523 let mut pus_tm = ping_reply_no_data(timestamp, None);
1524 let u16_dest_id = UnsignedByteFieldU16::new(0x7fff).into();
1525 pus_tm.set_dest_id(Some(u16_dest_id));
1526 pus_tm.set_msg_counter(Some(0x1f));
1527 assert_eq!(pus_tm.dest_id(), Some(u16_dest_id));
1528 assert_eq!(pus_tm.msg_counter(), Some(0x1f));
1529 pus_tm.set_apid(u11::new(0x7ff));
1530 assert_eq!(pus_tm.apid().value(), 0x7ff);
1531 }
1532
1533 #[test]
1534 fn test_write_into_vec() {
1535 let timestamp = dummy_timestamp();
1536 let pus_tm = ping_reply_no_data(timestamp, None);
1537 let tm_vec = pus_tm.to_vec().expect("Serialization failed");
1538 assert_eq!(tm_vec.len(), 18);
1539 let tm_deserialized = PusTmReader::new(tm_vec.as_slice(), &MIN_SEC_HEADER_PARAMS)
1540 .expect("Deserialization failed");
1541 assert_eq!(tm_vec.len(), tm_deserialized.packet_len());
1542 verify_ping_reply_with_reader(&tm_deserialized, false, 18, dummy_timestamp(), None, None);
1543 }
1544
1545 #[test]
1546 fn test_deserialization_no_source_data() {
1547 let timestamp = dummy_timestamp();
1548 let pus_tm = ping_reply_no_data(timestamp, None);
1549 let mut buf: [u8; 32] = [0; 32];
1550 let ser_len = pus_tm
1551 .write_to_bytes(&mut buf)
1552 .expect("Serialization failed");
1553 assert_eq!(ser_len, 18);
1554 let tm_deserialized =
1555 PusTmReader::new(&buf, &MIN_SEC_HEADER_PARAMS).expect("Deserialization failed");
1556 assert_eq!(ser_len, tm_deserialized.packet_len());
1557 assert_eq!(tm_deserialized.user_data(), tm_deserialized.source_data());
1558 assert_eq!(tm_deserialized.raw_data(), &buf[..ser_len]);
1559 assert_eq!(tm_deserialized.crc16(), pus_tm.checksum().unwrap());
1560 verify_ping_reply_with_reader(&tm_deserialized, false, 18, dummy_timestamp(), None, None);
1561 }
1562
1563 fn generic_test_deserialization_no_source_data_with_additional_fields(
1564 src_data: &[u8],
1565 expected_full_len: usize,
1566 msg_counter: Option<u8>,
1567 dest_id: Option<UnsignedByteField>,
1568 ) {
1569 let timestamp = dummy_timestamp();
1570 let pus_tm =
1571 ping_reply_with_data_and_additional_fields(src_data, msg_counter, dest_id, timestamp);
1572 let mut buf: [u8; 32] = [0; 32];
1573 let ser_len = pus_tm
1574 .write_to_bytes(&mut buf)
1575 .expect("Serialization failed");
1576 assert_eq!(ser_len, expected_full_len);
1577 let tm_deserialized = PusTmReader::new(
1578 &buf,
1579 &SecondaryHeaderParameters {
1580 timestamp_len: 7,
1581 has_msg_counter: msg_counter.is_some(),
1582 opt_dest_id_len: dest_id.as_ref().map(|id| id.size()),
1583 spare_bytes: 0,
1584 },
1585 )
1586 .expect("Deserialization failed");
1587 assert_eq!(ser_len, tm_deserialized.packet_len());
1588 assert_eq!(tm_deserialized.user_data(), tm_deserialized.source_data());
1589 assert_eq!(tm_deserialized.raw_data(), &buf[..ser_len]);
1590 assert_eq!(tm_deserialized.crc16(), pus_tm.checksum().unwrap());
1591 verify_ping_reply_with_reader(
1592 &tm_deserialized,
1593 false,
1594 expected_full_len,
1595 dummy_timestamp(),
1596 dest_id,
1597 msg_counter,
1598 );
1599 }
1600
1601 #[test]
1602 fn test_deserialization_with_source_data_dest_id_msg_counter() {
1603 let msg_counter = Some(5);
1604 let dest_id = Some(UnsignedByteFieldU16::new(0x1f1f).into());
1605 generic_test_deserialization_no_source_data_with_additional_fields(
1606 &[1, 2, 3],
1607 24,
1608 msg_counter,
1609 dest_id,
1610 );
1611 }
1612
1613 #[test]
1614 fn test_deserialization_no_source_data_with_dest_id_msg_counter() {
1615 let msg_counter = Some(5);
1616 let dest_id = Some(UnsignedByteFieldU16::new(0x1f1f).into());
1617 generic_test_deserialization_no_source_data_with_additional_fields(
1618 &[],
1619 21,
1620 msg_counter,
1621 dest_id,
1622 );
1623 }
1624
1625 #[test]
1626 fn test_deserialization_no_source_data_with_msg_counter() {
1627 let msg_counter = Some(5);
1628 let dest_id = None;
1629 generic_test_deserialization_no_source_data_with_additional_fields(
1630 &[],
1631 19,
1632 msg_counter,
1633 dest_id,
1634 );
1635 }
1636
1637 #[test]
1638 fn test_deserialization_no_source_data_with_dest_id() {
1639 let msg_counter = None;
1640 let dest_id = Some(UnsignedByteFieldU16::new(0x1f1f).into());
1641 generic_test_deserialization_no_source_data_with_additional_fields(
1642 &[],
1643 20,
1644 msg_counter,
1645 dest_id,
1646 );
1647 }
1648
1649 #[test]
1650 fn test_deserialization_no_source_data_with_trait() {
1651 let timestamp = dummy_timestamp();
1652 let pus_tm = ping_reply_no_data(timestamp, None);
1653 let mut buf: [u8; 32] = [0; 32];
1654 let ser_len =
1655 WritablePusPacket::write_to_bytes(&pus_tm, &mut buf).expect("Serialization failed");
1656 assert_eq!(ser_len, 18);
1657 let tm_deserialized =
1658 PusTmReader::new(&buf, &MIN_SEC_HEADER_PARAMS).expect("Deserialization failed");
1659 assert_eq!(ser_len, tm_deserialized.packet_len());
1660 assert_eq!(tm_deserialized.user_data(), tm_deserialized.source_data());
1661 assert_eq!(tm_deserialized.raw_data(), &buf[..ser_len]);
1662 assert_eq!(tm_deserialized.crc16(), pus_tm.checksum().unwrap());
1663 verify_ping_reply_with_reader(&tm_deserialized, false, 18, dummy_timestamp(), None, None);
1664 }
1665
1666 #[test]
1667 fn test_deserialization_no_table() {
1668 let timestamp = dummy_timestamp();
1669 let pus_tm = ping_reply_no_data(timestamp, None);
1670 let mut buf: [u8; 32] = [0; 32];
1671 let ser_len = pus_tm
1672 .write_to_bytes(&mut buf)
1673 .expect("Serialization failed");
1674 assert_eq!(ser_len, 18);
1675 let tm_deserialized = PusTmReader::new_crc_no_table(&buf, &MIN_SEC_HEADER_PARAMS)
1676 .expect("Deserialization failed");
1677 assert_eq!(ser_len, tm_deserialized.packet_len());
1678 assert_eq!(tm_deserialized.user_data(), tm_deserialized.source_data());
1679 assert_eq!(tm_deserialized.raw_data(), &buf[..ser_len]);
1680 assert_eq!(tm_deserialized.crc16(), pus_tm.checksum().unwrap());
1681 verify_ping_reply_with_reader(&tm_deserialized, false, 18, dummy_timestamp(), None, None);
1682 }
1683
1684 #[test]
1685 fn test_deserialization_faulty_crc() {
1686 let timestamp = dummy_timestamp();
1687 let pus_tm = ping_reply_no_data(timestamp, None);
1688 let mut buf: [u8; 32] = [0; 32];
1689 let ser_len = pus_tm
1690 .write_to_bytes(&mut buf)
1691 .expect("Serialization failed");
1692 assert_eq!(ser_len, 18);
1693 buf[ser_len - 2] = 0;
1694 buf[ser_len - 1] = 0;
1695 let tm_error = PusTmReader::new(&buf, &MIN_SEC_HEADER_PARAMS);
1696 assert!(tm_error.is_err());
1697 let tm_error = tm_error.unwrap_err();
1698 if let PusError::ChecksumFailure(crc) = tm_error {
1699 assert_eq!(crc, 0);
1700 assert_eq!(
1701 tm_error.to_string(),
1702 "checksum verification for crc16 0x0000 failed"
1703 );
1704 }
1705 }
1706
1707 #[test]
1708 fn test_manual_field_update() {
1709 let sph = SpHeader::new_for_unseg_tm(u11::new(0x123), u14::new(0x234), 0);
1710 let tc_header = PusTmSecondaryHeader::new_simple(17, 2, dummy_timestamp());
1711 let mut tm = PusTmCreator::new_no_source_data(sph, tc_header, false);
1712 tm.calc_crc_on_serialization = false;
1713 assert_eq!(tm.data_len(), 0x00);
1714 let mut buf: [u8; 32] = [0; 32];
1715 tm.update_ccsds_data_len();
1716 assert_eq!(tm.data_len(), 11);
1717 tm.calc_own_crc16();
1718 let res = tm.write_to_bytes(&mut buf);
1719 assert!(res.is_ok());
1720 tm.sp_header.data_len = 0;
1721 tm.update_packet_fields();
1722 assert_eq!(tm.data_len(), 11);
1723 }
1724
1725 #[test]
1726 fn test_target_buf_too_small() {
1727 let timestamp = dummy_timestamp();
1728 let pus_tm = ping_reply_no_data(timestamp, None);
1729 let mut buf: [u8; 16] = [0; 16];
1730 let res = pus_tm.write_to_bytes(&mut buf);
1731 assert!(res.is_err());
1732 let error = res.unwrap_err();
1733 if let ByteConversionError::ToSliceTooSmall { found, expected } = error {
1734 assert_eq!(expected, 18);
1735 assert_eq!(found, 16);
1736 } else {
1737 panic!("Invalid error {:?}", error);
1738 }
1739 }
1740
1741 #[test]
1742 #[cfg(feature = "alloc")]
1743 fn test_append_to_vec() {
1744 let timestamp = dummy_timestamp();
1745 let pus_tm = ping_reply_no_data(timestamp, None);
1746 let mut vec = Vec::new();
1747 let res = pus_tm.append_to_vec(&mut vec);
1748 assert!(res.is_ok());
1749 assert_eq!(res.unwrap(), 18);
1750 verify_raw_ping_reply(pus_tm.checksum(), vec.as_slice(), res.unwrap(), None, None);
1751 }
1752
1753 #[test]
1754 #[cfg(feature = "alloc")]
1755 fn test_append_to_vec_with_src_data() {
1756 let src_data = [1, 2, 3];
1757 let hk_reply = base_hk_reply(dummy_timestamp(), &src_data);
1758 let mut vec = Vec::new();
1759 vec.push(4);
1760 let res = hk_reply.append_to_vec(&mut vec);
1761 assert!(res.is_ok());
1762 assert_eq!(res.unwrap(), 21);
1763 assert_eq!(vec.len(), 22);
1764 }
1765
1766 fn verify_raw_ping_reply_no_crc(
1767 buf: &[u8],
1768 msg_counter: Option<u8>,
1769 dest_id: Option<UnsignedByteField>,
1770 ) {
1771 assert_eq!(buf[0], 0x09);
1773 assert_eq!(buf[1], 0x23);
1775 assert_eq!(buf[2], 0xc2);
1777 assert_eq!(buf[3], 0x34);
1778 let mut expected_len = 11;
1779 if let Some(dest_id) = dest_id {
1780 expected_len += dest_id.size();
1781 }
1782 if msg_counter.is_some() {
1783 expected_len += 1;
1784 }
1785 assert_eq!(((buf[4] as u16) << 8) | buf[5] as u16, expected_len as u16);
1786 assert_eq!(buf[6], (PusA as u8) << 4);
1787 assert_eq!(buf[7], 17);
1788 assert_eq!(buf[8], 2);
1789 let mut current_idx = 9;
1790 if let Some(msg_counter) = msg_counter {
1791 assert_eq!(buf[current_idx], msg_counter);
1792 current_idx += 1;
1793 }
1794 if let Some(dest_id) = dest_id {
1795 let extracted_dest_id =
1796 UnsignedByteField::new_from_be_bytes(dest_id.size(), &buf[current_idx..])
1797 .expect("Failed to extract destination ID");
1798 assert_eq!(extracted_dest_id, dest_id);
1799 current_idx += dest_id.size();
1800 }
1801 assert_eq!(
1803 &buf[current_idx..current_idx + dummy_timestamp().len()],
1804 dummy_timestamp()
1805 );
1806 }
1807
1808 fn verify_raw_ping_reply(
1809 crc16: Option<u16>,
1810 buf: &[u8],
1811 exp_full_len: usize,
1812 msg_counter: Option<u8>,
1813 dest_id: Option<UnsignedByteField>,
1814 ) {
1815 verify_raw_ping_reply_no_crc(buf, msg_counter, dest_id);
1816 let mut digest = CRC_CCITT_FALSE.digest();
1817 digest.update(&buf[0..exp_full_len - 2]);
1818 let crc16_calced = digest.finalize();
1819 let crc16_read = u16::from_be_bytes([buf[exp_full_len - 2], buf[exp_full_len - 1]]);
1820 assert_eq!(crc16_read, crc16_calced);
1821 if let Some(crc16) = crc16 {
1822 assert_eq!(((crc16 >> 8) & 0xff) as u8, buf[exp_full_len - 2]);
1823 assert_eq!((crc16 & 0xff) as u8, buf[exp_full_len - 1]);
1824 }
1825 }
1826
1827 fn verify_ping_reply(
1828 tm: &PusTmCreator,
1829 has_user_data: bool,
1830 exp_full_len: usize,
1831 exp_timestamp: &[u8],
1832 dest_id: Option<UnsignedByteField>,
1833 msg_counter: Option<u8>,
1834 ) {
1835 assert_eq!(tm.len_written(), exp_full_len);
1836 assert_eq!(tm.timestamp(), exp_timestamp);
1837 assert_eq!(tm.source_data(), tm.user_data());
1838 verify_ping_reply_generic(tm, has_user_data, exp_full_len, dest_id, msg_counter);
1839 }
1840
1841 fn verify_ping_reply_with_reader(
1842 tm: &PusTmReader,
1843 has_user_data: bool,
1844 exp_full_len: usize,
1845 exp_timestamp: &[u8],
1846 dest_id: Option<UnsignedByteField>,
1847 msg_counter: Option<u8>,
1848 ) {
1849 assert_eq!(tm.len_packed(), exp_full_len);
1850 assert_eq!(tm.timestamp(), exp_timestamp);
1851 verify_ping_reply_generic(tm, has_user_data, exp_full_len, dest_id, msg_counter);
1852 }
1853
1854 fn verify_ping_reply_generic(
1855 tm: &(impl GenericPusTmSecondaryHeader + PusPacket),
1856 has_user_data: bool,
1857 exp_full_len: usize,
1858 dest_id: Option<UnsignedByteField>,
1859 msg_counter: Option<u8>,
1860 ) {
1861 assert!(tm.is_tm());
1862 assert_eq!(PusPacket::service_type_id(tm), 17);
1863 assert_eq!(GenericPusTmSecondaryHeader::service(tm), 17);
1864 assert_eq!(PusPacket::message_subtype_id(tm), 2);
1865 assert_eq!(GenericPusTmSecondaryHeader::subservice(tm), 2);
1866 assert!(tm.sec_header_flag());
1867 if has_user_data {
1868 assert!(!tm.user_data().is_empty());
1869 }
1870 assert_eq!(tm.apid().value(), 0x123);
1871 assert_eq!(tm.seq_count().value(), 0x234);
1872 assert_eq!(PusPacket::pus_version(tm).unwrap(), PusVersion::PusA);
1873 assert_eq!(
1874 GenericPusTmSecondaryHeader::pus_version(tm),
1875 PusVersion::PusA
1876 );
1877 assert_eq!(tm.data_len(), exp_full_len as u16 - 7);
1878 assert_eq!(tm.dest_id(), dest_id);
1879 assert_eq!(tm.msg_counter(), msg_counter);
1880 }
1881
1882 #[test]
1883 fn partial_eq_pus_tm() {
1884 let timestamp = dummy_timestamp();
1885 let pus_tm_1 = ping_reply_no_data(timestamp, None);
1886 let pus_tm_2 = ping_reply_no_data(timestamp, None);
1887 assert_eq!(pus_tm_1, pus_tm_2);
1888 }
1889
1890 #[test]
1891 fn partial_eq_serialized_vs_derialized() {
1892 let timestamp = dummy_timestamp();
1893 let pus_tm = ping_reply_no_data(timestamp, None);
1894 let mut buf = [0; 32];
1895 pus_tm.write_to_bytes(&mut buf).unwrap();
1896 assert_eq!(
1897 pus_tm,
1898 PusTmReader::new(&buf, &MIN_SEC_HEADER_PARAMS).unwrap()
1899 );
1900 }
1901
1902 #[test]
1903 fn test_zero_copy_writer() {
1904 let ping_tm = ping_reply_no_data(dummy_timestamp(), None);
1905 let mut buf: [u8; 64] = [0; 64];
1906 let tm_size = ping_tm
1907 .write_to_bytes(&mut buf)
1908 .expect("writing PUS ping TM failed");
1909 let mut writer = PusTmZeroCopyWriter::new(&mut buf[..tm_size], &MIN_SEC_HEADER_PARAMS)
1910 .expect("Creating zero copy writer failed");
1911 writer.set_seq_count(MAX_SEQ_COUNT);
1912 writer.set_apid(MAX_APID);
1913 writer.finish();
1914 let tm_read_back =
1916 PusTmReader::new(&buf, &MIN_SEC_HEADER_PARAMS).expect("Re-creating PUS TM failed");
1917 assert_eq!(tm_read_back.packet_len(), tm_size);
1918 assert!(tm_read_back.msg_counter().is_none());
1919 assert!(tm_read_back.dest_id().is_none());
1920 assert_eq!(tm_read_back.seq_count(), MAX_SEQ_COUNT);
1921 assert_eq!(tm_read_back.apid(), MAX_APID);
1922 }
1923
1924 #[test]
1925 fn test_zero_copy_writer_ccsds_api() {
1926 let dest_id = UnsignedByteFieldU16::new(0x1f1f);
1927 let ping_tm = ping_reply_no_data(dummy_timestamp(), Some(dest_id.into()));
1928 let mut buf: [u8; 64] = [0; 64];
1929 let tm_size = ping_tm
1930 .write_to_bytes(&mut buf)
1931 .expect("writing PUS ping TM failed");
1932 let mut writer = PusTmZeroCopyWriter::new(
1933 &mut buf[..tm_size],
1934 &SecondaryHeaderParameters {
1935 timestamp_len: dummy_timestamp().len(),
1936 has_msg_counter: false,
1937 opt_dest_id_len: Some(2),
1938 spare_bytes: 0,
1939 },
1940 )
1941 .expect("Creating zero copy writer failed");
1942 writer.set_seq_count(MAX_SEQ_COUNT);
1943 writer.set_apid(MAX_APID);
1944 writer
1945 .set_destination_id(UnsignedByteFieldU16::new(0xf1f1).into())
1946 .unwrap();
1947 assert_eq!(PusPacket::service_type_id(&writer), 17);
1948 assert_eq!(PusPacket::message_subtype_id(&writer), 2);
1949 assert_eq!(
1950 writer.dest_id().unwrap().unwrap(),
1951 UnsignedByteFieldU16::new(0xf1f1).into()
1952 );
1953 assert_eq!(writer.apid(), MAX_APID);
1954 assert_eq!(writer.seq_count(), MAX_SEQ_COUNT);
1955 }
1956
1957 #[test]
1958 fn test_zero_copy_pus_api() {
1959 let ping_tm = ping_reply_with_data(DUMMY_DATA, dummy_timestamp());
1960 let mut buf: [u8; 64] = [0; 64];
1961 let tm_size = ping_tm
1962 .write_to_bytes(&mut buf)
1963 .expect("writing PUS ping TM failed");
1964 let crc16_raw = u16::from_be_bytes(buf[tm_size - 2..tm_size].try_into().unwrap());
1965 let mut writer = PusTmZeroCopyWriter::new(&mut buf[..tm_size], &MIN_SEC_HEADER_PARAMS)
1966 .expect("Creating zero copy writer failed");
1967 writer.set_seq_count(MAX_SEQ_COUNT);
1968 writer.set_apid(MAX_APID);
1969 assert_eq!(PusPacket::service_type_id(&writer), 17);
1970 assert_eq!(PusPacket::message_subtype_id(&writer), 2);
1971 assert!(writer.dest_id().unwrap().is_none());
1972 assert!(writer.msg_counter().is_none());
1973 if let Err(err) = writer.set_destination_id(UnsignedByteFieldU16::new(0xf1f1).into()) {
1974 matches!(err, DestIdOperationError::FieldNotPresent(_));
1975 } else {
1976 panic!("setting destination ID should have failed");
1977 }
1978 if let Err(err) = writer.set_msg_count(22) {
1979 matches!(err, SecondaryHeaderFieldNotPresentError);
1980 } else {
1981 panic!("setting destination ID should have failed");
1982 }
1983 assert_eq!(writer.user_data(), DUMMY_DATA);
1984 let crc16 = writer.checksum();
1986 assert!(crc16.is_some());
1987 assert_eq!(crc16.unwrap(), crc16_raw);
1988 writer.finish();
1989 }
1990
1991 #[test]
1992 fn test_sec_header_without_stamp() {
1993 let sec_header = PusTmSecondaryHeader::new_simple_no_timestamp(17, 1);
1994 assert_eq!(sec_header.timestamp, &[]);
1995 }
1996
1997 #[test]
1998 fn test_reader_partial_eq() {
1999 let timestamp = dummy_timestamp();
2000 let pus_tm = ping_reply_no_data(timestamp, None);
2001 let mut buf = [0; 32];
2002 pus_tm.write_to_bytes(&mut buf).unwrap();
2003 let tm_0 = PusTmReader::new(&buf, &MIN_SEC_HEADER_PARAMS).unwrap();
2004 let tm_1 = PusTmReader::new(&buf, &MIN_SEC_HEADER_PARAMS).unwrap();
2005 assert_eq!(tm_0, tm_1);
2006 }
2007 #[test]
2008 fn test_reader_buf_too_small_2() {
2009 let timestamp = dummy_timestamp();
2010 let pus_tm = ping_reply_no_data(timestamp, None);
2011 let mut buf = [0; 32];
2012 let written = pus_tm.write_to_bytes(&mut buf).unwrap();
2013 let tm_error = PusTmReader::new(
2014 &buf[0..PUS_TM_MIN_LEN_WITHOUT_SOURCE_DATA + 1],
2015 &MIN_SEC_HEADER_PARAMS,
2016 );
2017 assert!(tm_error.is_err());
2018 let tm_error = tm_error.unwrap_err();
2019 if let PusError::ByteConversion(ByteConversionError::FromSliceTooSmall {
2020 found,
2021 expected,
2022 }) = tm_error
2023 {
2024 assert_eq!(found, PUS_TM_MIN_LEN_WITHOUT_SOURCE_DATA + 1);
2025 assert_eq!(expected, written);
2026 } else {
2027 panic!("unexpected error {tm_error}")
2028 }
2029 }
2030 #[test]
2031 fn test_reader_buf_too_small() {
2032 let timestamp = dummy_timestamp();
2033 let pus_tm = ping_reply_no_data(timestamp, None);
2034 let mut buf = [0; 32];
2035 pus_tm.write_to_bytes(&mut buf).unwrap();
2036 let tm_error = PusTmReader::new(&buf[0..5], &MIN_SEC_HEADER_PARAMS);
2037 assert!(tm_error.is_err());
2038 let tm_error = tm_error.unwrap_err();
2039 if let PusError::ByteConversion(ByteConversionError::FromSliceTooSmall {
2040 found,
2041 expected,
2042 }) = tm_error
2043 {
2044 assert_eq!(found, 5);
2045 assert_eq!(expected, PUS_TM_MIN_LEN_WITHOUT_SOURCE_DATA);
2046 } else {
2047 panic!("unexpected error {tm_error}")
2048 }
2049 }
2050
2051 #[test]
2052 #[cfg(feature = "serde")]
2053 fn test_serialization_creator_serde() {
2054 let sph = SpHeader::new_for_unseg_tm(u11::new(0x123), u14::new(0x234), 0);
2055 let time_provider = CdsTime::new_with_u16_days(0, 0);
2056 let mut stamp_buf: [u8; 8] = [0; 8];
2057 let pus_tm =
2058 PusTmCreator::new_simple(sph, 17, 2, &time_provider, &mut stamp_buf, &[], true)
2059 .unwrap();
2060
2061 let output = to_allocvec(&pus_tm).unwrap();
2062 let output_converted_back: PusTmCreator = from_bytes(&output).unwrap();
2063 assert_eq!(output_converted_back, pus_tm);
2064 }
2065
2066 #[test]
2067 #[cfg(feature = "serde")]
2068 fn test_serialization_reader_serde() {
2069 let sph = SpHeader::new_for_unseg_tm(u11::new(0x123), u14::new(0x234), 0);
2070 let time_provider = CdsTime::new_with_u16_days(0, 0);
2071 let mut stamp_buf: [u8; 8] = [0; 8];
2072 let pus_tm =
2073 PusTmCreator::new_simple(sph, 17, 2, &time_provider, &mut stamp_buf, &[], true)
2074 .unwrap();
2075 let pus_tm_vec = pus_tm.to_vec().unwrap();
2076 let tm_reader = PusTmReader::new(&pus_tm_vec, &MIN_SEC_HEADER_PARAMS).unwrap();
2077 let output = to_allocvec(&tm_reader).unwrap();
2078 let output_converted_back: PusTmReader = from_bytes(&output).unwrap();
2079 assert_eq!(output_converted_back, tm_reader);
2080 }
2081}