use std::io::{Error, ErrorKind, Read};
use byteorder::{BigEndian, ReadBytesExt};
#[cfg(feature = "crc")]
use crc::Crc;
use crate::GroupingFlag;
use crate::tctm::randomizer::{apply_randomization, Randomization};
#[derive(Debug, Clone, Copy)]
pub enum TMRandomization {
None,
Tm255,
Tm131071,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum BooleanFieldFlag {
NotPresent = 0,
Present = 1,
}
impl BooleanFieldFlag {
pub fn from_u8(val: u8) -> Result<Self, Error> {
match val {
0 => Ok(Self::NotPresent),
1 => Ok(Self::Present),
val => Err(Error::new(
ErrorKind::InvalidData,
format!("Invalid BooleanFieldFlag value {val:}. Can only be 1 bit."),
)),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum SynchronizationFlag {
Nominal = 0,
VcaSdu = 1,
}
impl SynchronizationFlag {
pub fn from_u8(val: u8) -> Result<Self, Error> {
match val {
0 => Ok(Self::Nominal),
1 => Ok(Self::VcaSdu),
val => Err(Error::new(
ErrorKind::InvalidData,
format!("Invalid SynchronizationFlag value {val:}. Can only be 1 bit."),
)),
}
}
}
#[repr(u8)]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum SegmentLength {
Undefined(u8),
Unsegmented = 0b11,
}
impl SegmentLength {
pub fn from_u8(value: u8) -> Result<Self, Error> {
match value {
val if val < 0b11 => Ok(Self::Undefined(val)),
0b11 => Ok(Self::Unsegmented),
val => Err(Error::new(
ErrorKind::InvalidData,
format!("SegmentLength can must be less than 4, found {val}"),
)),
}
}
pub fn into_u8(self) -> u8 {
match self {
SegmentLength::Undefined(val) => val & 0x3,
SegmentLength::Unsegmented => 0b11,
}
}
}
#[repr(u16)]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum FirstHeaderPointer {
ByteIndex(u16),
OnlyIdleData = 0b111_1111_1110,
NoPacketStart = 0b111_1111_1111,
}
impl FirstHeaderPointer {
pub fn into_u16(self) -> u16 {
match self {
FirstHeaderPointer::ByteIndex(value) => value & 0x7ff,
FirstHeaderPointer::OnlyIdleData => 0b111_1111_1110,
FirstHeaderPointer::NoPacketStart => 0b111_1111_1111,
}
}
pub fn from_u16(value: u16) -> Result<Self, Error> {
match value {
val if val < 2046 => Ok(Self::ByteIndex(val)),
0b111_1111_1110 => Ok(Self::OnlyIdleData),
0b111_1111_1111 => Ok(Self::NoPacketStart),
val => Err(Error::new(
ErrorKind::InvalidData,
format!(
"Invalid FristHeaderPointer value. \
Value must be less than 2048 but received {val}."
),
)),
}
}
pub fn validate(&self) -> Result<(), Error> {
match self {
Self::ByteIndex(index) => {
if index < &2046_u16 {
Ok(())
} else {
Err(Error::new(
ErrorKind::InvalidData,
format!("First Header byte index must be less than 2046 found {index}"),
))
}
}
Self::OnlyIdleData => Ok(()),
Self::NoPacketStart => Ok(()),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct TMDataFieldStatus {
pub secondary_header_flag: BooleanFieldFlag,
pub synchronization_flag: SynchronizationFlag,
pub packet_order: bool,
pub segment_length: GroupingFlag,
pub first_header_pointer: FirstHeaderPointer,
}
impl TMDataFieldStatus {
pub fn validate(&self) -> Result<(), Error> {
self.first_header_pointer.validate()
}
pub fn encode(self) -> Vec<u8> {
let Self {
secondary_header_flag,
synchronization_flag,
packet_order,
segment_length,
first_header_pointer,
} = self;
let word = ((secondary_header_flag as u16) << 15)
| ((synchronization_flag as u16) << 14)
| ((packet_order as u16) << 13)
| ((segment_length as u16) << 11)
| first_header_pointer.into_u16();
word.to_be_bytes().to_vec()
}
pub fn decode<R: Read>(buffer: &mut R) -> Result<Self, Error> {
let first_word = buffer.read_u16::<BigEndian>()?;
Ok(Self {
secondary_header_flag: BooleanFieldFlag::from_u8((first_word >> 15) as u8 & 0x1_u8)?,
synchronization_flag: SynchronizationFlag::from_u8((first_word >> 14) as u8 & 0x1_u8)?,
packet_order: (first_word >> 13) & 0x1 == 1,
segment_length: GroupingFlag::from_2bits((first_word >> 11) as u8 & 0x3),
first_header_pointer: FirstHeaderPointer::from_u16(first_word & 0x7FF_u16)?,
})
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct TMPrimaryHeader {
pub tfvn: u8,
pub scid: u16,
pub vcid: u8,
pub ocf_flag: BooleanFieldFlag,
pub mc_frame_count: u8,
pub vc_frame_count: u8,
pub data_field_status: TMDataFieldStatus,
}
impl TMPrimaryHeader {
pub fn validate(&self) -> Result<(), Error> {
if self.tfvn > 3 {
return Err(Error::new(
ErrorKind::InvalidData,
format!(
"Transfer frame version number must be <=3 but found {}",
self.tfvn
),
));
}
if self.scid > 1023 {
return Err(Error::new(
ErrorKind::InvalidData,
format!("Spacecraft ID must be <=1023 but found {}", self.scid),
));
}
if self.vcid > 7 {
return Err(Error::new(
ErrorKind::InvalidData,
format!("Virtual Channel ID must be <=7 but found {}", self.vcid),
));
}
self.data_field_status.validate()?;
Ok(())
}
pub fn encode(self) -> Vec<u8> {
let Self {
tfvn,
scid,
vcid,
ocf_flag,
mc_frame_count,
vc_frame_count,
data_field_status,
} = self;
let first_word = {
((tfvn as u16 & 0x3_u16) << 14)
| ((scid & 0x3ff_u16) << 4)
| ((vcid as u16 & 0x7_u16) << 1)
| ocf_flag as u16
};
let mut message = first_word.to_be_bytes().to_vec();
message.push(mc_frame_count);
message.push(vc_frame_count);
message.extend_from_slice(&data_field_status.encode());
message
}
pub fn decode<R: Read>(buffer: &mut R) -> Result<Self, Error> {
let first_word = buffer.read_u16::<BigEndian>()?;
Ok(Self {
tfvn: (first_word >> 14) as u8 & 0x3_u8,
scid: (first_word >> 4) & 0x3ff_u16,
vcid: (first_word >> 1) as u8 & 0x7_u8,
ocf_flag: BooleanFieldFlag::from_u8((first_word & 0x1_u16) as u8)?,
mc_frame_count: buffer.read_u8()?,
vc_frame_count: buffer.read_u8()?,
data_field_status: TMDataFieldStatus::decode(buffer)?,
})
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct TMSecondaryHeader {
pub tfvn: u8,
pub data_field: Vec<u8>,
}
impl TMSecondaryHeader {
pub fn validate(&self) -> Result<(), Error> {
if self.tfvn > 3 {
return Err(Error::new(
ErrorKind::InvalidData,
format!(
"Transfer frame version number must be <=3 but found {}",
self.tfvn
),
));
}
if self.data_field.len() > 63 {
return Err(Error::new(
ErrorKind::InvalidData,
format!(
"Secondary Header data field must have length <=63. Found {}",
self.data_field.len()
),
));
}
Ok(())
}
pub fn encode(self) -> Vec<u8> {
let Self {
tfvn,
mut data_field,
} = self;
let packet_len = (data_field.len()) as u8;
let mut message = vec![{ ((tfvn & 0x3_u8) << 6) | packet_len }];
message.append(&mut data_field);
message
}
pub fn decode<R: Read>(buffer: &mut R) -> Result<Self, Error> {
let first_byte = buffer.read_u8()?;
let data_len = (first_byte & 0x3f) as usize;
Ok(Self {
tfvn: (first_byte >> 6) & 0x3,
data_field: {
let mut tmp = vec![0; data_len];
buffer.read_exact(&mut tmp)?;
tmp
},
})
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct TMTransferFrame {
pub primary_header: TMPrimaryHeader,
pub data_field: Vec<u8>,
}
impl TMTransferFrame {
fn _encode_helper(self) -> Vec<u8> {
let Self {
primary_header,
mut data_field,
} = self;
let mut message = primary_header.encode();
message.append(&mut data_field);
message
}
pub fn encode(self, randomization: TMRandomization) -> Vec<u8> {
match randomization {
TMRandomization::None => self._encode_helper(),
TMRandomization::Tm255 => {
apply_randomization(self._encode_helper().as_slice(), Randomization::Tm255)
}
TMRandomization::Tm131071 => {
apply_randomization(self._encode_helper().as_slice(), Randomization::Tm131071)
}
}
}
fn _decode_helper<R: Read>(
mut buffer: R,
length: usize,
randomization: TMRandomization,
) -> Result<Vec<u8>, Error> {
let byte_array = {
let mut tmp = vec![0_u8; length];
buffer.read_exact(&mut tmp)?;
tmp
};
let buffer_vec = match randomization {
TMRandomization::None => byte_array,
TMRandomization::Tm255 => {
apply_randomization(byte_array.as_slice(), Randomization::Tm255)
}
TMRandomization::Tm131071 => {
apply_randomization(byte_array.as_slice(), Randomization::Tm131071)
}
};
Ok(buffer_vec)
}
pub fn decode<R: Read>(
buffer: R,
length: usize,
randomization: TMRandomization,
) -> Result<Self, Error> {
let buffer = Self::_decode_helper(buffer, length, randomization)?;
let mut buffer = buffer.as_slice();
Ok(Self {
primary_header: TMPrimaryHeader::decode(&mut buffer)?,
data_field: {
let mut tmp = vec![0_u8; length - 6];
buffer.read_exact(&mut tmp)?;
tmp
},
})
}
#[cfg(feature = "crc")]
#[cfg_attr(docsrs, doc(cfg(feature = "crc")))]
pub fn encode_crc(self, crc: &Crc<u16>, randomization: TMRandomization) -> Vec<u8> {
let mut message = self._encode_helper();
message.extend(crc.checksum(message.as_slice()).to_be_bytes());
match randomization {
TMRandomization::None => message,
TMRandomization::Tm255 => apply_randomization(message.as_slice(), Randomization::Tm255),
TMRandomization::Tm131071 => {
apply_randomization(message.as_slice(), Randomization::Tm131071)
}
}
}
#[cfg(feature = "crc")]
#[cfg_attr(docsrs, doc(cfg(feature = "crc")))]
pub fn decode_crc<R: Read>(
buffer: &mut R,
length: usize,
randomization: TMRandomization,
crc: &Crc<u16>,
) -> Result<Self, Error> {
let buffer = Self::_decode_helper(buffer, length, randomization)?;
let mut buffer = buffer.as_slice();
let mut msg_buffer = vec![0_u8; length - 2];
buffer.read_exact(&mut msg_buffer)?;
let attached_crc = buffer.read_u16::<BigEndian>()?;
let computed_crc = crc.checksum(msg_buffer.as_slice());
if computed_crc != attached_crc {
return Err(Error::new(
ErrorKind::InvalidData,
format!(
"CRC failure on TM Transfer Frame. \
Exepcted {attached_crc:#04X} Computer {computed_crc:#04X}"
),
));
}
Ok(Self {
primary_header: TMPrimaryHeader::decode(&mut buffer)?,
data_field: {
let mut tmp = vec![0_u8; length - 6];
buffer.read_exact(&mut tmp)?;
tmp
},
})
}
}
#[cfg(test)]
mod test {
use super::*;
use rstest::rstest;
#[rstest]
#[case(0, 5, 2, 12)]
#[case(0, 1023, 7, 2045)]
#[should_panic]
#[case(4, 5, 2, 2045)]
#[should_panic]
#[case(0, 1024, 5, 1023)]
#[should_panic]
#[case(0, 7, 8, 1023)]
#[should_panic]
#[case(0, 100, 3, 2049)]
fn tm_header_validation(
#[case] tfvn: u8,
#[case] scid: u16,
#[case] vcid: u8,
#[case] index: u16,
) {
let header = TMPrimaryHeader {
tfvn,
scid,
vcid,
ocf_flag: BooleanFieldFlag::Present,
mc_frame_count: 7,
vc_frame_count: 244,
data_field_status: TMDataFieldStatus {
secondary_header_flag: BooleanFieldFlag::NotPresent,
synchronization_flag: SynchronizationFlag::Nominal,
packet_order: false,
segment_length: GroupingFlag::Unsegm,
first_header_pointer: FirstHeaderPointer::ByteIndex(index),
},
};
assert!(header.validate().is_ok())
}
#[rstest]
fn tm_primary_header(
#[values(0, 5, 1023)] scid: u16,
#[values(0, 3, 7)] vcid: u8,
#[values(BooleanFieldFlag::NotPresent, BooleanFieldFlag::Present)]
ocf_flag: BooleanFieldFlag,
#[values(BooleanFieldFlag::NotPresent, BooleanFieldFlag::Present)]
secondary_header_flag: BooleanFieldFlag,
#[values(SynchronizationFlag::Nominal, SynchronizationFlag::VcaSdu)]
synchronization_flag: SynchronizationFlag,
#[values(GroupingFlag::First, GroupingFlag::Unsegm)] segment_length: GroupingFlag,
#[values(0, 2045, 2046, 2047)] index: u16,
) {
let expected = TMPrimaryHeader {
tfvn: 0b11,
scid,
vcid,
ocf_flag,
mc_frame_count: 77,
vc_frame_count: 128,
data_field_status: TMDataFieldStatus {
secondary_header_flag,
synchronization_flag,
packet_order: false,
segment_length,
first_header_pointer: FirstHeaderPointer::from_u16(index)
.expect("Bad index number"),
},
};
let bytes = expected.encode();
let recovered = TMPrimaryHeader::decode(&mut bytes.as_slice())
.expect("Unable to decode TMPrimaryHeader");
assert_eq!(expected, recovered)
}
#[test]
fn tm_compare_spacepy() {
let mut input_bytes: &[u8] = &[
0x2F, 0x61, 0x00, 0x00, 0x18, 0x00, 0x0C, 0xD2, 0xC0, 0x00, 0x00, 0x1A, 0x10, 0x03,
0x19, 0x16, 0x92, 0x5E, 0x92, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x89, 0xE4, 0x07, 0xFF, 0xC0,
0x00, 0x04, 0x27, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0xC9, 0x48, 0x01, 0x00, 0x00, 0x00, 0xBB, 0xD6,
];
let expected = TMTransferFrame {
primary_header: TMPrimaryHeader {
tfvn: 0,
scid: 758,
vcid: 0,
ocf_flag: BooleanFieldFlag::Present,
mc_frame_count: 0,
vc_frame_count: 0,
data_field_status: TMDataFieldStatus {
secondary_header_flag: BooleanFieldFlag::NotPresent,
synchronization_flag: SynchronizationFlag::Nominal,
packet_order: false,
segment_length: GroupingFlag::Unsegm,
first_header_pointer: FirstHeaderPointer::ByteIndex(0),
},
},
data_field: vec![
0x0C, 0xD2, 0xC0, 0x00, 0x00, 0x1A, 0x10, 0x03, 0x19, 0x16, 0x92, 0x5E, 0x92, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x89, 0xE4, 0x07, 0xFF, 0xC0, 0x00, 0x04, 0x27, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC9, 0x48, 0x01, 0x00, 0x00,
0x00, 0xBB, 0xD6,
],
};
let parsed_tm = TMTransferFrame::decode(&mut input_bytes, 1115, TMRandomization::None)
.expect("Unable to parse TM Frame.");
assert_eq!(expected, parsed_tm)
}
}