2023-05-18 15:01:08 +02:00
|
|
|
use crate::cfdp::lv::{
|
|
|
|
generic_len_check_data_serialization, generic_len_check_deserialization, Lv, MIN_LV_LEN,
|
|
|
|
};
|
|
|
|
use crate::cfdp::TlvLvError;
|
|
|
|
use crate::ByteConversionError;
|
2023-05-18 14:05:51 +02:00
|
|
|
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,
|
|
|
|
}
|
|
|
|
|
2023-05-18 20:37:41 +02:00
|
|
|
/// 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].
|
2023-05-18 14:05:51 +02:00
|
|
|
pub struct Tlv<'a> {
|
|
|
|
tlv_type: TlvType,
|
2023-05-18 15:01:08 +02:00
|
|
|
lv: Lv<'a>,
|
2023-05-18 14:05:51 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
impl<'a> Tlv<'a> {
|
2023-05-18 15:01:08 +02:00
|
|
|
pub fn new(tlv_type: TlvType, data: &[u8]) -> Result<Tlv, TlvLvError> {
|
2023-05-18 14:05:51 +02:00
|
|
|
if data.len() > u8::MAX as usize {
|
2023-05-18 15:01:08 +02:00
|
|
|
return Err(TlvLvError::DataTooLarge(data.len()));
|
2023-05-18 14:05:51 +02:00
|
|
|
}
|
2023-05-18 15:01:08 +02:00
|
|
|
Ok(Tlv {
|
|
|
|
tlv_type,
|
|
|
|
lv: Lv::new(data)?,
|
|
|
|
})
|
2023-05-18 14:05:51 +02:00
|
|
|
}
|
|
|
|
|
2023-05-18 20:37:41 +02:00
|
|
|
/// Creates a TLV with an empty value field.
|
|
|
|
pub fn new_empty(tlv_type: TlvType) -> Tlv<'a> {
|
|
|
|
Tlv {
|
|
|
|
tlv_type,
|
|
|
|
lv: Lv::new_empty(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-05-18 14:05:51 +02:00
|
|
|
pub fn write_to_be_bytes(&self, buf: &mut [u8]) -> Result<usize, ByteConversionError> {
|
2023-05-18 20:37:41 +02:00
|
|
|
generic_len_check_data_serialization(buf, self.len_value(), MIN_TLV_LEN)?;
|
2023-05-18 14:05:51 +02:00
|
|
|
buf[0] = self.tlv_type as u8;
|
2023-05-18 15:01:08 +02:00
|
|
|
self.lv.write_to_be_bytes_no_len_check(&mut buf[1..]);
|
2023-05-18 20:37:41 +02:00
|
|
|
Ok(self.len_full())
|
2023-05-18 14:05:51 +02:00
|
|
|
}
|
|
|
|
|
2023-05-18 20:37:41 +02:00
|
|
|
pub fn value(&self) -> Option<&[u8]> {
|
2023-05-18 15:01:08 +02:00
|
|
|
self.lv.value()
|
|
|
|
}
|
|
|
|
|
2023-05-18 20:37:41 +02:00
|
|
|
/// Returns the length of the value part, not including the length byte.
|
|
|
|
pub fn len_value(&self) -> usize {
|
|
|
|
self.lv.len_value() + 1
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Returns the full raw length, including the length byte.
|
|
|
|
pub fn len_full(&self) -> usize {
|
|
|
|
self.lv.len_raw() + 1
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Checks whether the value field is empty.
|
|
|
|
pub fn is_empty(&self) -> bool {
|
|
|
|
self.lv.is_empty()
|
|
|
|
}
|
|
|
|
|
2023-05-18 15:01:08 +02:00
|
|
|
pub fn from_be_bytes(buf: &'a [u8]) -> Result<Tlv<'a>, TlvLvError> {
|
|
|
|
generic_len_check_deserialization(buf, MIN_TLV_LEN)?;
|
2023-05-18 14:05:51 +02:00
|
|
|
let tlv_type_res = TlvType::try_from(buf[0]);
|
|
|
|
if tlv_type_res.is_err() {
|
2023-05-18 15:01:08 +02:00
|
|
|
return Err(TlvLvError::UnknownTlvType(buf[1]));
|
2023-05-18 14:05:51 +02:00
|
|
|
}
|
|
|
|
Ok(Self {
|
|
|
|
tlv_type: tlv_type_res.unwrap(),
|
2023-05-18 15:01:08 +02:00
|
|
|
lv: Lv::from_be_bytes(&buf[MIN_LV_LEN..])?,
|
2023-05-18 14:05:51 +02:00
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|