Skip to main content

decode_meas3/
decode_meas3.rs

1use std::collections::HashMap;
2use std::env;
3use std::error::Error;
4use std::fs::File;
5
6use sbf_tools::{Meas3BlockSet, Meas3Decoder, SbfBlock, SbfReader};
7
8fn main() -> Result<(), Box<dyn Error>> {
9    let path = env::args()
10        .nth(1)
11        .ok_or("usage: cargo run --example decode_meas3 -- <path-to-file.sbf>")?;
12
13    let file = File::open(&path)?;
14    let reader = SbfReader::new(file);
15
16    let mut decoder = Meas3Decoder::new();
17    let mut current_tow: Option<u32> = None;
18    let mut bundles: HashMap<u8, Meas3BlockSet> = HashMap::new();
19
20    for block in reader {
21        let block = block?;
22
23        if let Some((tow_ms, antenna_id)) = meas3_epoch_key(&block) {
24            if current_tow != Some(tow_ms) {
25                flush_bundles(&mut bundles, &mut decoder)?;
26                current_tow = Some(tow_ms);
27            }
28            bundles.entry(antenna_id).or_default().insert_block(&block);
29            continue;
30        }
31
32        if matches!(block, SbfBlock::EndOfMeas(_)) {
33            flush_bundles(&mut bundles, &mut decoder)?;
34            current_tow = None;
35        }
36    }
37
38    flush_bundles(&mut bundles, &mut decoder)?;
39    Ok(())
40}
41
42fn meas3_epoch_key(block: &SbfBlock) -> Option<(u32, u8)> {
43    match block {
44        SbfBlock::Meas3Ranges(b) => Some((b.tow_ms(), b.antenna_id())),
45        SbfBlock::Meas3Cn0HiRes(b) => Some((b.tow_ms(), b.antenna_id())),
46        SbfBlock::Meas3Doppler(b) => Some((b.tow_ms(), b.antenna_id())),
47        SbfBlock::Meas3Pp(b) => Some((b.tow_ms(), b.antenna_id())),
48        SbfBlock::Meas3Mp(b) => Some((b.tow_ms(), b.antenna_id())),
49        _ => None,
50    }
51}
52
53fn flush_bundles(
54    bundles: &mut HashMap<u8, Meas3BlockSet>,
55    decoder: &mut Meas3Decoder,
56) -> Result<(), Box<dyn Error>> {
57    let mut antenna_ids: Vec<u8> = bundles.keys().copied().collect();
58    antenna_ids.sort_unstable();
59
60    for antenna_id in antenna_ids {
61        if let Some(block_set) = bundles.get(&antenna_id) {
62            if block_set.ranges.is_none() {
63                continue;
64            }
65
66            let epoch = decoder.decode_block_set(block_set)?;
67            println!(
68                "TOW {} WNc {} antenna {}: {} satellites, {} measurements",
69                epoch.tow_ms(),
70                epoch.wnc(),
71                epoch.antenna_id,
72                epoch.num_satellites(),
73                epoch.num_measurements()
74            );
75
76            for satellite in epoch.satellites.iter().take(4) {
77                let signal_summary = satellite
78                    .measurements
79                    .iter()
80                    .map(|meas| match meas.cn0_dbhz() {
81                        Some(cn0) => format!("{}:{cn0:.2}dB-Hz", meas.signal_type),
82                        None => meas.signal_type.to_string(),
83                    })
84                    .collect::<Vec<_>>()
85                    .join(", ");
86                println!("  {}  {}", satellite.sat_id, signal_summary);
87            }
88        }
89    }
90
91    bundles.clear();
92    Ok(())
93}