diff --git a/src/cfdp/mod.rs b/src/cfdp/mod.rs index 194d9a7..2704bb6 100644 --- a/src/cfdp/mod.rs +++ b/src/cfdp/mod.rs @@ -3,6 +3,7 @@ use num_enum::{IntoPrimitive, TryFromPrimitive}; use serde::{Deserialize, Serialize}; pub mod pdu; +pub mod tlv; pub const CFDP_VERSION_2_NAME: &str = "CCSDS 727.0-B-5"; pub const CFDP_VERSION_2: u8 = 0b001; diff --git a/src/cfdp/pdu/metadata.rs b/src/cfdp/pdu/metadata.rs new file mode 100644 index 0000000..2883478 --- /dev/null +++ b/src/cfdp/pdu/metadata.rs @@ -0,0 +1,15 @@ +use crate::cfdp::pdu::{FileDirectiveType, PduHeader}; +use crate::cfdp::ChecksumType; + +pub struct MetadataParams { + closure_requested: bool, + checksum_type: ChecksumType, + file_size: u64, + //src_file_name: +} + +pub struct MetadataPdu { + pdu_header: PduHeader, + file_directive: FileDirectiveType, + metadata_params: MetadataParams, +} diff --git a/src/cfdp/pdu/mod.rs b/src/cfdp/pdu/mod.rs index 4a4f40d..81bcc4a 100644 --- a/src/cfdp/pdu/mod.rs +++ b/src/cfdp/pdu/mod.rs @@ -5,6 +5,21 @@ use core::fmt::{Display, Formatter}; #[cfg(feature = "std")] use std::error::Error; +pub mod metadata; + +#[derive(Debug, Copy, Clone, PartialEq, Eq, TryFromPrimitive, IntoPrimitive)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +#[repr(u8)] +pub enum FileDirectiveType { + EofPdu = 0x04, + FinishedPdu = 0x05, + AckPdu = 0x06, + MetadataPdu = 0x07, + NakPdu = 0x08, + PromptPdu = 0x09, + KeepAlivePdu = 0x0c, +} + #[derive(Debug, Copy, Clone, PartialEq, Eq)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub enum PduError { @@ -148,7 +163,7 @@ impl CommonPduConfig { } } -const FIXED_HEADER_LEN: usize = 4; +pub const FIXED_HEADER_LEN: usize = 4; /// Abstraction for the PDU header common to all CFDP PDUs #[derive(Debug, Copy, Clone, PartialEq, Eq)] diff --git a/src/cfdp/tlv.rs b/src/cfdp/tlv.rs new file mode 100644 index 0000000..b23e938 --- /dev/null +++ b/src/cfdp/tlv.rs @@ -0,0 +1,86 @@ +use crate::{ByteConversionError, SizeMissmatch}; +use num_enum::{IntoPrimitive, TryFromPrimitive}; +#[cfg(feature = "serde")] +use serde::{Deserialize, Serialize}; + +pub const MIN_TLV_LEN: usize = 2; + +#[derive(Debug, Copy, Clone, PartialEq, Eq, TryFromPrimitive, IntoPrimitive)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +#[repr(u8)] +pub enum TlvType { + FilestoreRequest = 0x00, + FilestoreResponse = 0x01, + MsgToUser = 0x02, + FaultHandler = 0x04, + FlowLabel = 0x05, + EntityId = 0x06, +} + +pub struct Tlv<'a> { + tlv_type: TlvType, + data: &'a [u8], +} + +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +pub enum TlvError { + DataTooLarge(usize), + ByteConversionError(ByteConversionError), + UnknownTlvType(u8), +} + +impl From for TlvError { + fn from(value: ByteConversionError) -> Self { + Self::ByteConversionError(value) + } +} + +impl<'a> Tlv<'a> { + pub fn new(tlv_type: TlvType, data: &[u8]) -> Result { + if data.len() > u8::MAX as usize { + return Err(TlvError::DataTooLarge(data.len())); + } + Ok(Tlv { tlv_type, data }) + } + + pub fn write_to_be_bytes(&self, buf: &mut [u8]) -> Result { + if buf.len() < self.data.len() + MIN_TLV_LEN { + return Err(ByteConversionError::ToSliceTooSmall(SizeMissmatch { + found: buf.len(), + expected: self.data.len() + MIN_TLV_LEN, + })); + } + buf[0] = self.tlv_type as u8; + // Length check in constructor ensures the length always has a valid value. + buf[1] = self.data.len() as u8; + buf[MIN_TLV_LEN..self.data.len() + MIN_TLV_LEN].copy_from_slice(self.data); + Ok(MIN_TLV_LEN + self.data.len()) + } + + pub fn from_be_bytes(buf: &'a [u8]) -> Result, TlvError> { + if buf.len() < MIN_TLV_LEN { + return Err(ByteConversionError::FromSliceTooSmall(SizeMissmatch { + found: buf.len(), + expected: MIN_TLV_LEN, + }) + .into()); + } + let tlv_type_res = TlvType::try_from(buf[0]); + if tlv_type_res.is_err() { + return Err(TlvError::UnknownTlvType(buf[1])); + } + let value_len = buf[1] as usize; + if buf.len() < value_len { + return Err(ByteConversionError::FromSliceTooSmall(SizeMissmatch { + found: buf.len(), + expected: MIN_TLV_LEN + value_len, + }) + .into()); + } + Ok(Self { + tlv_type: tlv_type_res.unwrap(), + data: &buf[MIN_TLV_LEN..MIN_TLV_LEN + value_len], + }) + } +}