use crate::{CcsdsPacket, PacketError}; use core::mem::size_of; use crc::{Crc, CRC_16_IBM_3740}; use serde::{Deserialize, Serialize}; pub type CrcType = u16; /// CRC algorithm used by the PUS standard pub const CRC_CCITT_FALSE: Crc = Crc::::new(&CRC_16_IBM_3740); pub const CCSDS_HEADER_LEN: usize = size_of::(); /// All PUS versions. Only PUS C is supported by this library #[derive(PartialEq, Copy, Clone, Serialize, Deserialize, Debug)] pub enum PusVersion { EsaPus = 0, PusA = 1, PusC = 2, Invalid = 0b1111, } impl TryFrom for PusVersion { type Error = (); fn try_from(value: u8) -> Result { match value { x if x == PusVersion::EsaPus as u8 => Ok(PusVersion::EsaPus), x if x == PusVersion::PusA as u8 => Ok(PusVersion::PusA), x if x == PusVersion::PusC as u8 => Ok(PusVersion::PusC), _ => Err(()), } } } #[derive(Debug, Copy, Clone, PartialEq)] pub enum PusError { VersionNotSupported(PusVersion), IncorrectCrc(u16), RawDataTooShort(usize), NoRawData, /// CRC16 needs to be calculated first CrcCalculationMissing, OtherPacketError(PacketError), } pub trait PusPacket: CcsdsPacket { const PUS_VERSION: PusVersion = PusVersion::PusC; fn pus_version(&self) -> PusVersion; fn service(&self) -> u8; fn subservice(&self) -> u8; fn user_data(&self) -> Option<&[u8]>; fn crc16(&self) -> Option; } pub(crate) fn crc_from_raw_data(raw_data: Option<&[u8]>) -> Result { if let Some(raw_data) = raw_data { if raw_data.len() < 2 { return Err(PusError::RawDataTooShort(raw_data.len())); } return Ok(u16::from_be_bytes( raw_data[raw_data.len() - 2..raw_data.len()] .try_into() .unwrap(), )); } Err(PusError::NoRawData) } pub(crate) fn calc_pus_crc16(bytes: &[u8]) -> u16 { let mut digest = CRC_CCITT_FALSE.digest(); digest.update(bytes); digest.finalize() } pub(crate) fn crc_procedure( calc_on_serialization: bool, cached_crc16: &Option, curr_idx: usize, slice: &[u8], ) -> Result { let crc16; if calc_on_serialization { crc16 = calc_pus_crc16(&slice[0..curr_idx]) } else if cached_crc16.is_none() { return Err(PusError::CrcCalculationMissing); } else { crc16 = cached_crc16.unwrap(); } Ok(crc16) }