API update
Some checks failed
Rust/spacepackets/pipeline/head There was a failure building this commit
Some checks failed
Rust/spacepackets/pipeline/head There was a failure building this commit
This commit is contained in:
parent
f406957752
commit
c85177ece9
@ -19,6 +19,9 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
|
||||
- `UnsignedByteField` as a type-erased helper.
|
||||
- Added `SerializablePusPacket` as a generic abstraction for PUS packets which are
|
||||
writable.
|
||||
- Added new `PusTmZeroCopyWriter` class which allows to set fields on a raw TM packet,
|
||||
which might be more efficient that modification and re-writing a packet with the
|
||||
`PusTm` object.
|
||||
|
||||
## Changed
|
||||
|
||||
|
@ -598,12 +598,12 @@ mod tests {
|
||||
// No record boundary preservation
|
||||
assert_eq!((buf[3] >> 7) & 1, pdu_conf.seg_ctrl as u8);
|
||||
// Entity ID length raw value is actual number of octets - 1 => 0
|
||||
let entity_id_len = pdu_conf.pdu_conf.source_entity_id.len();
|
||||
let entity_id_len = pdu_conf.pdu_conf.source_entity_id.size();
|
||||
assert_eq!((buf[3] >> 4) & 0b111, entity_id_len as u8 - 1);
|
||||
// No segment metadata
|
||||
assert_eq!((buf[3] >> 3) & 0b1, pdu_conf.seg_metadata_flag as u8);
|
||||
// Transaction Sequence ID length raw value is actual number of octets - 1 => 0
|
||||
let seq_num_len = pdu_conf.pdu_conf.transaction_seq_num.len();
|
||||
let seq_num_len = pdu_conf.pdu_conf.transaction_seq_num.size();
|
||||
assert_eq!(buf[3] & 0b111, seq_num_len as u8 - 1);
|
||||
let mut current_idx = 4;
|
||||
let mut byte_field_check = |field_len: usize, ubf: &UnsignedByteField| {
|
||||
|
@ -257,16 +257,22 @@ pub(crate) fn user_data_from_raw(
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn verify_crc16_ccitt_false_from_raw(
|
||||
pub(crate) fn verify_crc16_ccitt_false_from_raw_to_pus_error(
|
||||
raw_data: &[u8],
|
||||
crc16: u16,
|
||||
) -> Result<(), PusError> {
|
||||
verify_crc16_ccitt_false_from_raw(raw_data)
|
||||
.then(|| ())
|
||||
.ok_or(PusError::IncorrectCrc(crc16))
|
||||
}
|
||||
|
||||
pub(crate) fn verify_crc16_ccitt_false_from_raw(raw_data: &[u8]) -> bool {
|
||||
let mut digest = CRC_CCITT_FALSE.digest();
|
||||
digest.update(raw_data);
|
||||
if digest.finalize() == 0 {
|
||||
return Ok(());
|
||||
return true;
|
||||
}
|
||||
Err(PusError::IncorrectCrc(crc16))
|
||||
false
|
||||
}
|
||||
|
||||
macro_rules! ccsds_impl {
|
||||
|
@ -33,7 +33,7 @@
|
||||
//! ```
|
||||
use crate::ecss::{
|
||||
ccsds_impl, crc_from_raw_data, crc_procedure, sp_header_impls, user_data_from_raw,
|
||||
verify_crc16_ccitt_false_from_raw, CrcType, PusError, PusPacket, PusVersion,
|
||||
verify_crc16_ccitt_false_from_raw_to_pus_error, CrcType, PusError, PusPacket, PusVersion,
|
||||
SerializablePusPacket,
|
||||
};
|
||||
use crate::{
|
||||
@ -394,7 +394,10 @@ impl<'raw_data> PusTc<'raw_data> {
|
||||
calc_crc_on_serialization: false,
|
||||
crc16: Some(crc_from_raw_data(raw_data)?),
|
||||
};
|
||||
verify_crc16_ccitt_false_from_raw(raw_data, pus_tc.crc16.expect("CRC16 invalid"))?;
|
||||
verify_crc16_ccitt_false_from_raw_to_pus_error(
|
||||
raw_data,
|
||||
pus_tc.crc16.expect("CRC16 invalid"),
|
||||
)?;
|
||||
Ok((pus_tc, total_len))
|
||||
}
|
||||
|
||||
@ -500,7 +503,7 @@ impl GenericPusTcSecondaryHeader for PusTc<'_> {
|
||||
#[cfg(all(test, feature = "std"))]
|
||||
mod tests {
|
||||
use crate::ecss::PusVersion::PusC;
|
||||
use crate::ecss::{PusError, PusPacket};
|
||||
use crate::ecss::{PusError, PusPacket, SerializablePusPacket};
|
||||
use crate::tc::ACK_ALL;
|
||||
use crate::tc::{GenericPusTcSecondaryHeader, PusTc, PusTcSecondaryHeader};
|
||||
use crate::{ByteConversionError, SpHeader};
|
||||
|
91
src/tm.rs
91
src/tm.rs
@ -1,13 +1,13 @@
|
||||
//! This module contains all components required to create a ECSS PUS C telemetry packets according
|
||||
//! to [ECSS-E-ST-70-41C](https://ecss.nl/standard/ecss-e-st-70-41c-space-engineering-telemetry-and-telecommand-packet-utilization-15-april-2016/).
|
||||
use crate::ecss::{
|
||||
ccsds_impl, crc_from_raw_data, crc_procedure, sp_header_impls, user_data_from_raw,
|
||||
verify_crc16_ccitt_false_from_raw, CrcType, PusError, PusPacket, PusVersion,
|
||||
SerializablePusPacket,
|
||||
calc_pus_crc16, ccsds_impl, crc_from_raw_data, crc_procedure, sp_header_impls,
|
||||
user_data_from_raw, verify_crc16_ccitt_false_from_raw_to_pus_error, CrcType, PusError,
|
||||
PusPacket, PusVersion, SerializablePusPacket,
|
||||
};
|
||||
use crate::{
|
||||
ByteConversionError, CcsdsPacket, PacketType, SequenceFlags, SizeMissmatch, SpHeader,
|
||||
CCSDS_HEADER_LEN, CRC_CCITT_FALSE,
|
||||
CCSDS_HEADER_LEN, CRC_CCITT_FALSE, MAX_SEQ_COUNT,
|
||||
};
|
||||
use core::mem::size_of;
|
||||
#[cfg(feature = "serde")]
|
||||
@ -388,7 +388,10 @@ impl<'raw_data> PusTm<'raw_data> {
|
||||
calc_crc_on_serialization: false,
|
||||
crc16: Some(crc_from_raw_data(raw_data)?),
|
||||
};
|
||||
verify_crc16_ccitt_false_from_raw(raw_data, pus_tm.crc16.expect("CRC16 invalid"))?;
|
||||
verify_crc16_ccitt_false_from_raw_to_pus_error(
|
||||
raw_data,
|
||||
pus_tm.crc16.expect("CRC16 invalid"),
|
||||
)?;
|
||||
Ok((pus_tm, total_len))
|
||||
}
|
||||
|
||||
@ -399,6 +402,62 @@ impl<'raw_data> PusTm<'raw_data> {
|
||||
}
|
||||
}
|
||||
|
||||
/// This is a helper class to update certain fields in a raw PUS telemetry packet directly in place.
|
||||
/// This can be more efficient than creating a full [PusTm], modifying the fields and then writing
|
||||
/// it back to another buffer.
|
||||
///
|
||||
/// Please note that the [Self::finish] method has to be called for the PUS TM CRC16 to be valid
|
||||
/// after changing fields of the TM packet. Furthermore, the constructor of this class will not
|
||||
/// do any checks except a length check to ensure that all relevant fields can be updated without
|
||||
/// a panic. If a full validity check of the PUS TM packet is required, it is recommended
|
||||
/// to construct a full [PusTm] object from the raw bytestream first.
|
||||
pub struct PusTmZeroCopyWriter<'raw> {
|
||||
raw_tm: &'raw mut [u8],
|
||||
}
|
||||
|
||||
impl<'raw> PusTmZeroCopyWriter<'raw> {
|
||||
/// This function will not do any other checks on the raw data other than a length check
|
||||
/// for all internal fields which can be updated. It is the responsibility of the user to ensure
|
||||
/// the raw slice contains a valid telemetry packet. The slice should have the exact length
|
||||
/// of the telemetry packet for this class to work properly.
|
||||
pub fn new(raw_tm: &'raw mut [u8]) -> Option<Self> {
|
||||
if raw_tm.len() < 13 {
|
||||
return None;
|
||||
}
|
||||
Some(Self { raw_tm })
|
||||
}
|
||||
|
||||
/// This function sets the message counter in the PUS TM secondary header.
|
||||
pub fn set_msg_count(&mut self, msg_count: u16) {
|
||||
self.raw_tm[9..11].copy_from_slice(&msg_count.to_be_bytes());
|
||||
}
|
||||
|
||||
/// This function sets the destination ID in the PUS TM secondary header.
|
||||
pub fn set_destination_id(&mut self, dest_id: u16) {
|
||||
self.raw_tm[11..13].copy_from_slice(&dest_id.to_be_bytes())
|
||||
}
|
||||
|
||||
/// Set the sequence count. Returns false and does not update the value if the passed value
|
||||
/// exceeds [MAX_SEQ_COUNT].
|
||||
pub fn set_seq_count_in_place(&mut self, seq_count: u16) -> bool {
|
||||
if seq_count > MAX_SEQ_COUNT {
|
||||
return false;
|
||||
}
|
||||
let new_psc =
|
||||
(u16::from_be_bytes(self.raw_tm[2..4].try_into().unwrap()) & 0xC000) | seq_count;
|
||||
self.raw_tm[2..4].copy_from_slice(&new_psc.to_be_bytes());
|
||||
true
|
||||
}
|
||||
|
||||
/// This method has to be called after modifying fields to ensure the CRC16 of the telemetry
|
||||
/// packet remains valid.
|
||||
pub fn finish(self) {
|
||||
let slice_len = self.raw_tm.len();
|
||||
let crc16 = calc_pus_crc16(&self.raw_tm[..slice_len - 2]);
|
||||
self.raw_tm[slice_len - 2..].copy_from_slice(&crc16.to_be_bytes());
|
||||
}
|
||||
}
|
||||
|
||||
impl SerializablePusPacket for PusTm<'_> {
|
||||
fn len_packed(&self) -> usize {
|
||||
let mut length = PUS_TM_MIN_LEN_WITHOUT_SOURCE_DATA;
|
||||
@ -714,4 +773,26 @@ mod tests {
|
||||
pus_tm.write_to_bytes(&mut buf).unwrap();
|
||||
assert_eq!(pus_tm, PusTm::from_bytes(&buf, timestamp.len()).unwrap().0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_zero_copy_writer() {
|
||||
let ping_tm = base_ping_reply_full_ctor(dummy_timestamp());
|
||||
let mut buf: [u8; 64] = [0; 64];
|
||||
let tm_size = ping_tm
|
||||
.write_to_bytes(&mut buf)
|
||||
.expect("writing PUS ping TM failed");
|
||||
let mut writer = PusTmZeroCopyWriter::new(&mut buf[..tm_size])
|
||||
.expect("Creating zero copy writer failed");
|
||||
writer.set_destination_id(55);
|
||||
writer.set_msg_count(100);
|
||||
writer.set_seq_count_in_place(MAX_SEQ_COUNT - 1);
|
||||
writer.finalize();
|
||||
// This performs all necessary checks, including the CRC check.
|
||||
let (tm_read_back, tm_size_read_back) =
|
||||
PusTm::from_bytes(&buf, 7).expect("Re-creating PUS TM failed");
|
||||
assert_eq!(tm_size_read_back, tm_size);
|
||||
assert_eq!(tm_read_back.msg_counter(), 100);
|
||||
assert_eq!(tm_read_back.dest_id(), 55);
|
||||
assert_eq!(tm_read_back.seq_count(), MAX_SEQ_COUNT - 1);
|
||||
}
|
||||
}
|
||||
|
16
src/util.rs
16
src/util.rs
@ -317,7 +317,7 @@ pub mod tests {
|
||||
#[test]
|
||||
fn test_simple_u8() {
|
||||
let u8 = UnsignedByteFieldU8::new(5);
|
||||
assert_eq!(u8.len(), 1);
|
||||
assert_eq!(u8.size(), 1);
|
||||
let mut buf: [u8; 8] = [0; 8];
|
||||
let len = u8
|
||||
.write_to_be_bytes(&mut buf)
|
||||
@ -332,7 +332,7 @@ pub mod tests {
|
||||
#[test]
|
||||
fn test_simple_u16() {
|
||||
let u16 = UnsignedByteFieldU16::new(3823);
|
||||
assert_eq!(u16.len(), 2);
|
||||
assert_eq!(u16.size(), 2);
|
||||
let mut buf: [u8; 8] = [0; 8];
|
||||
let len = u16
|
||||
.write_to_be_bytes(&mut buf)
|
||||
@ -348,7 +348,7 @@ pub mod tests {
|
||||
#[test]
|
||||
fn test_simple_u32() {
|
||||
let u32 = UnsignedByteFieldU32::new(80932);
|
||||
assert_eq!(u32.len(), 4);
|
||||
assert_eq!(u32.size(), 4);
|
||||
let mut buf: [u8; 8] = [0; 8];
|
||||
let len = u32
|
||||
.write_to_be_bytes(&mut buf)
|
||||
@ -364,7 +364,7 @@ pub mod tests {
|
||||
#[test]
|
||||
fn test_simple_u64() {
|
||||
let u64 = UnsignedByteFieldU64::new(5999999);
|
||||
assert_eq!(u64.len(), 8);
|
||||
assert_eq!(u64.size(), 8);
|
||||
let mut buf: [u8; 8] = [0; 8];
|
||||
let len = u64
|
||||
.write_to_be_bytes(&mut buf)
|
||||
@ -493,7 +493,7 @@ pub mod tests {
|
||||
#[test]
|
||||
fn type_erased_u8_write() {
|
||||
let u8 = UnsignedByteField::new(1, 5);
|
||||
assert_eq!(u8.len(), 1);
|
||||
assert_eq!(u8.size(), 1);
|
||||
let mut buf: [u8; 8] = [0; 8];
|
||||
u8.write_to_be_bytes(&mut buf)
|
||||
.expect("writing to raw buffer failed");
|
||||
@ -506,7 +506,7 @@ pub mod tests {
|
||||
#[test]
|
||||
fn type_erased_u16_write() {
|
||||
let u16 = UnsignedByteField::new(2, 3823);
|
||||
assert_eq!(u16.len(), 2);
|
||||
assert_eq!(u16.size(), 2);
|
||||
let mut buf: [u8; 8] = [0; 8];
|
||||
u16.write_to_be_bytes(&mut buf)
|
||||
.expect("writing to raw buffer failed");
|
||||
@ -520,7 +520,7 @@ pub mod tests {
|
||||
#[test]
|
||||
fn type_erased_u32_write() {
|
||||
let u32 = UnsignedByteField::new(4, 80932);
|
||||
assert_eq!(u32.len(), 4);
|
||||
assert_eq!(u32.size(), 4);
|
||||
let mut buf: [u8; 8] = [0; 8];
|
||||
u32.write_to_be_bytes(&mut buf)
|
||||
.expect("writing to raw buffer failed");
|
||||
@ -534,7 +534,7 @@ pub mod tests {
|
||||
#[test]
|
||||
fn type_erased_u64_write() {
|
||||
let u64 = UnsignedByteField::new(8, 5999999);
|
||||
assert_eq!(u64.len(), 8);
|
||||
assert_eq!(u64.size(), 8);
|
||||
let mut buf: [u8; 8] = [0; 8];
|
||||
u64.write_to_be_bytes(&mut buf)
|
||||
.expect("writing to raw buffer failed");
|
||||
|
Loading…
Reference in New Issue
Block a user