feat: ar2 work
Some checks are pending
Verify Latest Dependencies / Verify Latest Dependencies (push) Waiting to run
build and test / wxbox - latest (push) Waiting to run

This commit is contained in:
core 2025-05-18 22:07:46 -04:00
parent 99afa10c1f
commit 9ab0a77d64
Signed by: core
GPG key ID: FDBF740DADDCEECF
14 changed files with 668 additions and 20 deletions

1
.idea/wxbox.iml generated
View file

@ -19,6 +19,7 @@
<sourceFolder url="file://$MODULE_DIR$/crates/tiler/src" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/crates/ar2/src" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/crates/nommer/src" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/crates/ar2/benches" isTestSource="true" />
<excludeFolder url="file://$MODULE_DIR$/.tmp" />
<excludeFolder url="file://$MODULE_DIR$/temp" />
<excludeFolder url="file://$MODULE_DIR$/tmp" />

215
Cargo.lock generated
View file

@ -206,6 +206,12 @@ dependencies = [
"libc",
]
[[package]]
name = "anes"
version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299"
[[package]]
name = "anstream"
version = "0.6.18"
@ -652,6 +658,26 @@ dependencies = [
"serde",
]
[[package]]
name = "bincode"
version = "2.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "36eaf5d7b090263e8150820482d5d93cd964a81e4019913c972f4edcc6edb740"
dependencies = [
"bincode_derive",
"serde",
"unty",
]
[[package]]
name = "bincode_derive"
version = "2.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bf95709a440f45e986983918d0e8a1f30a9b1df04918fc828670606804ac3c09"
dependencies = [
"virtue",
]
[[package]]
name = "bit-set"
version = "0.8.0"
@ -785,6 +811,16 @@ dependencies = [
"libc",
]
[[package]]
name = "bzip2"
version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49ecfb22d906f800d4fe833b6282cf4dc1c298f5057ca0b5445e5c209735ca47"
dependencies = [
"bzip2-sys",
"libbz2-rs-sys",
]
[[package]]
name = "bzip2-sys"
version = "0.1.13+1.0.8"
@ -848,6 +884,12 @@ dependencies = [
"wayland-client",
]
[[package]]
name = "cast"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5"
[[package]]
name = "cc"
version = "1.2.17"
@ -910,6 +952,33 @@ dependencies = [
"windows-link",
]
[[package]]
name = "ciborium"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "42e69ffd6f0917f5c029256a24d0161db17cea3997d185db0d35926308770f0e"
dependencies = [
"ciborium-io",
"ciborium-ll",
"serde",
]
[[package]]
name = "ciborium-io"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "05afea1e0a06c9be33d539b876f1ce3692f4afea2cb41f740e7743225ed1c757"
[[package]]
name = "ciborium-ll"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "57663b653d948a338bfb3eeba9bb2fd5fcfaecb9e199e87e1eda4d9e8b240fd9"
dependencies = [
"ciborium-io",
"half",
]
[[package]]
name = "clap"
version = "4.5.35"
@ -1084,6 +1153,42 @@ dependencies = [
"cfg-if",
]
[[package]]
name = "criterion"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f2b12d017a929603d80db1831cd3a24082f8137ce19c69e6447f54f5fc8d692f"
dependencies = [
"anes",
"cast",
"ciborium",
"clap",
"criterion-plot",
"is-terminal",
"itertools 0.10.5",
"num-traits",
"once_cell",
"oorandom",
"plotters",
"rayon",
"regex",
"serde",
"serde_derive",
"serde_json",
"tinytemplate",
"walkdir",
]
[[package]]
name = "criterion-plot"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6b50826342786a51a89e2da3a28f1c32b06e387201bc2d19791f622c673706b1"
dependencies = [
"cast",
"itertools 0.10.5",
]
[[package]]
name = "crossbeam-channel"
version = "0.5.14"
@ -2025,6 +2130,12 @@ version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fbf6a919d6cf397374f7dfeeea91d974c7c0a7221d0d0f4f20d859d329e53fcc"
[[package]]
name = "hermit-abi"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f154ce46856750ed433c8649605bf7ed2de3bc35fd9d2a9f30cddd873c80cb08"
[[package]]
name = "hex"
version = "0.4.3"
@ -2087,7 +2198,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7e883defacf53960c7717d9e928dc8667be9501d9f54e6a8b7703d7a30320e9c"
dependencies = [
"async-trait",
"bincode",
"bincode 1.3.3",
"cacache",
"http",
"http-cache-semantics",
@ -2465,12 +2576,32 @@ version = "2.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "469fb0b9cefa57e3ef31275ee7cacb78f2fdca44e4765491884a2b119d4eb130"
[[package]]
name = "is-terminal"
version = "0.4.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e04d7f318608d35d4b61ddd75cbdaee86b023ebe2bd5a66ee0915f0bf93095a9"
dependencies = [
"hermit-abi 0.5.1",
"libc",
"windows-sys 0.59.0",
]
[[package]]
name = "is_terminal_polyfill"
version = "1.70.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf"
[[package]]
name = "itertools"
version = "0.10.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473"
dependencies = [
"either",
]
[[package]]
name = "itertools"
version = "0.12.1"
@ -2571,6 +2702,12 @@ version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "03087c2bad5e1034e8cace5926dec053fb3790248370865f5117a7d0213354c8"
[[package]]
name = "libbz2-rs-sys"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0864a00c8d019e36216b69c2c4ce50b83b7bd966add3cf5ba554ec44f8bebcf5"
[[package]]
name = "libc"
version = "0.2.171"
@ -2945,8 +3082,8 @@ version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2b2aef96f687e5774386f0dfe4e95bbf98b531559426e4b3bdddd27ca3d38488"
dependencies = [
"bincode",
"bzip2",
"bincode 1.3.3",
"bzip2 0.4.4",
"chrono",
"clap",
"log",
@ -2965,7 +3102,7 @@ version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dab458c09a15d9a133a7935a8024022db3cd3282549c2ed000f44c4ea392213a"
dependencies = [
"bincode",
"bincode 1.3.3",
"chrono",
"log",
"nexrad-model",
@ -3352,6 +3489,12 @@ version = "1.21.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d75b0bedcc4fe52caa0e03d9f1151a323e4aa5e2d78ba3580400cd3c9e2bc4bc"
[[package]]
name = "oorandom"
version = "11.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d6790f58c7ff633d8771f42965289203411a5e5c68388703c06e14f24770b41e"
[[package]]
name = "openssl"
version = "0.10.71"
@ -3535,6 +3678,34 @@ version = "0.3.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c"
[[package]]
name = "plotters"
version = "0.3.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5aeb6f403d7a4911efb1e33402027fc44f29b5bf6def3effcc22d7bb75f2b747"
dependencies = [
"num-traits",
"plotters-backend",
"plotters-svg",
"wasm-bindgen",
"web-sys",
]
[[package]]
name = "plotters-backend"
version = "0.3.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "df42e13c12958a16b3f7f4386b9ab1f3e7933914ecea48da7139435263a4172a"
[[package]]
name = "plotters-svg"
version = "0.3.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "51bae2ac328883f7acdfea3d66a7c35751187f870bc81f94563733a154d7a670"
dependencies = [
"plotters-backend",
]
[[package]]
name = "png"
version = "0.17.16"
@ -3566,7 +3737,7 @@ checksum = "a604568c3202727d1507653cb121dbd627a58684eb09a820fd746bee38b4442f"
dependencies = [
"cfg-if",
"concurrent-queue",
"hermit-abi",
"hermit-abi 0.4.0",
"pin-project-lite",
"rustix 0.38.44",
"tracing",
@ -3809,7 +3980,7 @@ dependencies = [
"built",
"cfg-if",
"interpolate_name",
"itertools",
"itertools 0.12.1",
"libc",
"libfuzzer-sys",
"log",
@ -4835,6 +5006,16 @@ dependencies = [
"zerovec",
]
[[package]]
name = "tinytemplate"
version = "1.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "be4d6b5f19ff7664e8c98d03e2139cb510db9b0a60b55f8e8709b689d939b6bc"
dependencies = [
"serde",
"serde_json",
]
[[package]]
name = "tinyvec"
version = "1.9.0"
@ -5154,6 +5335,12 @@ version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1"
[[package]]
name = "unty"
version = "0.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6d49784317cd0d1ee7ec5c716dd598ec5b4483ea832a2dced265471cc0f690ae"
[[package]]
name = "uom"
version = "0.36.0"
@ -5282,6 +5469,12 @@ version = "0.9.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
[[package]]
name = "virtue"
version = "0.0.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "051eb1abcf10076295e815102942cc58f9d5e3b4560e46e53c21e8ff6f3af7b1"
[[package]]
name = "walkdir"
version = "2.5.0"
@ -6265,10 +6458,17 @@ checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51"
name = "wxbox-ar2"
version = "0.1.0"
dependencies = [
"bincode 2.0.1",
"bzip2 0.5.2",
"criterion",
"nexrad-data",
"nexrad-decode",
"rayon",
"serde",
"thiserror 2.0.12",
"toml",
"tracing",
"wxbox-nommer",
]
[[package]]
@ -6319,6 +6519,9 @@ dependencies = [
[[package]]
name = "wxbox-nommer"
version = "0.1.0"
dependencies = [
"bincode 2.0.1",
]
[[package]]
name = "wxbox-pal"

View file

@ -4,7 +4,20 @@ version = "0.1.0"
edition = "2024"
[dependencies]
tracing = "0.1"
nexrad-decode = "0.1.1"
nexrad-data = "0.2"
serde = { version = "1", features = ["derive"]}
toml = "0.8"
toml = "0.8"
thiserror = "2"
wxbox-nommer = { path = "../nommer" }
bzip2 = { version = "0.5", default-features = false, features = ["libbz2-rs-sys"] }
rayon = { version = "1" }
bincode = { version = "2", features = ["serde"] }
[dev-dependencies]
criterion = { version = "0.5" }
[[bench]]
name = "parse_benchmark"
harness = false

View file

@ -0,0 +1,15 @@
use std::{env, fs};
use std::hint::black_box;
use std::time::Instant;
use criterion::{criterion_group, criterion_main, Criterion};
use wxbox_ar2::parse;
fn criterion_benchmark(c: &mut Criterion) {
let f = fs::read("/home/core/dl/KGWX20250518_165333_V06").unwrap();
c.bench_function("parse KGWX", |b| b.iter(|| {
parse(black_box(f.clone()))
}));
}
criterion_group!(benches, criterion_benchmark);
criterion_main!(benches);

View file

@ -5,6 +5,7 @@ use nexrad_decode::result::Error;
use std::fmt::Debug;
pub mod sites;
pub mod parser;
pub struct Scan {
pub coverage_pattern_number: u16,

View file

@ -1,19 +1,13 @@
use std::{env, fs};
use std::fs::File;
use std::time::Instant;
use wxbox_ar2::parse;
use wxbox_ar2::parser::Ar2Parser;
fn main() {
let f = fs::read(env::args().nth(1).unwrap()).unwrap();
let f = parse(f).unwrap();
println!(
"{:?}",
f.sweeps
.get(0)
.unwrap()
.radials
.get(0)
.unwrap()
.reflectivity
.as_ref()
.unwrap()
);
let start = Instant::now();
let p = parse(f);
let elapsed = start.elapsed();
println!("{:?}", elapsed);
}

View file

@ -0,0 +1,11 @@
use thiserror::Error;
#[derive(Debug, Error)]
pub enum Archive2Error {
#[error("i/o error: {0}")]
IoError(#[from] std::io::Error),
#[error("invalid tape filename: {0}")]
InvalidTapeFilename(String),
#[error("bincode decode error: {0}")]
Bincode(#[from] bincode::error::DecodeError)
}

View file

@ -0,0 +1,33 @@
use serde::Deserialize;
#[derive(Deserialize, Debug)]
pub struct Message2 {
pub rda_status: u16,
pub operability_status: u16,
pub control_status: u16,
pub aux_power_generator_state: u16,
pub avg_tx_power: u16,
pub horiz_ref_calib_corr: u16,
pub data_tx_enabled: u16,
pub volume_coverage_pattern_number: u16,
pub rda_control_auth: u16,
pub rda_build: u16,
pub operational_mode: u16,
pub super_res_status: u16,
pub clutter_mitigation_decision_status: u16,
pub avset_status: u16,
pub rda_alarm_summary: u16,
pub command_ack: u16,
pub channel_control_status: u16,
pub spot_blanking_status: u16,
pub bypass_map_gen_date: u16,
pub bypass_map_gen_time: u16,
pub clutter_filter_map_gen_date: u16,
pub clutter_filter_map_gen_time: u16,
pub vert_ref_calib_corr: u16,
pub transition_pwr_source_status: u16,
pub rms_control_status: u16,
pub performance_check_status: u16,
pub alarm_codes: u16,
pub spares: [u8; 14]
}

View file

@ -0,0 +1,99 @@
use std::io::{Cursor, Read};
use bincode::config::Configuration;
use serde::Deserialize;
use wxbox_nommer::NomReader;
use crate::parser::error::Archive2Error;
use crate::parser::message2::Message2;
use crate::parser::types::{ElevationData, GenericDataMoment, MessageHeader, RadialData, VolumeData};
#[derive(Deserialize, Debug)]
pub struct Message31Header {
pub radar_identifier: [u8; 4],
pub collection_time: u32,
pub collection_date: u16,
pub azimuth_number: u16,
pub azimuth_angle: f32,
pub compression_indicator: u8,
pub spare: u8,
pub radial_length: u16,
pub azimuth_resolution_spacing_code: u8,
pub radial_status: u8,
pub elevation_number: u8,
pub cut_sector_number: u8,
pub elevation_angle: f32,
pub radial_spot_blanking_status: u8,
pub azimuth_indexing_mode: u8,
pub data_block_count: u16
}
pub struct Message31 {
pub header: Message31Header,
}
impl Message31 {
pub fn decode(r: &mut NomReader<Cursor<&mut Vec<u8>>>) -> Result<Self, Archive2Error> {
let position = r.mut_inner().position();
let (h, read): (Message31Header, usize) = bincode::serde::decode_from_reader(&mut *r, bincode::config::standard().with_big_endian().with_fixed_int_encoding())?;
let mut data_block_pointers: Vec<u32> = vec![];
for _ in 0..h.data_block_count {
let ptr = r.read_u32()?;
if ptr == 0x52_56_4F_4C {
// we've hit data, stop reading pointers
let back = r.mut_inner().position()-4;
r.mut_inner().set_position(back);
break;
}
if ptr != 0 {
data_block_pointers.push(ptr);
}
}
println!("actually got {} pointers", data_block_pointers.len());
assert_eq!(data_block_pointers.len(), h.data_block_count as usize);
for pointer in data_block_pointers {
r.mut_inner().set_position(position + pointer as u64);
let data_block_type: char;
let data_name: String;
let data_block_info_raw = r.read_n(4)?;
let mut data_block_info = String::from_utf8_lossy(&data_block_info_raw).to_string();
let mut data_block_info = data_block_info.chars();
let data_block_info_2 = String::from_utf8_lossy(&data_block_info_raw).to_string();
data_block_type = data_block_info.next().unwrap();
data_name = (&data_block_info_2[1..]).to_string();
match data_name.as_str() {
"VOL" => {
let (volume_data_block, read): (VolumeData, usize) = bincode::serde::decode_from_reader(&mut *r, bincode::config::standard().with_big_endian().with_fixed_int_encoding())?;
},
"ELV" => {
let (elev_data_block, read): (ElevationData, usize) = bincode::serde::decode_from_reader(&mut *r, bincode::config::standard().with_big_endian().with_fixed_int_encoding())?;
},
"RAD" => {
let (radial_data_block, read): (RadialData, usize) = bincode::serde::decode_from_reader(&mut *r, bincode::config::standard().with_big_endian().with_fixed_int_encoding())?;
},
"REF" | "VEL" | "CFP" | "SW " | "ZDR" | "PHI" | "RHO" => {
let (data_moment, read): (GenericDataMoment, usize) = bincode::serde::decode_from_reader(&mut *r, bincode::config::standard().with_big_endian().with_fixed_int_encoding())?;
// LDM is the amount of space in bytes required for a data moment
// array and equals ((NG * DWS) / 8) where NG is the number of gates
// at the gate spacing resolution specified and DWS is the number of
// bits stored for each gate (DWS is always a multiple of 8).
let ldm = data_moment.number_data_moment_gates * data_moment.data_word_size as u16 / 8;
let data = r.read_n(ldm as usize)?;
},
_ => {
println!("unknown data block name `{data_name}`")
}
}
}
r.mut_inner().set_position(position+h.radial_length as u64);
Ok(Self {
header: h,
})
}
}

View file

@ -0,0 +1,176 @@
mod error;
mod types;
mod message2;
mod message31;
use std::fmt::{Debug, Formatter};
use std::io::{ErrorKind, Read, Cursor};
use bzip2::read::{BzDecoder};
use std::marker::PhantomData;
use bincode::config::Configuration;
use wxbox_nommer::NomReader;
use crate::parser::error::Archive2Error;
use rayon::prelude::*;
use crate::parser::message2::Message2;
use crate::parser::message31::Message31;
use crate::parser::types::MessageHeader;
#[derive(Debug)]
pub struct VolumeHeaderRecord<R: Read> {
pub tape_filename: String,
pub extension_number: String,
pub date: u32,
pub time: u32,
pub icao: String,
_p: PhantomData<R>
}
impl<R: Read> VolumeHeaderRecord<R> {
pub fn parse(r: &mut NomReader<R>) -> Result<Self, Archive2Error> {
let tape_filename_bytes = r.read_n(9)?;
let tape_filename = String::from_utf8_lossy(&tape_filename_bytes);
match tape_filename.as_ref() {
"AR2V0002." | "AR2V0003." | "AR2V0004." | "AR2V0005." | "AR2V0006." | "AR2V0007." => (),
_ => {return Err(Archive2Error::InvalidTapeFilename(tape_filename.to_string()))}
}
let extension_number_bytes = r.read_n(3)?;
let extension_number = String::from_utf8_lossy(&extension_number_bytes);
let date = r.read_u32()?;
let time = r.read_u32()?;
let icao_bytes = r.read_n(4)?;
let icao = String::from_utf8_lossy(&icao_bytes);
Ok(Self {
tape_filename: tape_filename.to_string(),
extension_number: extension_number.to_string(),
date,
time,
icao: icao.to_string(),
_p: PhantomData
})
}
}
pub struct LdmCompressedRecord {
pub block_size: usize,
pub reader: BzDecoder<Cursor<Vec<u8>>>,
}
impl Debug for LdmCompressedRecord {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f,"LdmCompressedRecord(uc{}b)", self.block_size)
}
}
pub struct LdmDecompressedRecord {
pub data: Vec<u8>
}
impl Debug for LdmDecompressedRecord {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f,"LdmDecompressedRecord(dc{}b)", self.data.len())
}
}
#[derive(Debug)]
pub struct Archive2<R: Read> {
pub vhr: VolumeHeaderRecord<R>,
pub records: Vec<LdmDecompressedRecord>
}
pub struct Ar2Parser<R: Read> {
pub r: NomReader<R>
}
impl<R: Read> Ar2Parser<R> {
pub fn new(r: R) -> Self {
Self { r: NomReader::new(r) }
}
pub fn parse(mut self) -> Result<Archive2<R>, Archive2Error> {
let vhr = VolumeHeaderRecord::parse(&mut self.r)?;
// identify and extract (but do not parse) the ldm compressed records
let mut ldm_records = vec![];
loop {
let control_word = match self.r.read_i32() {
Ok(w) => w,
Err(e) if e.kind() == ErrorKind::UnexpectedEof => { break; },
e => e?
};
let block_size = control_word.abs() as usize;
let block_contents = self.r.read_n(block_size)?;
ldm_records.push(LdmCompressedRecord {
block_size,
reader: BzDecoder::new(Cursor::new(block_contents))
});
}
let mut decompressed_records: Vec<LdmDecompressedRecord> = ldm_records.par_iter_mut()
.map(|u| {
let mut data = vec![];
u.reader.read_to_end(&mut data);
LdmDecompressedRecord {
data
}
})
.collect();
let messages: Vec<Result<Vec<Vec<u8>>, Archive2Error>> = decompressed_records.iter_mut()
.map(|u| {
let mut reader = NomReader::new(Cursor::new(&mut u.data));
let mut raw_messages = vec![];
loop {
// skip 12 bytes for legacy compliance
let _n = reader.read_n(12)?;
let header = match MessageHeader::decode(&mut reader) {
Ok(h) => h,
Err(e) if e.kind() == ErrorKind::UnexpectedEof => { break; }
e => e?
};
match header.message_type {
2 => {
let body = reader.read_n(2432 - 28)?;
let (m2, read): (Message2, usize) = bincode::serde::decode_from_slice(&body, bincode::config::standard().with_big_endian().with_fixed_int_encoding())?;
},
3 => {
let body = reader.read_n(2432 - 28)?;
},
31 => {
let msg = Message31::decode(&mut reader)?;
},
15 => {
let _ = reader.read_n(2432 - 28)?;
},
32 => {
let _ = reader.read_n(2432 - 28)?;
},
18 => {
let _ = reader.read_n(2432 - 28)?;
},
5 => {
let _ = reader.read_n(2432 - 28)?;
},
_ => {
if header.message_type != 0 {
panic!("unhandled message: {}", header.message_type);
}
let _ = reader.read_n(2432 - 28)?;
}
}
}
Ok(raw_messages)
})
.collect();
for msg in messages {
msg?;
}
Ok(Archive2 {
vhr,
records: decompressed_records
})
}
}

View file

@ -0,0 +1,80 @@
use std::io::Cursor;
use serde::Deserialize;
use wxbox_nommer::NomReader;
#[derive(Debug)]
pub struct MessageHeader {
pub message_size: u16,
pub rda_redundant_channel: u8,
pub message_type: u8,
pub id_sequence_number: u16,
pub julian_date: u16,
pub millis_of_day: u32,
pub num_message_segments: u16,
pub message_segment_num: u16
}
impl MessageHeader {
pub fn decode(r: &mut NomReader<Cursor<&mut Vec<u8>>>) -> Result<Self, std::io::Error> {
Ok(Self {
message_size: r.read_u16()?,
rda_redundant_channel: r.read_u8()?,
message_type: r.read_u8()?,
id_sequence_number: r.read_u16()?,
julian_date: r.read_u16()?,
millis_of_day: r.read_u32()?,
num_message_segments: r.read_u16()?,
message_segment_num: r.read_u16()?,
})
}
}
#[derive(Deserialize, Debug)]
pub struct VolumeData {
pub LRTUP: u16,
pub version_major: u8,
pub version_minor: u8,
pub lat: f32,
pub long: f32,
pub site_height: u16,
pub feedhorn_height: u16,
pub calibration_constant: f32,
pub shvtx_power_hor: f32,
pub shvtx_power_ver: f32,
pub system_differential_reflectivity: f32,
pub initial_system_differential_phase: f32,
pub vcp_no: u16,
pub processing_status: u16
}
#[derive(Deserialize, Debug)]
pub struct ElevationData {
pub LRTUP: u16,
pub ATMOS: [u8; 2],
pub calibration_constant: f32
}
#[derive(Deserialize, Debug)]
pub struct RadialData {
pub LRTUP: u16,
pub unambiguous_range: u16,
pub noise_level_horz: f32,
pub noise_level_vert: f32,
pub nyquist_velocity: u16,
pub radial_flags: u16,
pub calib_const_horz_chan: f32,
pub calib_const_vert_chan: f32
}
#[derive(Deserialize, Debug)]
pub struct GenericDataMoment {
pub _reserved: u32,
pub number_data_moment_gates: u16,
pub data_moment_range: u16,
pub data_moment_range_sample_interval: u16,
pub TOVER: u16,
pub snr_threshold: u16,
pub control_flags: u8,
pub data_word_size: u8,
pub scale: f32,
pub offset: f32
}

View file

@ -4,3 +4,4 @@ version = "0.1.0"
edition = "2024"
[dependencies]
bincode = "2"

View file

@ -1,4 +1,6 @@
use std::io::Read;
use bincode::de::read::Reader;
use bincode::error::DecodeError;
#[derive(Debug)]
pub struct NomReader<R: Read> {
@ -8,6 +10,9 @@ impl<R: Read> NomReader<R> {
pub fn new(inner: R) -> NomReader<R> {
Self { inner }
}
pub fn mut_inner(&mut self) -> &mut R {
&mut self.inner
}
pub fn read_u8(&mut self) -> Result<u8, std::io::Error> {
let mut buf = [0u8; 1];
@ -45,3 +50,17 @@ impl<R: Read> NomReader<R> {
Ok(f32::from_be_bytes(buf))
}
}
impl<R: Read> Read for NomReader<R> {
fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
self.inner.read(buf)
}
}
impl<R: Read> Reader for NomReader<R> {
fn read(&mut self, bytes: &mut [u8]) -> Result<(), DecodeError> {
self.read_exact(bytes).map_err(|u| DecodeError::Io {
inner: u,
additional: 0,
})
}
}

View file

@ -1,6 +1,7 @@
use serde::Deserialize;
#[derive(Deserialize, Debug)]
#[allow(non_snake_case)] // xml
pub struct ListBucketResult {
pub Name: String,
pub Prefix: String,
@ -10,6 +11,7 @@ pub struct ListBucketResult {
pub Contents: Option<Vec<ListBucketResultContents>>,
}
#[derive(Deserialize, Debug)]
#[allow(non_snake_case)] // xml
pub struct ListBucketResultContents {
pub Key: String,
pub LastModified: String