Skip to content

Commit

Permalink
more uniform framing tests
Browse files Browse the repository at this point in the history
  • Loading branch information
bmflynn committed Jan 30, 2025
1 parent 151b707 commit c7fad53
Show file tree
Hide file tree
Showing 18 changed files with 355 additions and 103 deletions.
14 changes: 10 additions & 4 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -1,4 +1,10 @@
lib/tests/fixtures/viirs_packets.dat filter=lfs diff=lfs merge=lfs -text
lib/tests/fixtures/snpp_7cadus_2vcids.dat filter=lfs diff=lfs merge=lfs -text
lib/tests/fixtures/overpass_snpp_2017_7min.dat filter=lfs diff=lfs merge=lfs -text
lib/tests/fixtures/snpp_synchronized_cadus.dat filter=lfs diff=lfs merge=lfs -text
ccsds-lib/tests/fixtures/viirs_merge1.dat filter=lfs diff=lfs merge=lfs -text
ccsds-lib/tests/fixtures/viirs_merge2.dat filter=lfs diff=lfs merge=lfs -text
ccsds-lib/tests/fixtures/viirs_packets.dat filter=lfs diff=lfs merge=lfs -text
ccsds-lib/tests/fixtures/cadu/aqua.20241206T175646.dat filter=lfs diff=lfs merge=lfs -text
ccsds-lib/tests/fixtures/cadu/gcomw1.20241206T165853.dat filter=lfs diff=lfs merge=lfs -text
ccsds-lib/tests/fixtures/cadu/metopb.20241206T152751.dat filter=lfs diff=lfs merge=lfs -text
ccsds-lib/tests/fixtures/cadu/metopc.20241206T162917.dat filter=lfs diff=lfs merge=lfs -text
ccsds-lib/tests/fixtures/cadu/noaa20.20241206T162710.dat filter=lfs diff=lfs merge=lfs -text
ccsds-lib/tests/fixtures/cadu/noaa21.20241206T171609.dat filter=lfs diff=lfs merge=lfs -text
ccsds-lib/tests/fixtures/cadu/npp.20241206T173815.dat filter=lfs diff=lfs merge=lfs -text
181 changes: 179 additions & 2 deletions ccsds-cmd/src/frame.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,17 @@
use anyhow::{bail, Context, Result};
use ccsds::{
framing::{DefaultDerandomizer, DefaultReedSolomon, FrameDecoder, Synchronizer, ASM},
framing::{
DefaultDerandomizer, DefaultReedSolomon, FrameDecoder, Integrity, Synchronizer, ASM,
},
prelude::Vcid,
};
use handlebars::handlebars_helper;
use serde::Serialize;
use spacecrafts::FramingConfig;
use std::{
collections::HashMap,
fs::File,
io::{BufReader, Write},
io::{stdout, BufReader, Write},
path::Path,
};
use tracing::{debug, warn};
Expand Down Expand Up @@ -91,3 +96,175 @@ pub fn frame(

Ok(())
}

#[derive(Debug, Clone)]
pub enum Format {
Json,
Text,
}

impl clap::ValueEnum for Format {
fn value_variants<'a>() -> &'a [Self] {
&[Self::Json, Self::Text]
}

fn to_possible_value(&self) -> Option<clap::builder::PossibleValue> {
match self {
Self::Json => Some(clap::builder::PossibleValue::new("json")),
Self::Text => Some(clap::builder::PossibleValue::new("text")),
}
}
}

#[derive(Default, Debug, Clone, Serialize)]
struct Summary {
total_frames: usize,
total_bytes: usize,
missing_frames: usize,

corrected: usize,
uncorrectable: usize,
ok: usize,
error: usize,
not_performed: usize,
}

#[derive(Debug, Clone, Serialize)]
struct Info {
filename: String,
summary: Summary,
vcids: Vec<(Vcid, Summary)>,
}

