added distinction between CCSDS packet and user data #191
@@ -8,6 +8,10 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
|
|||||||
|
|
||||||
# [unreleased]
|
# [unreleased]
|
||||||
|
|
||||||
|
## Changed
|
||||||
|
|
||||||
|
- Added distinction between `CcsdsPacketReader::user_data` and `CcsdsPacketReader::packet_data`.
|
||||||
|
|
||||||
# [v0.17.0] 2025-11-06
|
# [v0.17.0] 2025-11-06
|
||||||
|
|
||||||
## Changed
|
## Changed
|
||||||
|
|||||||
65
src/lib.rs
65
src/lib.rs
@@ -1528,12 +1528,19 @@ pub enum CcsdsPacketReadError {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// CCSDS packet reader structure.
|
/// CCSDS packet reader structure.
|
||||||
|
///
|
||||||
|
/// This implementation makes one assumption about the passed data: It allows verifying a
|
||||||
|
/// CRC16-CCITT checksum at the last two bytes of the packet data field and excluding it from the
|
||||||
|
/// [Self::packet_data] slice. For that purpose, it makes a distinction between the full
|
||||||
|
/// [Self::packet_data] including the checksum, and [Self::user_data] which does not include
|
||||||
|
/// the checksum.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||||
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||||
pub struct CcsdsPacketReader<'buf> {
|
pub struct CcsdsPacketReader<'buf> {
|
||||||
sp_header: SpHeader,
|
sp_header: SpHeader,
|
||||||
packet_data: &'buf [u8],
|
packet_data: &'buf [u8],
|
||||||
|
checksum: Option<u16>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'buf> CcsdsPacketReader<'buf> {
|
impl<'buf> CcsdsPacketReader<'buf> {
|
||||||
@@ -1550,7 +1557,7 @@ impl<'buf> CcsdsPacketReader<'buf> {
|
|||||||
/// Generic constructor.
|
/// Generic constructor.
|
||||||
pub fn new(
|
pub fn new(
|
||||||
buf: &'buf [u8],
|
buf: &'buf [u8],
|
||||||
checksum: Option<ChecksumType>,
|
checksum_type: Option<ChecksumType>,
|
||||||
) -> Result<Self, CcsdsPacketReadError> {
|
) -> Result<Self, CcsdsPacketReadError> {
|
||||||
let sp_header = SpHeader::from_be_bytes(&buf[0..CCSDS_HEADER_LEN])?.0;
|
let sp_header = SpHeader::from_be_bytes(&buf[0..CCSDS_HEADER_LEN])?.0;
|
||||||
if sp_header.packet_len() > buf.len() {
|
if sp_header.packet_len() > buf.len() {
|
||||||
@@ -1560,21 +1567,26 @@ impl<'buf> CcsdsPacketReader<'buf> {
|
|||||||
}
|
}
|
||||||
.into());
|
.into());
|
||||||
}
|
}
|
||||||
let user_data = match checksum {
|
let checksum = match checksum_type {
|
||||||
Some(ChecksumType::WithCrc16) => {
|
Some(ChecksumType::WithCrc16) => {
|
||||||
if CRC_CCITT_FALSE.checksum(&buf[0..sp_header.packet_len()]) != 0 {
|
if CRC_CCITT_FALSE.checksum(&buf[0..sp_header.packet_len()]) != 0 {
|
||||||
return Err(CcsdsPacketReadError::CrcError);
|
return Err(CcsdsPacketReadError::CrcError);
|
||||||
}
|
}
|
||||||
&buf[CCSDS_HEADER_LEN..sp_header.packet_len() - 2]
|
Some(u16::from_be_bytes([
|
||||||
|
buf[sp_header.packet_len() - 2],
|
||||||
|
buf[sp_header.packet_len() - 1],
|
||||||
|
]))
|
||||||
}
|
}
|
||||||
Some(ChecksumType::WithCrc16ButIgnored) => {
|
Some(ChecksumType::WithCrc16ButIgnored) => Some(u16::from_be_bytes([
|
||||||
&buf[CCSDS_HEADER_LEN..sp_header.packet_len() - 2]
|
buf[sp_header.packet_len() - 2],
|
||||||
}
|
buf[sp_header.packet_len() - 1],
|
||||||
None => &buf[CCSDS_HEADER_LEN..sp_header.packet_len()],
|
])),
|
||||||
|
None => None,
|
||||||
};
|
};
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
sp_header,
|
sp_header,
|
||||||
packet_data: user_data,
|
packet_data: &buf[CCSDS_HEADER_LEN..sp_header.packet_len()],
|
||||||
|
checksum,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1598,12 +1610,27 @@ impl CcsdsPacketReader<'_> {
|
|||||||
self.sp_header.packet_id.packet_type
|
self.sp_header.packet_id.packet_type
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Read-only access to the packet data field.
|
/// Read-only access to the full packet data field.
|
||||||
|
///
|
||||||
|
/// This might also include the checksum. [Self::user_data] can be used to only retrieve the
|
||||||
|
/// user data slice without the checksum part.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn packet_data(&self) -> &[u8] {
|
pub fn packet_data(&self) -> &[u8] {
|
||||||
self.packet_data
|
self.packet_data
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Read-only access to the user data field.
|
||||||
|
///
|
||||||
|
/// This is the data without the checksum, if the packet has one.
|
||||||
|
#[inline]
|
||||||
|
pub fn user_data(&self) -> &[u8] {
|
||||||
|
if self.checksum.is_some() {
|
||||||
|
self.packet_data()[0..self.packet_data().len() - 2].as_ref()
|
||||||
|
} else {
|
||||||
|
self.packet_data()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// 11-bit Application Process ID field.
|
/// 11-bit Application Process ID field.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn apid(&self) -> u11 {
|
pub fn apid(&self) -> u11 {
|
||||||
@@ -1633,6 +1660,12 @@ impl CcsdsPacketReader<'_> {
|
|||||||
pub fn data_len(&self) -> u16 {
|
pub fn data_len(&self) -> u16 {
|
||||||
self.sp_header.data_len()
|
self.sp_header.data_len()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Packet checksum if available.
|
||||||
|
#[inline]
|
||||||
|
pub fn checksum(&self) -> Option<u16> {
|
||||||
|
self.checksum
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CcsdsPacket for CcsdsPacketReader<'_> {
|
impl CcsdsPacket for CcsdsPacketReader<'_> {
|
||||||
@@ -2211,7 +2244,7 @@ pub(crate) mod tests {
|
|||||||
let reader =
|
let reader =
|
||||||
CcsdsPacketReader::new(&buf[0..13], Some(ChecksumType::WithCrc16ButIgnored)).unwrap();
|
CcsdsPacketReader::new(&buf[0..13], Some(ChecksumType::WithCrc16ButIgnored)).unwrap();
|
||||||
// Enforced 1 byte packet length.
|
// Enforced 1 byte packet length.
|
||||||
assert_eq!(reader.packet_data(), &data);
|
assert_eq!(reader.user_data(), &data);
|
||||||
assert_eq!(reader.packet_len(), 13);
|
assert_eq!(reader.packet_len(), 13);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2415,7 +2448,7 @@ pub(crate) mod tests {
|
|||||||
.to_vec();
|
.to_vec();
|
||||||
let reader =
|
let reader =
|
||||||
CcsdsPacketReader::new(&packet_raw, Some(ChecksumType::WithCrc16ButIgnored)).unwrap();
|
CcsdsPacketReader::new(&packet_raw, Some(ChecksumType::WithCrc16ButIgnored)).unwrap();
|
||||||
assert_eq!(reader.packet_data(), data);
|
assert_eq!(reader.user_data(), data);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn generic_test_creator(packet_raw: &[u8], sp_header: &SpHeader, packet_type: PacketType) {
|
fn generic_test_creator(packet_raw: &[u8], sp_header: &SpHeader, packet_type: PacketType) {
|
||||||
@@ -2482,7 +2515,7 @@ pub(crate) mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn generic_ccsds_reader_test(
|
fn generic_ccsds_reader_test(
|
||||||
packet_data: &[u8],
|
user_data: &[u8],
|
||||||
packet_raw: &[u8],
|
packet_raw: &[u8],
|
||||||
packet_type: PacketType,
|
packet_type: PacketType,
|
||||||
sp_header: SpHeader,
|
sp_header: SpHeader,
|
||||||
@@ -2493,7 +2526,11 @@ pub(crate) mod tests {
|
|||||||
);
|
);
|
||||||
let reader = CcsdsPacketReader::new_with_checksum(packet_raw).unwrap();
|
let reader = CcsdsPacketReader::new_with_checksum(packet_raw).unwrap();
|
||||||
assert_eq!(*reader.sp_header(), sp_header);
|
assert_eq!(*reader.sp_header(), sp_header);
|
||||||
assert_eq!(reader.packet_data(), packet_data);
|
assert_eq!(
|
||||||
|
&reader.packet_data()[0..reader.packet_data().len() - 2],
|
||||||
|
user_data
|
||||||
|
);
|
||||||
|
assert_eq!(reader.user_data(), user_data);
|
||||||
assert_eq!(reader.apid(), u11::new(0x1));
|
assert_eq!(reader.apid(), u11::new(0x1));
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
reader.packet_id(),
|
reader.packet_id(),
|
||||||
@@ -2704,7 +2741,7 @@ pub(crate) mod tests {
|
|||||||
*packet_raw.last_mut().unwrap() = 0;
|
*packet_raw.last_mut().unwrap() = 0;
|
||||||
let reader =
|
let reader =
|
||||||
CcsdsPacketReader::new(&packet_raw, Some(ChecksumType::WithCrc16ButIgnored)).unwrap();
|
CcsdsPacketReader::new(&packet_raw, Some(ChecksumType::WithCrc16ButIgnored)).unwrap();
|
||||||
assert_eq!(reader.packet_data(), data);
|
assert_eq!(reader.user_data(), data);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|||||||
Reference in New Issue
Block a user