CFDP initial packet support #14
@ -1,8 +1,8 @@
|
||||
use crate::cfdp::lv::Lv;
|
||||
use crate::cfdp::pdu::{FileDirectiveType, PduError, PduHeader};
|
||||
use crate::cfdp::tlv::Tlv;
|
||||
use crate::cfdp::{ChecksumType, LargeFileFlag};
|
||||
use crate::{ByteConversionError, SizeMissmatch};
|
||||
use crate::cfdp::{ChecksumType, CrcFlag, LargeFileFlag};
|
||||
use crate::{ByteConversionError, SizeMissmatch, CRC_CCITT_FALSE};
|
||||
#[cfg(feature = "alloc")]
|
||||
use alloc::vec::Vec;
|
||||
#[cfg(feature = "serde")]
|
||||
@ -74,12 +74,25 @@ impl<'src_name, 'dest_name, 'opts> MetadataPdu<'src_name, 'dest_name, 'opts> {
|
||||
}
|
||||
|
||||
pub fn new_with_opts(
|
||||
pdu_header: PduHeader,
|
||||
mut pdu_header: PduHeader,
|
||||
metadata_params: MetadataGenericParams,
|
||||
src_file_name: Lv<'src_name>,
|
||||
dest_file_name: Lv<'dest_name>,
|
||||
options: Option<&'opts [u8]>,
|
||||
) -> Self {
|
||||
let is_large_file = pdu_header.common_pdu_conf().file_flag == LargeFileFlag::Large;
|
||||
let has_crc = pdu_header.common_pdu_conf().crc_flag == CrcFlag::WithCrc;
|
||||
pdu_header.pdu_datafield_len =
|
||||
2 + 4 + src_file_name.len_full() as u16 + dest_file_name.len_full() as u16;
|
||||
if is_large_file {
|
||||
pdu_header.pdu_datafield_len += 4;
|
||||
}
|
||||
if has_crc {
|
||||
pdu_header.pdu_datafield_len += 2;
|
||||
}
|
||||
if let Some(opts) = options {
|
||||
pdu_header.pdu_datafield_len += opts.len() as u16;
|
||||
}
|
||||
Self {
|
||||
pdu_header,
|
||||
metadata_params,
|
||||
@ -114,10 +127,17 @@ impl<'src_name, 'dest_name, 'opts> MetadataPdu<'src_name, 'dest_name, 'opts> {
|
||||
if let Some(opts) = self.options {
|
||||
len += opts.len();
|
||||
}
|
||||
if self.pdu_header.pdu_conf.crc_flag == CrcFlag::WithCrc {
|
||||
len += 2;
|
||||
}
|
||||
len
|
||||
}
|
||||
|
||||
pub fn write_to_be_bytes(&self, buf: &mut [u8]) -> Result<usize, PduError> {
|
||||
pub fn pdu_header(&self) -> &PduHeader {
|
||||
&self.pdu_header
|
||||
}
|
||||
|
||||
pub fn write_to_bytes(&self, buf: &mut [u8]) -> Result<usize, PduError> {
|
||||
let expected_len = self.written_len();
|
||||
if buf.len() < expected_len {
|
||||
return Err(ByteConversionError::ToSliceTooSmall(SizeMissmatch {
|
||||
@ -126,7 +146,8 @@ impl<'src_name, 'dest_name, 'opts> MetadataPdu<'src_name, 'dest_name, 'opts> {
|
||||
})
|
||||
.into());
|
||||
}
|
||||
let mut current_idx = self.pdu_header.write_to_be_bytes(buf)?;
|
||||
|
||||
let mut current_idx = self.pdu_header.write_to_bytes(buf)?;
|
||||
buf[current_idx] = FileDirectiveType::MetadataPdu as u8;
|
||||
current_idx += 1;
|
||||
buf[current_idx] = ((self.metadata_params.closure_requested as u8) << 7)
|
||||
@ -154,13 +175,19 @@ impl<'src_name, 'dest_name, 'opts> MetadataPdu<'src_name, 'dest_name, 'opts> {
|
||||
buf[current_idx..current_idx + opts.len()].copy_from_slice(opts);
|
||||
current_idx += opts.len();
|
||||
}
|
||||
if self.pdu_header.pdu_conf.crc_flag == CrcFlag::WithCrc {
|
||||
let mut digest = CRC_CCITT_FALSE.digest();
|
||||
digest.update(&buf[..current_idx]);
|
||||
buf[current_idx..current_idx + 2].copy_from_slice(&digest.finalize().to_be_bytes());
|
||||
current_idx += 2;
|
||||
}
|
||||
Ok(current_idx)
|
||||
}
|
||||
|
||||
pub fn from_be_bytes<'longest: 'src_name + 'dest_name + 'opts>(
|
||||
pub fn from_bytes<'longest: 'src_name + 'dest_name + 'opts>(
|
||||
buf: &'longest [u8],
|
||||
) -> Result<MetadataPdu<'src_name, 'dest_name, 'opts>, PduError> {
|
||||
let (pdu_header, mut current_idx) = PduHeader::from_be_bytes(buf)?;
|
||||
let (pdu_header, mut current_idx) = PduHeader::from_bytes(buf)?;
|
||||
let full_len_without_crc = pdu_header.verify_length_and_checksum(buf)?;
|
||||
let is_large_file = pdu_header.pdu_conf.file_flag == LargeFileFlag::Large;
|
||||
// Minimal length: 1 byte + FSS (4 byte) + 2 empty LV (1 byte)
|
||||
@ -272,14 +299,14 @@ pub mod tests {
|
||||
let metadata_pdu =
|
||||
MetadataPdu::new(pdu_header, metadata_params, src_filename, dest_filename);
|
||||
let mut buf: [u8; 64] = [0; 64];
|
||||
let res = metadata_pdu.write_to_be_bytes(&mut buf);
|
||||
let res = metadata_pdu.write_to_bytes(&mut buf);
|
||||
assert!(res.is_ok());
|
||||
let written = res.unwrap();
|
||||
assert_eq!(
|
||||
written,
|
||||
pdu_header.header_len() + 1 + 1 + 4 + src_len + dest_len
|
||||
);
|
||||
verify_raw_header(&pdu_header, &buf);
|
||||
verify_raw_header(metadata_pdu.pdu_header(), &buf);
|
||||
assert_eq!(buf[7], FileDirectiveType::MetadataPdu as u8);
|
||||
assert_eq!(buf[8] >> 6, false as u8);
|
||||
assert_eq!(buf[8] & 0b1111, ChecksumType::Crc32 as u8);
|
||||
|
@ -257,7 +257,7 @@ impl PduHeader {
|
||||
self.header_len() + self.pdu_datafield_len as usize
|
||||
}
|
||||
|
||||
pub fn write_to_be_bytes(&self, buf: &mut [u8]) -> Result<usize, PduError> {
|
||||
pub fn write_to_bytes(&self, buf: &mut [u8]) -> Result<usize, PduError> {
|
||||
// Internal note: There is currently no way to pass a PDU configuration like this, but
|
||||
// this check is still kept for defensive programming.
|
||||
if self.pdu_conf.source_entity_id.len() != self.pdu_conf.dest_entity_id.len() {
|
||||
@ -340,7 +340,7 @@ impl PduHeader {
|
||||
/// to hold the full PDU.
|
||||
///
|
||||
/// Both functions can however be performed with the [verify_length_and_checksum] function.
|
||||
pub fn from_be_bytes(buf: &[u8]) -> Result<(Self, usize), PduError> {
|
||||
pub fn from_bytes(buf: &[u8]) -> Result<(Self, usize), PduError> {
|
||||
if buf.len() < FIXED_HEADER_LEN {
|
||||
return Err(PduError::ByteConversionError(
|
||||
ByteConversionError::FromSliceTooSmall(SizeMissmatch {
|
||||
@ -546,7 +546,7 @@ mod tests {
|
||||
.expect("common config creation failed");
|
||||
let pdu_header = PduHeader::new_no_file_data(common_pdu_cfg, 5);
|
||||
let mut buf: [u8; 7] = [0; 7];
|
||||
let res = pdu_header.write_to_be_bytes(&mut buf);
|
||||
let res = pdu_header.write_to_bytes(&mut buf);
|
||||
assert!(res.is_ok());
|
||||
// 4 byte fixed header plus three bytes src, dest ID and transaction ID
|
||||
assert_eq!(res.unwrap(), 7);
|
||||
@ -562,9 +562,9 @@ mod tests {
|
||||
.expect("common config creation failed");
|
||||
let pdu_header = PduHeader::new_no_file_data(common_pdu_cfg, 5);
|
||||
let mut buf: [u8; 7] = [0; 7];
|
||||
let res = pdu_header.write_to_be_bytes(&mut buf);
|
||||
let res = pdu_header.write_to_bytes(&mut buf);
|
||||
assert!(res.is_ok());
|
||||
let deser_res = PduHeader::from_be_bytes(&buf);
|
||||
let deser_res = PduHeader::from_bytes(&buf);
|
||||
assert!(deser_res.is_ok());
|
||||
let (header_read_back, read_size) = deser_res.unwrap();
|
||||
assert_eq!(read_size, 7);
|
||||
@ -591,7 +591,7 @@ mod tests {
|
||||
);
|
||||
assert_eq!(pdu_header.header_len(), 10);
|
||||
let mut buf: [u8; 16] = [0; 16];
|
||||
let res = pdu_header.write_to_be_bytes(&mut buf);
|
||||
let res = pdu_header.write_to_bytes(&mut buf);
|
||||
assert!(res.is_ok(), "{}", format!("Result {res:?} not okay"));
|
||||
// 4 byte fixed header, 6 bytes additional fields
|
||||
assert_eq!(res.unwrap(), 10);
|
||||
@ -617,9 +617,9 @@ mod tests {
|
||||
SegmentationControl::WithRecordBoundaryPreservation,
|
||||
);
|
||||
let mut buf: [u8; 16] = [0; 16];
|
||||
let res = pdu_header.write_to_be_bytes(&mut buf);
|
||||
let res = pdu_header.write_to_bytes(&mut buf);
|
||||
assert!(res.is_ok());
|
||||
let deser_res = PduHeader::from_be_bytes(&buf);
|
||||
let deser_res = PduHeader::from_bytes(&buf);
|
||||
assert!(deser_res.is_ok());
|
||||
let (header_read_back, read_size) = deser_res.unwrap();
|
||||
assert_eq!(read_size, 10);
|
||||
@ -635,11 +635,11 @@ mod tests {
|
||||
.expect("common config creation failed");
|
||||
let pdu_header = PduHeader::new_no_file_data(common_pdu_cfg, 5);
|
||||
let mut buf: [u8; 7] = [0; 7];
|
||||
let res = pdu_header.write_to_be_bytes(&mut buf);
|
||||
let res = pdu_header.write_to_bytes(&mut buf);
|
||||
assert!(res.is_ok());
|
||||
buf[0] &= !0b1110_0000;
|
||||
buf[0] |= (CFDP_VERSION_2 + 1) << 5;
|
||||
let res = PduHeader::from_be_bytes(&buf);
|
||||
let res = PduHeader::from_bytes(&buf);
|
||||
assert!(res.is_err());
|
||||
let error = res.unwrap_err();
|
||||
if let PduError::CfdpVersionMissmatch(raw_version) = error {
|
||||
@ -652,7 +652,7 @@ mod tests {
|
||||
#[test]
|
||||
fn test_buf_too_small_1() {
|
||||
let buf: [u8; 3] = [0; 3];
|
||||
let res = PduHeader::from_be_bytes(&buf);
|
||||
let res = PduHeader::from_bytes(&buf);
|
||||
assert!(res.is_err());
|
||||
let error = res.unwrap_err();
|
||||
if let PduError::ByteConversionError(ByteConversionError::FromSliceTooSmall(missmatch)) =
|
||||
@ -674,9 +674,9 @@ mod tests {
|
||||
.expect("common config creation failed");
|
||||
let pdu_header = PduHeader::new_no_file_data(common_pdu_cfg, 5);
|
||||
let mut buf: [u8; 7] = [0; 7];
|
||||
let res = pdu_header.write_to_be_bytes(&mut buf);
|
||||
let res = pdu_header.write_to_bytes(&mut buf);
|
||||
assert!(res.is_ok());
|
||||
let header = PduHeader::from_be_bytes(&buf[0..6]);
|
||||
let header = PduHeader::from_bytes(&buf[0..6]);
|
||||
assert!(header.is_err());
|
||||
let error = header.unwrap_err();
|
||||
if let PduError::ByteConversionError(ByteConversionError::FromSliceTooSmall(missmatch)) =
|
||||
@ -737,12 +737,12 @@ mod tests {
|
||||
.expect("common config creation failed");
|
||||
let pdu_header = PduHeader::new_no_file_data(common_pdu_cfg, 5);
|
||||
let mut buf: [u8; 7] = [0; 7];
|
||||
let res = pdu_header.write_to_be_bytes(&mut buf);
|
||||
let res = pdu_header.write_to_bytes(&mut buf);
|
||||
assert!(res.is_ok());
|
||||
buf[3] &= !0b0111_0000;
|
||||
// Equivalent to the length of three
|
||||
buf[3] |= 0b10 << 4;
|
||||
let header_res = PduHeader::from_be_bytes(&buf);
|
||||
let header_res = PduHeader::from_bytes(&buf);
|
||||
assert!(header_res.is_err());
|
||||
let error = header_res.unwrap_err();
|
||||
if let PduError::InvalidEntityLen(len) = error {
|
||||
@ -761,12 +761,12 @@ mod tests {
|
||||
.expect("common config creation failed");
|
||||
let pdu_header = PduHeader::new_no_file_data(common_pdu_cfg, 5);
|
||||
let mut buf: [u8; 7] = [0; 7];
|
||||
let res = pdu_header.write_to_be_bytes(&mut buf);
|
||||
let res = pdu_header.write_to_bytes(&mut buf);
|
||||
assert!(res.is_ok());
|
||||
buf[3] &= !0b0000_0111;
|
||||
// Equivalent to the length of three
|
||||
buf[3] |= 0b10;
|
||||
let header_res = PduHeader::from_be_bytes(&buf);
|
||||
let header_res = PduHeader::from_bytes(&buf);
|
||||
assert!(header_res.is_err());
|
||||
let error = header_res.unwrap_err();
|
||||
if let PduError::InvalidTransactionSeqNumLen(len) = error {
|
||||
|
Loading…
Reference in New Issue
Block a user