pub fn info(config: FramingConfig, fpath: &Path, format: &Format) -> Result<()> {
let src = BufReader::new(File::open(fpath).context("opening source")?);
let sync = Synchronizer::new(src, &ASM, config.codeblock_len());
let mut framer = FrameDecoder::new();
if config.pseudo_noise.is_some() {
framer = framer.with_derandomization(Box::new(DefaultDerandomizer))
}
if let Some(rs_config) = config.reed_solomon {
let rs = DefaultReedSolomon::new(rs_config.interleave);
framer = framer.with_integrity(Box::new(rs));
}
let frames = framer
.decode(sync.into_iter().filter_map(Result::ok))
.filter_map(Result::ok);

let mut info = Info {
filename: fpath.file_name().unwrap().to_string_lossy().to_string(),
summary: Summary::default(),
vcids: Vec::default(),
};
let mut vcids: HashMap<Vcid, Summary> = HashMap::default();
for frame in frames {
info.summary.total_frames += 1;
info.summary.total_bytes += frame.frame.data.len();

let sum = vcids.entry(frame.frame.header.vcid).or_default();
sum.total_frames += 1;
sum.total_bytes += frame.frame.data.len();
match frame.integrity {
Some(integrity) => match integrity {
Integrity::Ok | Integrity::NoErrors => {
sum.ok += 1;
info.summary.ok += 1;
}
Integrity::Corrected => {
sum.corrected += 1;
info.summary.corrected += 1;
}
Integrity::HasErrors => {
sum.error += 1;
info.summary.error += 1;
}
Integrity::Uncorrectable => {
sum.uncorrectable += 1;
info.summary.uncorrectable += 1;
}
},
None => {
sum.not_performed += 1;
info.summary.not_performed += 1;
}
}
}

info.vcids = vcids.into_iter().collect();
info.vcids.sort_by_key(|(k, _)| *k);

match format {
Format::Json => {
serde_json::to_writer_pretty(stdout(), &info).context("serializing to json")
}
Format::Text => {
let data = render_text(&info).context("serializing info")?;
stdout()
.write_all(str::as_bytes(&data))
.context("writing to stdout")
}
}
}

fn render_text(info: &Info) -> Result<String> {
let mut hb = handlebars::Handlebars::new();

handlebars_helper!(right_pad: |num: u64, v: Json| {
let v = match v {
serde_json::Value::String(s) => s.to_owned(),
serde_json::Value::Null => String::new(),
_ => v.to_string()
};
let mut num: usize = usize::try_from(num).unwrap();
if num < v.len() {
num = v.len();
}
let mut s = v.to_string();
let padding = num - v.len();
for _ in 0..padding {
s.push(' ');
}
s
});
hb.register_helper("rpad", Box::new(right_pad));
handlebars_helper!(left_pad: |num: u64, v: Json| {
let v = match v {
serde_json::Value::String(s) => s.to_owned(),
serde_json::Value::Null => String::new(),
_ => v.to_string()
};
let mut num: usize = usize::try_from(num).unwrap();
if num < v.len() {
num = v.len();
}
let mut s = String::new();
let padding = num - v.len();
for _ in 0..padding {
s.push(' ');
}
s.push_str(&v);
s
});
hb.register_helper("lpad", Box::new(left_pad));
assert!(hb.register_template_string("info", TEXT_TEMPLATE).is_ok());

hb.render("info", &info).context("rendering text")
}

