#[cfg(feature = "std")] pub use stdmod::*; pub use satrs_core::res_code::ResultU16; use serde::{Deserialize, Serialize}; use serde_hex::{SerHex, StrictCapPfx}; #[derive(Debug, Copy, Clone, Serialize)] pub struct ResultU16Info { pub name: &'static str, pub result: &'static ResultU16, pub group_str: &'static str, pub info: &'static str, } impl ResultU16Info { pub const fn const_new( name: &'static str, result: &'static ResultU16, group_str: &'static str, info: &'static str, ) -> Self { Self { name, result, group_str, info, } } } #[derive(Debug, Serialize, Deserialize)] pub struct ResultU16InfoSerializable { #[serde(with = "SerHex::")] raw: u16, #[serde(with = "SerHex::")] group_id: u8, #[serde(with = "SerHex::")] unique_id: u8, name: &'static str, group_str: &'static str, info: &'static str, } impl From for ResultU16InfoSerializable { fn from(v: ResultU16Info) -> Self { Self { raw: v.result.raw(), group_id: v.result.group_id(), unique_id: v.result.unique_id(), name: v.name, group_str: v.group_str, info: v.info, } } } #[cfg(feature = "std")] pub mod stdmod { use super::*; use std::fs::File; use std::io; pub fn print_resultcodes_as_csv( writer_builder: csv::WriterBuilder, codes: &[ResultU16Info], ) -> Result<(), csv::Error> { let mut wtr = writer_builder.from_writer(io::stdout()); for result in codes { wtr.serialize(ResultU16InfoSerializable::from(*result))?; } wtr.flush()?; Ok(()) } pub fn write_resultcodes_to_csv( writer_builder: csv::WriterBuilder, results: &[ResultU16Info], file: File, ) -> Result<(), csv::Error> { let mut wtr = writer_builder.from_writer(file); for result_code in results { wtr.serialize(ResultU16InfoSerializable::from(*result_code))?; } wtr.flush()?; Ok(()) } } #[cfg(test)] mod tests { use super::*; use std::fs::File; use std::io::{BufRead, BufReader}; use std::path::Path; // Special solution for this crate because the code generated by a macro will use // satrs_mib::res_code::* use crate as satrs_mib; use satrs_core::res_code::ResultU16; use satrs_mib::resultcode; #[derive(Debug)] #[allow(dead_code)] pub enum GroupId { Tmtc = 0, } #[resultcode] pub const INVALID_PUS_SERVICE: ResultU16 = ResultU16::const_new(GroupId::Tmtc as u8, 0); #[resultcode] pub const INVALID_PUS_SUBSERVICE: ResultU16 = ResultU16::const_new(GroupId::Tmtc as u8, 1); #[resultcode(info = "Not enough data inside the TC application data field")] pub const NOT_ENOUGH_APP_DATA: ResultU16 = ResultU16::const_new(GroupId::Tmtc as u8, 2); pub const TMTC_RESULTS: &[ResultU16Info] = &[ INVALID_PUS_SERVICE_EXT, INVALID_PUS_SUBSERVICE_EXT, NOT_ENOUGH_APP_DATA_EXT, ]; const CSV_NAME: &'static str = "dummy.csv"; #[test] fn test_printout() { let mut wtrb = csv::WriterBuilder::new(); wtrb.delimiter(';' as u8); print_resultcodes_as_csv(wtrb, TMTC_RESULTS).expect("Priting result codes failed"); } #[test] fn test_csv_export() { let csvpath = Path::new(CSV_NAME); let mut wtrb = csv::WriterBuilder::new(); let file = File::create(csvpath).expect("Creating CSV file failed"); wtrb.delimiter(';' as u8); write_resultcodes_to_csv(wtrb, TMTC_RESULTS, file).expect("CSV export failed"); assert!(csvpath.exists()); let file = File::open(csvpath).expect("Opening CSV file failed"); let buf_reader = BufReader::new(file); for (idx, line) in buf_reader.lines().enumerate() { match idx { 0 => { assert!(line.is_ok()); let line = line.unwrap(); assert_eq!(line, "raw;group_id;unique_id;name;group_str;info"); } 1 => { assert!(line.is_ok()); let line = line.unwrap(); assert_eq!(line, "0x0000;0x00;0x00;INVALID_PUS_SERVICE;;"); } 2 => { assert!(line.is_ok()); let line = line.unwrap(); assert_eq!(line, "0x0001;0x00;0x01;INVALID_PUS_SUBSERVICE;;"); } 3 => { assert!(line.is_ok()); let line = line.unwrap(); assert_eq!(line, "0x0002;0x00;0x02;NOT_ENOUGH_APP_DATA;;Not enough data inside the TC application data field"); } _ => (), } } std::fs::remove_file(Path::new("dummy.csv")).expect("Removing dummy csv failed"); } }