feat: ar2 work
This commit is contained in:
parent
99afa10c1f
commit
9ab0a77d64
14 changed files with 668 additions and 20 deletions
1
.idea/wxbox.iml
generated
1
.idea/wxbox.iml
generated
|
@ -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
215
Cargo.lock
generated
|
@ -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"
|
||||
|
|
|
@ -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
|
15
crates/ar2/benches/parse_benchmark.rs
Normal file
15
crates/ar2/benches/parse_benchmark.rs
Normal 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);
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
11
crates/ar2/src/parser/error.rs
Normal file
11
crates/ar2/src/parser/error.rs
Normal 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)
|
||||
}
|
33
crates/ar2/src/parser/message2.rs
Normal file
33
crates/ar2/src/parser/message2.rs
Normal 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]
|
||||
}
|
99
crates/ar2/src/parser/message31.rs
Normal file
99
crates/ar2/src/parser/message31.rs
Normal 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,
|
||||
})
|
||||
}
|
||||
}
|
176
crates/ar2/src/parser/mod.rs
Normal file
176
crates/ar2/src/parser/mod.rs
Normal 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
|
||||
})
|
||||
}
|
||||
}
|
80
crates/ar2/src/parser/types.rs
Normal file
80
crates/ar2/src/parser/types.rs
Normal 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
|
||||
}
|
|
@ -4,3 +4,4 @@ version = "0.1.0"
|
|||
edition = "2024"
|
||||
|
||||
[dependencies]
|
||||
bincode = "2"
|
|
@ -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,
|
||||
})
|
||||
}
|
||||
}
|
|
@ -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
|
||||
|
|
Loading…
Add table
Reference in a new issue