const TEXT_TEMPLATE: &str = r#"{{ filename }}
===============================================================================================
VCIDs: {{ #each vcids }}{{ this.[0] }}{{ #if @last }}{{ else }}, {{ /if }}{{ /each }}
Count: {{ summary.total_frames }}
Missing: {{ summary.missing_frames }}
Integrity:
Ok: {{ summary.ok }}
Corrected: {{ summary.corrected }}
Failed: {{ summary.uncorrectable }}
Error: {{ summary.error }}
NotChecked: {{ summary.not_performed }}
-----------------------------------------------------------------------------------------------
VCID Count Missing Bytes Ok Corrected Failed Error NotChecked
-----------------------------------------------------------------------------------------------
{{ #each vcids }}{{ lpad 4 this.[0] }} {{ #with this.[1] }}{{ lpad 8 total_frames }} {{ lpad 8 missing_frames }} {{ lpad 15 total_bytes }} {{ lpad 8 ok }} {{ lpad 8 corrected }} {{ lpad 8 uncorrectable }} {{ lpad 8 error }} {{ lpad 8 not_performed }}{{ /with }}
{{/each }}
"#;
23 changes: 23 additions & 0 deletions ccsds-cmd/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,19 @@ enum FramingCommands {
/// Input CADU file to synchronize
input: PathBuf,
},

/// Summarize contained frames
Info {
/// Output format
#[arg(short, long, default_value = "text")]
format: frame::Format,

/// Input raw CADU file.
input: PathBuf,

/// Spacecraft identifier used to lookup framing config.
scid: Scid,
},
}

#[derive(Subcommand)]
Expand Down Expand Up @@ -409,6 +422,16 @@ fn main() -> Result<()> {

frame::frame(input, &output, sc.framing_config, include, exclude)
}
FramingCommands::Info {
format,
input,
scid,
} => {
let Some(sc) = Spacecrafts::default().lookup(*scid) else {
bail!("No spacecraft config found for {scid}");
};
frame::info(sc.framing_config, input, format)
}
},
}
}
1 change: 1 addition & 0 deletions ccsds-lib/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ md-5 = "0.10.6"
rand = "0.8.5"
tempfile = "3.9.0"
criterion = { version = "0.5.1", features = ["html_reports"] }
test-case = "3.3.1"

[build-dependencies]
spacecrafts.workspace = true
Expand Down
24 changes: 0 additions & 24 deletions ccsds-lib/src/framing/decoder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -410,28 +410,4 @@ mod tests {
);
assert!(!mpdu.has_header());
}

#[test]
fn test_decode_frames() {
let fpath = fixture_path("tests/fixtures/snpp_7cadus_2vcids.dat");
let reader = fs::File::open(&fpath).unwrap_or_else(|_| panic!("{fpath:?} to exist"));
let blocks: Vec<Vec<u8>> = Synchronizer::new(reader, &ASM, 1020)
.into_iter()
.map(|a| a.unwrap())
.collect();
assert_eq!(blocks.len(), 7);

let frames: Vec<Result<DecodedFrame>> = decode_frames_rs(blocks.into_iter(), 4).collect();

assert_eq!(frames.len(), 7, "expected frame count doesn't match");
for (idx, df) in frames.into_iter().enumerate() {
let df = df.unwrap();
assert_eq!(df.frame.header.scid, 157);
if idx < 3 {
assert_eq!(df.frame.header.vcid, 16);
} else {
assert_eq!(df.frame.header.vcid, 6);
}
}
}
}
8 changes: 8 additions & 0 deletions ccsds-lib/tests/common/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
use std::path::PathBuf;

pub fn fixture_path(name: &str) -> PathBuf {
let mut path = PathBuf::from(std::env::var("CARGO_MANIFEST_DIR").unwrap());
path.push("tests/fixtures");
path.push(name);
path
}
3 changes: 3 additions & 0 deletions ccsds-lib/tests/fixtures/cadu/aqua.20241206T175646.dat
Git LFS file not shown
3 changes: 3 additions & 0 deletions ccsds-lib/tests/fixtures/cadu/gcomw1.20241206T165853.dat
Git LFS file not shown
3 changes: 3 additions & 0 deletions ccsds-lib/tests/fixtures/cadu/metopb.20241206T152751.dat
Git LFS file not shown
3 changes: 3 additions & 0 deletions ccsds-lib/tests/fixtures/cadu/metopc.20241206T162917.dat
Git LFS file not shown
3 changes: 3 additions & 0 deletions ccsds-lib/tests/fixtures/cadu/noaa20.20241206T162710.dat
Git LFS file not shown
3 changes: 3 additions & 0 deletions ccsds-lib/tests/fixtures/cadu/noaa21.20241206T171609.dat
Git LFS file not shown
3 changes: 3 additions & 0 deletions ccsds-lib/tests/fixtures/cadu/npp.20241206T173815.dat
Git LFS file not shown
Binary file modified ccsds-lib/tests/fixtures/viirs_merge1.dat
Binary file not shown.
Binary file modified ccsds-lib/tests/fixtures/viirs_merge2.dat
Binary file not shown.
Binary file modified ccsds-lib/tests/fixtures/viirs_packets.dat
Binary file not shown.
Loading

0 comments on commit c7fad53

Please sign in to comment.