CFDP initial packet support #14
@ -1,3 +1,4 @@
|
|||||||
|
//! Generic CFDP length-value (LV) abstraction as specified in CFDP 5.1.8.
|
||||||
use crate::cfdp::TlvLvError;
|
use crate::cfdp::TlvLvError;
|
||||||
use crate::{ByteConversionError, SizeMissmatch};
|
use crate::{ByteConversionError, SizeMissmatch};
|
||||||
#[cfg(feature = "serde")]
|
#[cfg(feature = "serde")]
|
||||||
@ -8,12 +9,10 @@ use std::string::String;
|
|||||||
pub const MIN_LV_LEN: usize = 1;
|
pub const MIN_LV_LEN: usize = 1;
|
||||||
|
|
||||||
/// Generic CFDP length-value (LV) abstraction as specified in CFDP 5.1.8.
|
/// Generic CFDP length-value (LV) abstraction as specified in CFDP 5.1.8.
|
||||||
///
|
|
||||||
/// This is just a thin wrapper around a raw slice which performs some additional error handling.
|
|
||||||
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
||||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||||
pub struct Lv<'a> {
|
pub struct Lv<'value> {
|
||||||
data: Option<&'a [u8]>,
|
data: Option<&'value [u8]>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn generic_len_check_data_serialization(
|
pub(crate) fn generic_len_check_data_serialization(
|
||||||
@ -43,7 +42,7 @@ pub(crate) fn generic_len_check_deserialization(
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Lv<'a> {
|
impl<'value> Lv<'value> {
|
||||||
pub fn new(data: &[u8]) -> Result<Lv, TlvLvError> {
|
pub fn new(data: &[u8]) -> Result<Lv, TlvLvError> {
|
||||||
if data.len() > u8::MAX as usize {
|
if data.len() > u8::MAX as usize {
|
||||||
return Err(TlvLvError::DataTooLarge(data.len()));
|
return Err(TlvLvError::DataTooLarge(data.len()));
|
||||||
@ -52,7 +51,7 @@ impl<'a> Lv<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a LV with an empty value field.
|
/// Creates a LV with an empty value field.
|
||||||
pub fn new_empty() -> Lv<'a> {
|
pub fn new_empty() -> Lv<'value> {
|
||||||
Lv { data: None }
|
Lv { data: None }
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -65,7 +64,7 @@ impl<'a> Lv<'a> {
|
|||||||
/// Helper function to build a string LV. This is especially useful for the file or directory
|
/// Helper function to build a string LV. This is especially useful for the file or directory
|
||||||
/// path LVs
|
/// path LVs
|
||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
pub fn new_from_string(string: &'a String) -> Result<Lv<'a>, TlvLvError> {
|
pub fn new_from_string(string: &'value String) -> Result<Lv<'value>, TlvLvError> {
|
||||||
Self::new(string.as_bytes())
|
Self::new(string.as_bytes())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -99,7 +98,7 @@ impl<'a> Lv<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Reads a LV from a raw buffer.
|
/// Reads a LV from a raw buffer.
|
||||||
pub fn from_be_bytes(buf: &'a [u8]) -> Result<Lv<'a>, TlvLvError> {
|
pub fn from_be_bytes(buf: &'value [u8]) -> Result<Lv<'value>, ByteConversionError> {
|
||||||
generic_len_check_deserialization(buf, MIN_LV_LEN)?;
|
generic_len_check_deserialization(buf, MIN_LV_LEN)?;
|
||||||
Self::from_be_bytes_no_len_check(buf)
|
Self::from_be_bytes_no_len_check(buf)
|
||||||
}
|
}
|
||||||
@ -116,7 +115,9 @@ impl<'a> Lv<'a> {
|
|||||||
MIN_LV_LEN + data.len()
|
MIN_LV_LEN + data.len()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn from_be_bytes_no_len_check(buf: &'a [u8]) -> Result<Lv<'a>, TlvLvError> {
|
pub(crate) fn from_be_bytes_no_len_check(
|
||||||
|
buf: &'value [u8],
|
||||||
|
) -> Result<Lv<'value>, ByteConversionError> {
|
||||||
let value_len = buf[0] as usize;
|
let value_len = buf[0] as usize;
|
||||||
generic_len_check_deserialization(buf, value_len + MIN_LV_LEN)?;
|
generic_len_check_deserialization(buf, value_len + MIN_LV_LEN)?;
|
||||||
let mut data = None;
|
let mut data = None;
|
||||||
@ -131,6 +132,8 @@ impl<'a> Lv<'a> {
|
|||||||
pub mod tests {
|
pub mod tests {
|
||||||
use crate::cfdp::lv::Lv;
|
use crate::cfdp::lv::Lv;
|
||||||
use crate::cfdp::TlvLvError;
|
use crate::cfdp::TlvLvError;
|
||||||
|
use crate::ByteConversionError;
|
||||||
|
use std::string::String;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_basic() {
|
fn test_basic() {
|
||||||
@ -226,4 +229,67 @@ pub mod tests {
|
|||||||
panic!("invalid exception {:?}", error)
|
panic!("invalid exception {:?}", error)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_serialization_buf_too_small() {
|
||||||
|
let mut buf: [u8; 3] = [0; 3];
|
||||||
|
let lv_data: [u8; 4] = [1, 2, 3, 4];
|
||||||
|
let lv = Lv::new(&lv_data).unwrap();
|
||||||
|
let res = lv.write_to_be_bytes(&mut buf);
|
||||||
|
assert!(res.is_err());
|
||||||
|
let error = res.unwrap_err();
|
||||||
|
if let ByteConversionError::ToSliceTooSmall(missmatch) = error {
|
||||||
|
assert_eq!(missmatch.expected, 5);
|
||||||
|
assert_eq!(missmatch.found, 3);
|
||||||
|
} else {
|
||||||
|
panic!("invalid error {}", error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_deserialization_buf_too_small() {
|
||||||
|
let mut buf: [u8; 3] = [0; 3];
|
||||||
|
buf[0] = 4;
|
||||||
|
let res = Lv::from_be_bytes(&buf);
|
||||||
|
assert!(res.is_err());
|
||||||
|
let error = res.unwrap_err();
|
||||||
|
if let ByteConversionError::FromSliceTooSmall(missmatch) = error {
|
||||||
|
assert_eq!(missmatch.found, 3);
|
||||||
|
assert_eq!(missmatch.expected, 5);
|
||||||
|
} else {
|
||||||
|
panic!("invalid error {}", error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn verify_test_str_lv(lv: Lv) {
|
||||||
|
let mut buf: [u8; 16] = [0; 16];
|
||||||
|
let res = lv.write_to_be_bytes(&mut buf);
|
||||||
|
assert!(res.is_ok());
|
||||||
|
let res = res.unwrap();
|
||||||
|
assert_eq!(res, 8 + 1);
|
||||||
|
assert_eq!(buf[0], 8);
|
||||||
|
assert_eq!(buf[1], 't' as u8);
|
||||||
|
assert_eq!(buf[2], 'e' as u8);
|
||||||
|
assert_eq!(buf[3], 's' as u8);
|
||||||
|
assert_eq!(buf[4], 't' as u8);
|
||||||
|
assert_eq!(buf[5], '.' as u8);
|
||||||
|
assert_eq!(buf[6], 'b' as u8);
|
||||||
|
assert_eq!(buf[7], 'i' as u8);
|
||||||
|
assert_eq!(buf[8], 'n' as u8);
|
||||||
|
}
|
||||||
|
#[test]
|
||||||
|
fn test_str_helper() {
|
||||||
|
let test_str = "test.bin";
|
||||||
|
let str_lv = Lv::new_from_str(test_str);
|
||||||
|
assert!(str_lv.is_ok());
|
||||||
|
verify_test_str_lv(str_lv.unwrap());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_string_helper() {
|
||||||
|
let string = String::from("test.bin");
|
||||||
|
let str_lv = Lv::new_from_string(&string);
|
||||||
|
assert!(str_lv.is_ok());
|
||||||
|
verify_test_str_lv(str_lv.unwrap());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,7 +10,9 @@ pub mod lv;
|
|||||||
pub mod pdu;
|
pub mod pdu;
|
||||||
pub mod tlv;
|
pub mod tlv;
|
||||||
|
|
||||||
|
/// This is the name of the standard this module is based on.
|
||||||
pub const CFDP_VERSION_2_NAME: &str = "CCSDS 727.0-B-5";
|
pub const CFDP_VERSION_2_NAME: &str = "CCSDS 727.0-B-5";
|
||||||
|
/// Currently, only this version is supported.
|
||||||
pub const CFDP_VERSION_2: u8 = 0b001;
|
pub const CFDP_VERSION_2: u8 = 0b001;
|
||||||
|
|
||||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, TryFromPrimitive, IntoPrimitive)]
|
#[derive(Debug, Copy, Clone, PartialEq, Eq, TryFromPrimitive, IntoPrimitive)]
|
||||||
@ -116,8 +118,8 @@ pub enum LargeFileFlag {
|
|||||||
Large = 1,
|
Large = 1,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Checksum types according to the SANA Checksum Types registry
|
/// Checksum types according to the
|
||||||
/// https://sanaregistry.org/r/checksum_identifiers/
|
/// [SANA Checksum Types registry](https://sanaregistry.org/r/checksum_identifiers/)
|
||||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, TryFromPrimitive, IntoPrimitive)]
|
#[derive(Debug, Copy, Clone, PartialEq, Eq, TryFromPrimitive, IntoPrimitive)]
|
||||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||||
#[repr(u8)]
|
#[repr(u8)]
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
//! CFDP Packet Data Unit (PDU) support.
|
||||||
use crate::cfdp::*;
|
use crate::cfdp::*;
|
||||||
use crate::util::{UnsignedByteField, UnsignedEnum};
|
use crate::util::{UnsignedByteField, UnsignedEnum};
|
||||||
use crate::{ByteConversionError, SizeMissmatch};
|
use crate::{ByteConversionError, SizeMissmatch};
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
//! Generic CFDP type-length-value (TLV) abstraction as specified in CFDP 5.1.9.
|
||||||
use crate::cfdp::lv::{
|
use crate::cfdp::lv::{
|
||||||
generic_len_check_data_serialization, generic_len_check_deserialization, Lv, MIN_LV_LEN,
|
generic_len_check_data_serialization, generic_len_check_deserialization, Lv, MIN_LV_LEN,
|
||||||
};
|
};
|
||||||
@ -22,8 +23,6 @@ pub enum TlvType {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Generic CFDP type-length-value (TLV) abstraction as specified in CFDP 5.1.9.
|
/// Generic CFDP type-length-value (TLV) abstraction as specified in CFDP 5.1.9.
|
||||||
///
|
|
||||||
/// This is just a thin wrapper around a length-value (LV) object, which add the [TlvType].
|
|
||||||
pub struct Tlv<'a> {
|
pub struct Tlv<'a> {
|
||||||
tlv_type: TlvType,
|
tlv_type: TlvType,
|
||||||
lv: Lv<'a>,
|
lv: Lv<'a>,
|
||||||
@ -86,3 +85,9 @@ impl<'a> Tlv<'a> {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
#[test]
|
||||||
|
fn test_basic() {}
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user