Fully Working CCSDS parsing

+ updated ccsds config to make it work, as I expect it to at least
pull/1/head
Joey Hines 2022-04-09 11:25:09 -06:00
parent e822d9ff13
commit f8ba81e2ca
No known key found for this signature in database
GPG Key ID: 80F567B5C968F91B
3 changed files with 157 additions and 69 deletions

View File

@ -3,34 +3,40 @@
# Ref: https://public.ccsds.org/Pubs/133x0b2e1.pdfa
#
# Example Packet:
# [0xe0, 0xa1, 0xc0, 0x00, 0x05, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05]
# [0xe0, 0xa1, 0xc0, 0x00, 0x00, 0x05, 0x01, 0x02, 0x03, 0x04, 0x05]
[[formats]]
name = "ccsds"
bit_flip = true
bit_flip = false
[[formats.fields]]
name = "Version Number"
bit_flip = true
field_type = {type = "UInt", bit_width = 3, endianness = "BigEndian"}
[[formats.fields]]
name = "Packet Type"
bit_flip = true
field_type = {type = "UInt", bit_width = 1, endianness = "BigEndian"}
[[formats.fields]]
name = "Secondary Header Flag"
bit_flip = true
field_type = {type = "UInt", bit_width = 1, endianness = "BigEndian"}
[[formats.fields]]
name = "APID"
bit_flip = true
field_type = {type = "UInt", bit_width = 11, endianness = "BigEndian"}
[[formats.fields]]
name = "Sequency Flags"
name = "Sequence Flags"
bit_flip = true
field_type = {type = "UInt", bit_width = 2, endianness = "BigEndian"}
[[formats.fields]]
name = "Packet Sequence Count"
bit_flip = true
field_type = {type = "UInt", bit_width = 14, endianness = "BigEndian"}
[[formats.fields]]
@ -40,5 +46,4 @@ field_type = {type = "UInt", bit_width = 16, endianness = "BigEndian"}
[[formats.fields]]
name = "Data"
# Allow payloads up to the max size that can be specfied in "Data Length"
field_type = {type = "Bytes", max_len = 65535}
field_type = {type = "Bytes", max_len = 65535, endianness = "BigEndian"}

View File

