use crate::byte_stream::{ByteStream, bit_mask, ByteStreamError}; use serde::Deserialize; use std::fmt::{Write, Display, Formatter}; use num_bigint::{BigUint, BigInt}; use std::io::Cursor; use byteorder::{LittleEndian, ReadBytesExt}; use std::string::FromUtf8Error; use crate::formatter::printers::print_bytes_as_array; #[derive(Debug, Clone)] pub enum FormatError { ByteSteamError(ByteStreamError), #[allow(dead_code)] NotSupported, StringParseError(FromUtf8Error), } impl From for FormatError { fn from(e: ByteStreamError) -> Self { FormatError::ByteSteamError(e) } } impl From for FormatError { fn from(e: FromUtf8Error) -> Self { FormatError::StringParseError(e) } } impl Display for FormatError { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { match self { FormatError::ByteSteamError(e) => writeln!(f, "Byte stream error: {}", e), FormatError::NotSupported => write!(f, "Field type not supported"), FormatError::StringParseError(e) => write!(f, "String parse error: {}", e) } } } #[derive(Debug, Deserialize, Clone)] #[serde(tag = "type")] pub enum FieldType { /// Unsigned Int UInt { bit_width: usize }, /// Unsigned Int Int { bit_width: usize }, /// Single Precession Float Float, /// Double Precession Float Double, /// Null Terminated String Field String { max_len: usize }, /// Fixed Byte Length Field Bytes { max_len: usize }, } #[derive(Debug, Deserialize, Clone)] pub struct Field { /// Field Name pub name: String, /// Field Type pub field_type: FieldType, } impl Field { fn format_int(byte_stream: &ByteStream, bit_ndx: usize, bit_width: usize) -> Result<(String, usize), FormatError> { let mut bytes = byte_stream.get_bytes(bit_ndx, bit_width)?; if let Some(last_byte) = bytes.last_mut() { let last_bit = ((bit_width - 1) % 8) as u8; let sign_bit = (*last_byte >> last_bit) & 0x1 == 1; if sign_bit { // Sign extend *last_byte |= !bit_mask(last_bit + 1) } let big_int = BigInt::from_signed_bytes_le(&bytes); Ok((big_int.to_string(), bit_width)) } else { Err(ByteStreamError::OutOfRange.into()) } } fn format_uint(byte_stream: &ByteStream, bit_ndx: usize, bit_width: usize) -> Result<(String, usize), FormatError> { let bytes = byte_stream.get_bytes(bit_ndx, bit_width)?; let big_int = BigUint::from_bytes_le(&bytes); Ok((big_int.to_string(), bit_width)) } fn format_float(byte_stream: &ByteStream, bit_ndx: usize) -> Result<(String, usize), FormatError> { let bytes = byte_stream.get_bytes(bit_ndx, 32)?; let mut cursor = Cursor::new(bytes); Ok((cursor.read_f32::().unwrap().to_string(), 4)) } fn format_double(byte_stream: &ByteStream, bit_ndx: usize) -> Result<(String, usize), FormatError> { let bytes = byte_stream.get_bytes(bit_ndx, 64)?; let mut cursor = Cursor::new(bytes); Ok((cursor.read_f64::().unwrap().to_string(), 4)) } fn format_string(byte_stream: &ByteStream, mut bit_ndx: usize, max_byte_len: usize) -> Result<(String, usize), FormatError> { let mut string_bytes = Vec::new(); for _ in 0..max_byte_len { let byte = byte_stream.get_bytes(bit_ndx, 8)?[0]; if byte == 0 { break; } string_bytes.push(byte); bit_ndx += 8; } let byte_count = string_bytes.len(); Ok((String::from_utf8(string_bytes)?, byte_count)) } fn format_bytes(byte_stream: &ByteStream, bit_ndx: usize, max_byte_len: usize) -> Result<(String, usize), FormatError> { let data_remaining = byte_stream.len() - bit_ndx/8; let width = if max_byte_len < data_remaining { max_byte_len*8 } else { data_remaining*8 }; let data = byte_stream.get_bytes(bit_ndx, width)?; Ok((print_bytes_as_array(&data), width)) } fn format_data(&self, byte_stream: &ByteStream, bit_ndx: usize) -> Result<(String, usize), FormatError> { match self.field_type { FieldType::UInt { bit_width } => Self::format_uint(byte_stream, bit_ndx, bit_width), FieldType::Int { bit_width } => Self::format_int(byte_stream, bit_ndx, bit_width), FieldType::Float => Self::format_float(byte_stream, bit_ndx), FieldType::Double => Self::format_double(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) } } } #[derive(Debug, Deserialize, Clone)] pub struct Format { /// Format Name pub name: String, /// Elements of the format pub fields: Vec, } impl Format { pub fn format_data(&self, data: &[u8]) -> Result { let mut format_str = String::new(); let byte_stream = ByteStream::from(data); let mut bit_ndx: usize = 0; for field in &self.fields { match field.format_data(&byte_stream, bit_ndx) { Ok((data_str, bit_width)) => { bit_ndx += bit_width; writeln!(format_str, "{}: {}", field.name, data_str).unwrap(); } Err(e) => { println!("Error formatting field: \"{}\": {}", field.name, e); return Err(e); } } } Ok(format_str) } } #[cfg(test)] mod tests { use crate::formatter::format::{FieldType, Field}; use crate::byte_stream::ByteStream; #[test] fn test_format_int_4_bits() { let field = Field {field_type: FieldType::Int {bit_width: 4,}, name: "test".to_string()}; for i in 0i8..7i8 { let mut byte_vec = Vec::new(); byte_vec.push(i as u8); byte_vec.push((-i) as u8); let byte_steam = ByteStream::from(byte_vec); let (pos_output, _) = field.format_data(&byte_steam, 0).unwrap(); let (neg_output, _) = field.format_data(&byte_steam, 8).unwrap(); assert_eq!(pos_output, i.to_string()); assert_eq!(neg_output, (-i).to_string()); } } #[test] fn test_format_int_5_bits() { let field = Field {field_type: FieldType::Int {bit_width: 5,}, name: "test".to_string()}; let byte_steam = ByteStream::from(vec![0x1B]); let (output, _) = field.format_data(&byte_steam, 0).unwrap(); assert_eq!(output, "-5") } #[test] fn test_format_int_16_bits() { let field = Field {field_type: FieldType::Int {bit_width: 16,}, name: "test".to_string()}; let byte_steam = ByteStream::from(vec![0xFC, 0xA5]); let (output, _) = field.format_data(&byte_steam, 0).unwrap(); assert_eq!(output, "-23044") } #[test] fn test_format_int_16_bits_not_aligned() { let field = Field {field_type: FieldType::Int {bit_width: 16,}, name: "test".to_string()}; let byte_steam = ByteStream::from(vec![0xC0, 0x5F, 0x0A]); let (output, _) = field.format_data(&byte_steam, 4).unwrap(); assert_eq!(output, "-23044") } #[test] fn test_format_float() { let field = Field {field_type: FieldType::Float, name: "test".to_string()}; let byte_steam = ByteStream::from(b"\x52\x58\xd2\xc3".to_vec()); let (output, _) = field.format_data(&byte_steam, 0).unwrap(); assert_eq!(output, "-420.69") } #[test] fn test_format_double() { let field = Field {field_type: FieldType::Double, name: "test".to_string()}; let byte_steam = ByteStream::from(b"\xD7\xA3\x70\x3D\x0A\x4B\x7A\xC0".to_vec()); let (output, _) = field.format_data(&byte_steam, 0).unwrap(); assert_eq!(output, "-420.69") } #[test] fn test_format_float_err() { let field = Field {field_type: FieldType::Double, name: "test".to_string()}; let byte_steam = ByteStream::from(b"\x3D\x70\xA3\xD7".to_vec()); assert!(field.format_data(&byte_steam, 0).is_err()) } #[test] fn test_format_string() { let field = Field {field_type: FieldType::String {max_len: 16}, name: "test".to_string()}; let byte_steam = ByteStream::from(b"Hello World!\0".to_vec()); let (output, _) = field.format_data(&byte_steam, 0).unwrap(); assert_eq!(output, "Hello World!".to_string()) } #[test] fn test_format_bytes() { let field = Field {field_type: FieldType::Bytes {max_len: 2}, name: "test".to_string()}; let byte_steam = ByteStream::from(vec![0xDE, 0xAD, 0xBE, 0xEF]); let (output, _) = field.format_data(&byte_steam, 0).unwrap(); assert_eq!(output, "[222, 173]") } #[test] fn test_format_bytes_max_len_bigger_than_data() { let field = Field {field_type: FieldType::Bytes {max_len: 64}, name: "test".to_string()}; let byte_steam = ByteStream::from(vec![0xDE, 0xAD]); let (output, _) = field.format_data(&byte_steam, 0).unwrap(); assert_eq!(output, "[222, 173]") } #[test] fn test_ccsds_apid_issue() { let field = Field {field_type: FieldType::UInt {bit_width: 11}, name: "test".to_string()}; let byte_steam = ByteStream::from(vec![0xe0, 0xa1, 0xc0, 0x00, 0x05, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05]); let (output, _) = field.format_data(&byte_steam, 5).unwrap(); assert_eq!(output, "1295") } }