@ -1,4 +1,4 @@
use num_bigint::BigUint;
use crate::formatter::format::LastByte;
use std::fmt::{Display, Formatter};
#[derive(Clone, Debug)]
@ -31,10 +31,23 @@ pub const fn bit_mask(mask: u8) -> u8 {
#[derive(Default, Clone, Debug)]
pub struct ByteStream {
data: Vec<u8>,
reverse_bits: bool,
}
impl ByteStream {
pub fn get_bytes(&self, bit_ndx: usize, bit_count: usize) -> Result<Vec<u8>, ByteStreamError> {
pub fn set_reverse_bits(&mut self, reverse_bits: bool) {
self.reverse_bits = reverse_bits;
}
pub fn get_reverse_bits(&self) -> bool {
self.reverse_bits
}
pub fn get_bytes<T: LastByte>(
&self,
bit_ndx: usize,
bit_count: usize,
) -> Result<Vec<u8>, ByteStreamError> {
let byte_ndx = bit_ndx / 8;
let bits_before = (bit_ndx % 8) as u8;
let bits_in_last_byte = ((bit_ndx + bit_count - bits_before as usize) % 8) as u8;
@ -51,11 +64,17 @@ impl ByteStream {
return Err(ByteStreamError::OutOfRange);
}
let byte_stream = self.data[byte_ndx..byte_ndx + bytes_needed].to_vec();
let mut byte_stream = self.data[byte_ndx..byte_ndx + bytes_needed].to_vec();
let number = BigUint::from_bytes_le(&byte_stream) >> bits_before;
if self.reverse_bits {
for byte in &mut byte_stream {
*byte = byte.reverse_bits();
}
}
let mut byte_stream = number.to_bytes_le();
let number = T::big_uint(&byte_stream) >> bits_before;
let mut byte_stream = T::big_u_int_to_bytes(number);
if bytes_needed > byte_count && bytes_needed == byte_stream.len() {
byte_stream.pop();
@ -81,20 +100,26 @@ impl From<&[u8]> for ByteStream {
impl From<Vec<u8>> for ByteStream {
fn from(vec: Vec<u8>) -> Self {
ByteStream { data: vec }
ByteStream {
data: vec,
reverse_bits: false,
}
}
}
#[cfg(test)]
mod tests {
use super::ByteStream;
use byteorder::BigEndian;
#[test]
fn test_get_bytes_no_shift() {
let bytes: Vec<u8> = vec![0xff, 0x00, 0x55];
let bit_stream = ByteStream::from(bytes.clone());
let new_bytes = bit_stream.get_bytes(0, bytes.len() * 8).unwrap();
let new_bytes = bit_stream
.get_bytes::<BigEndian>(0, bytes.len() * 8)
.unwrap();
assert_eq!(bytes, new_bytes);
}
@ -103,7 +128,7 @@ mod tests {
let bytes: Vec<u8> = vec![0x5f, 0x00, 0x55];
let bit_stream = ByteStream::from(bytes.clone());
let new_bytes = bit_stream.get_bytes(4, 4).unwrap();
let new_bytes = bit_stream.get_bytes::<BigEndian>(4, 4).unwrap();
assert_eq!(vec![0x05], new_bytes);
}
@ -112,7 +137,7 @@ mod tests {
let bytes: Vec<u8> = vec![0xff, 0x55];
let bit_stream = ByteStream::from(bytes.clone());
let new_bytes = bit_stream.get_bytes(4, 8).unwrap();
let new_bytes = bit_stream.get_bytes::<BigEndian>(4, 8).unwrap();
assert_eq!(vec![0x5f], new_bytes);
}
@ -121,7 +146,7 @@ mod tests {
let bytes: Vec<u8> = vec![0xff, 0x55];
let bit_stream = ByteStream::from(bytes.clone());
let new_bytes = bit_stream.get_bytes(7, 2).unwrap();
let new_bytes = bit_stream.get_bytes::<BigEndian>(7, 2).unwrap();
assert_eq!(vec![0x03], new_bytes);
}
@ -130,7 +155,7 @@ mod tests {
let bytes: Vec<u8> = vec![0xff, 0x55];
let bit_stream = ByteStream::from(bytes.clone());
let new_bytes = bit_stream.get_bytes(8, 8).unwrap();
let new_bytes = bit_stream.get_bytes::<BigEndian>(8, 8).unwrap();
assert_eq!(vec![0x55], new_bytes);
}
@ -139,7 +164,7 @@ mod tests {
let bytes: Vec<u8> = vec![0x55];
let bit_stream = ByteStream::from(bytes.clone());
let new_bytes = bit_stream.get_bytes(0, 3).unwrap();
let new_bytes = bit_stream.get_bytes::<BigEndian>(0, 3).unwrap();
assert_eq!(vec![0x05], new_bytes);
}
}

View File

@ -13,6 +13,10 @@ pub trait LastByte: ByteOrder {
fn big_int(buf: &[u8]) -> BigInt;
fn big_uint(buf: &[u8]) -> BigUint;
fn big_u_int_to_bytes(big_int: BigUint) -> Vec<u8>;
fn big_int_to_bytes(big_int: BigInt) -> Vec<u8>;
}
impl LastByte for BigEndian {
@ -27,6 +31,14 @@ impl LastByte for BigEndian {
fn big_uint(buf: &[u8]) -> BigUint {
BigUint::from_bytes_be(buf)
}
fn big_u_int_to_bytes(big_int: BigUint) -> Vec<u8> {
big_int.to_bytes_be()
}
fn big_int_to_bytes(big_int: BigInt) -> Vec<u8> {
big_int.to_signed_bytes_be()
}
}
impl LastByte for LittleEndian {
@ -41,6 +53,14 @@ impl LastByte for LittleEndian {
fn big_uint(buf: &[u8]) -> BigUint {
BigUint::from_bytes_le(buf)
}
fn big_u_int_to_bytes(big_int: BigUint) -> Vec<u8> {
big_int.to_bytes_le()
}
fn big_int_to_bytes(big_int: BigInt) -> Vec<u8> {
big_int.to_signed_bytes_le()
}
}
#[derive(Debug, Clone)]
@ -79,25 +99,31 @@ pub enum FieldType {
/// Unsigned Int
UInt {
bit_width: usize,
endianness: BigEndianness,
endianness: Endianness,
},
/// Unsigned Int
Int {
bit_width: usize,
endianness: BigEndianness,
endianness: Endianness,
},
/// Single Precession Float
Float { endianness: BigEndianness },
Float { endianness: Endianness },
/// Double Precession Float
Double { endianness: BigEndianness },
Double { endianness: Endianness },
/// Null Terminated String Field
String { max_len: usize },
String {
max_len: usize,
endianness: Endianness,
},
/// Fixed Byte Length Field
Bytes { max_len: usize },
Bytes {
max_len: usize,
endianness: Endianness,
},
}
#[derive(Debug, Deserialize, Clone, PartialOrd, PartialEq, Copy)]
pub enum BigEndianness {
pub enum Endianness {
LittleEndian,
BigEndian,
}
@ -108,8 +134,8 @@ pub struct Field {
pub name: String,
/// Field Type
pub field_type: FieldType,
/// Flip Bit Border
pub flip_bit_order: Option<bool>,
/// Flip Bit Order
pub bit_flip: Option<bool>,
}
impl Field {
@ -118,7 +144,7 @@ impl Field {
bit_ndx: usize,
bit_width: usize,
) -> Result<(String, usize), FormatError> {
let mut bytes = byte_stream.get_bytes(bit_ndx, bit_width)?;
let mut bytes = byte_stream.get_bytes::<T>(bit_ndx, bit_width)?;
if let Some(last_byte) = T::last_byte(&mut bytes) {
let last_bit = ((bit_width - 1) % 8) as u8;
@ -142,7 +168,7 @@ impl Field {
bit_ndx: usize,
bit_width: usize,
) -> Result<(String, usize), FormatError> {
let bytes = byte_stream.get_bytes(bit_ndx, bit_width)?;
let bytes = byte_stream.get_bytes::<T>(bit_ndx, bit_width)?;
let big_int = T::big_uint(&bytes);
Ok((big_int.to_string(), bit_width))
@ -152,7 +178,7 @@ impl Field {
byte_stream: &ByteStream,
bit_ndx: usize,
) -> Result<(String, usize), FormatError> {
let bytes = byte_stream.get_bytes(bit_ndx, 32)?;
let bytes = byte_stream.get_bytes::<T>(bit_ndx, 32)?;
let mut cursor = Cursor::new(bytes);
Ok((cursor.read_f32::<T>().unwrap().to_string(), 4))
@ -162,13 +188,13 @@ impl Field {
byte_stream: &ByteStream,
bit_ndx: usize,
) -> Result<(String, usize), FormatError> {
let bytes = byte_stream.get_bytes(bit_ndx, 64)?;
let bytes = byte_stream.get_bytes::<T>(bit_ndx, 64)?;
let mut cursor = Cursor::new(bytes);
Ok((cursor.read_f64::<T>().unwrap().to_string(), 4))
}
fn format_string(
fn format_string<T: LastByte>(
byte_stream: &ByteStream,
mut bit_ndx: usize,
max_byte_len: usize,
@ -176,7 +202,7 @@ impl Field {
let mut string_bytes = Vec::new();
for _ in 0..max_byte_len {
let byte = byte_stream.get_bytes(bit_ndx, 8)?[0];
let byte = byte_stream.get_bytes::<T>(bit_ndx, 8)?[0];
if byte == 0 {
break;
@ -190,7 +216,7 @@ impl Field {
Ok((String::from_utf8(string_bytes)?, byte_count))
}
fn format_bytes(
fn format_bytes<T: LastByte>(
byte_stream: &ByteStream,
bit_ndx: usize,
max_byte_len: usize,
@ -203,25 +229,31 @@ impl Field {
data_remaining * 8
};
let data = byte_stream.get_bytes(bit_ndx, width)?;
let data = byte_stream.get_bytes::<T>(bit_ndx, width)?;
Ok((print_bytes_as_array(&data), width))
}
fn format_data(
&self,
byte_stream: &ByteStream,
byte_stream: &mut ByteStream,
bit_ndx: usize,
) -> Result<(String, usize), FormatError> {
match self.field_type {
let global_bit_flip = byte_stream.get_reverse_bits();
if let Some(bit_flip) = self.bit_flip {
byte_stream.set_reverse_bits(bit_flip);
}
let fmt = match self.field_type {
FieldType::UInt {
bit_width,
endianness,
} => match endianness {
BigEndianness::LittleEndian => {
Endianness::LittleEndian => {
Self::format_uint::<LittleEndian>(byte_stream, bit_ndx, bit_width)
}
BigEndianness::BigEndian => {
Endianness::BigEndian => {
Self::format_uint::<BigEndian>(byte_stream, bit_ndx, bit_width)
}
},
@ -229,28 +261,52 @@ impl Field {
bit_width,
endianness,
} => match endianness {
BigEndianness::LittleEndian => {
Endianness::LittleEndian => {
Self::format_int::<LittleEndian>(byte_stream, bit_ndx, bit_width)
}
BigEndianness::BigEndian => {
Endianness::BigEndian => {
Self::format_int::<BigEndian>(byte_stream, bit_ndx, bit_width)
}
},
FieldType::Float { endianness } => match endianness {
BigEndianness::LittleEndian => {
Endianness::LittleEndian => {
Self::format_float::<LittleEndian>(byte_stream, bit_ndx)
}
BigEndianness::BigEndian => Self::format_float::<BigEndian>(byte_stream, bit_ndx),
Endianness::BigEndian => Self::format_float::<BigEndian>(byte_stream, bit_ndx),
},
FieldType::Double { endianness } => match endianness {
BigEndianness::LittleEndian => {
Endianness::LittleEndian => {
Self::format_double::<LittleEndian>(byte_stream, bit_ndx)
}
BigEndianness::BigEndian => Self::format_double::<BigEndian>(byte_stream, bit_ndx),
Endianness::BigEndian => Self::format_double::<BigEndian>(byte_stream, bit_ndx),
},
FieldType::String { max_len } => Self::format_string(byte_stream, bit_ndx, max_len),
FieldType::Bytes { max_len } => Self::format_bytes(byte_stream, bit_ndx, max_len),
}
FieldType::String {
max_len,
endianness,
} => match endianness {
Endianness::LittleEndian => {
Self::format_string::<LittleEndian>(byte_stream, bit_ndx, max_len)
}
Endianness::BigEndian => {
Self::format_string::<LittleEndian>(byte_stream, bit_ndx, max_len)
}
},
FieldType::Bytes {
max_len,
endianness,
} => match endianness {
Endianness::LittleEndian => {
Self::format_bytes::<LittleEndian>(byte_stream, bit_ndx, max_len)
}
Endianness::BigEndian => {
Self::format_bytes::<LittleEndian>(byte_stream, bit_ndx, max_len)
}
},
}?;
byte_stream.set_reverse_bits(global_bit_flip);
Ok(fmt)
}
}
@ -267,11 +323,13 @@ pub struct Format {
impl Format {
pub fn format_data(&self, data: &[u8]) -> Result<String, FormatError> {
let mut format_str = String::new();
let byte_stream = ByteStream::from(data);
let mut byte_stream = ByteStream::from(data);
let mut bit_ndx: usize = 0;
byte_stream.set_reverse_bits(self.bit_flip);
for field in &self.fields {
match field.format_data(&byte_stream, bit_ndx) {
match field.format_data(&mut byte_stream, bit_ndx) {
Ok((data_str, bit_width)) => {
bit_ndx += bit_width;
writeln!(format_str, "{}: {}", field.name, data_str).unwrap();
@ -290,17 +348,17 @@ impl Format {
#[cfg(test)]
mod tests {
use crate::byte_stream::ByteStream;
use crate::formatter::format::{BigEndianness, Field, FieldType};
use crate::formatter::format::{Endianness, Field, FieldType};
#[test]
fn test_format_int_4_bits() {
let field = Field {
field_type: FieldType::Int {
bit_width: 4,
endianness: BigEndianness::LittleEndian,
endianness: Endianness::LittleEndian,
},
name: "test".to_string(),
flip_bit_order: None,
bit_flip: None,
};
for i in 0i8..7i8 {
@ -322,10 +380,10 @@ mod tests {
let field = Field {
field_type: FieldType::Int {
bit_width: 5,
endianness: BigEndianness::LittleEndian,
endianness: Endianness::LittleEndian,
},
name: "test".to_string(),
flip_bit_order: None,
bit_flip: None,
};
let byte_steam = ByteStream::from(vec![0x1B]);
let (output, _) = field.format_data(&byte_steam, 0).unwrap();
@ -338,10 +396,10 @@ mod tests {
let field = Field {
field_type: FieldType::Int {
bit_width: 16,
endianness: BigEndianness::LittleEndian,
endianness: Endianness::LittleEndian,
},
name: "test".to_string(),
flip_bit_order: None,
bit_flip: None,
};
let byte_steam = ByteStream::from(vec![0xFC, 0xA5]);
@ -355,10 +413,10 @@ mod tests {
let field = Field {
field_type: FieldType::Int {
bit_width: 16,
endianness: BigEndianness::LittleEndian,
endianness: Endianness::LittleEndian,
},
name: "test".to_string(),
flip_bit_order: None,
bit_flip: None,
};
let byte_steam = ByteStream::from(vec![0xC0, 0x5F, 0x0A]);
@ -371,10 +429,10 @@ mod tests {
fn test_format_float() {
let field = Field {
field_type: FieldType::Float {
endianness: BigEndianness::LittleEndian,
endianness: Endianness::LittleEndian,
},
name: "test".to_string(),
flip_bit_order: None,
bit_flip: None,
};
let byte_steam = ByteStream::from(b"\x52\x58\xd2\xc3".to_vec());
@ -387,10 +445,10 @@ mod tests {
fn test_format_double() {
let field = Field {
field_type: FieldType::Double {
endianness: BigEndianness::LittleEndian,
endianness: Endianness::LittleEndian,
},
name: "test".to_string(),
flip_bit_order: None,
bit_flip: None,
};
let byte_steam = ByteStream::from(b"\xD7\xA3\x70\x3D\x0A\x4B\x7A\xC0".to_vec());
@ -403,10 +461,10 @@ mod tests {
fn test_format_float_err() {
let field = Field {
field_type: FieldType::Double {
endianness: BigEndianness::LittleEndian,
endianness: Endianness::LittleEndian,
},
name: "test".to_string(),
flip_bit_order: None,
bit_flip: None,
};
let byte_steam = ByteStream::from(b"\x3D\x70\xA3\xD7".to_vec());
@ -419,7 +477,7 @@ mod tests {
let field = Field {
field_type: FieldType::String { max_len: 16 },
name: "test".to_string(),
flip_bit_order: None,
bit_flip: None,
};
let byte_steam = ByteStream::from(b"Hello World!\0".to_vec());
@ -434,7 +492,7 @@ mod tests {
let field = Field {
field_type: FieldType::Bytes { max_len: 2 },
name: "test".to_string(),
flip_bit_order: None,
bit_flip: None,
};
let byte_steam = ByteStream::from(vec![0xDE, 0xAD, 0xBE, 0xEF]);
@ -449,7 +507,7 @@ mod tests {
let field = Field {
field_type: FieldType::Bytes { max_len: 64 },
name: "test".to_string(),
flip_bit_order: None,
bit_flip: None,
};
let byte_steam = ByteStream::from(vec![0xDE, 0xAD]);
@ -464,10 +522,10 @@ mod tests {
let field = Field {
field_type: FieldType::UInt {
bit_width: 11,
endianness: BigEndianness::LittleEndian,
endianness: Endianness::LittleEndian,
},
name: "test".to_string(),
flip_bit_order: None,
bit_flip: None,
};
let byte_steam = ByteStream::from(vec![