work
This commit is contained in:
parent
33ca20410e
commit
b813294ea5
|
@ -6,16 +6,19 @@ use std::fmt::{Display, Formatter};
|
|||
use std::io;
|
||||
use std::io::{Cursor, Read, Seek, SeekFrom};
|
||||
use std::str::Utf8Error;
|
||||
use log::{debug, trace};
|
||||
use log::{debug, info, Record, trace, warn};
|
||||
use crate::bzip::BzipDecoder;
|
||||
use crate::message::{LEGACY_CTM_HEADER_LEN, MESSAGE_BODY_SIZE, MESSAGE_HEADER_SIZE, MessageHeader};
|
||||
use crate::message::{FromBody, LEGACY_CTM_HEADER_LEN, Message, MESSAGE_BODY_SIZE, MESSAGE_HEADER_SIZE, MessageHeader};
|
||||
use crate::message2::Msg02RDAStatusData;
|
||||
|
||||
pub mod message;
|
||||
pub mod bzip;
|
||||
pub mod message2;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Nexrad2Chunk {
|
||||
pub volume_header_record: VolumeHeaderRecord,
|
||||
pub chunks: Vec<Vec<Message>>
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
|
@ -106,10 +109,18 @@ pub fn parse_nx2_chunk(cursor: &mut (impl Read + Seek)) -> Result<Nexrad2Chunk,
|
|||
|
||||
trace!("Loaded - {:#?}", header);
|
||||
|
||||
let mut records: Vec<Vec<Message>> = vec![];
|
||||
|
||||
loop {
|
||||
// LDM records
|
||||
let mut ldm_size_bytes = [0u8; 4];
|
||||
cursor.read_exact(&mut ldm_size_bytes).map_err(|e| NexradParseError::LdmReadFailed(e))?;
|
||||
match cursor.read_exact(&mut ldm_size_bytes) {
|
||||
Ok(_) => (),
|
||||
Err(e) if matches!(e.kind(), io::ErrorKind::UnexpectedEof) => {
|
||||
break;
|
||||
},
|
||||
Err(e) => return Err(NexradParseError::LdmReadFailed(e))
|
||||
}
|
||||
let ldm_size = i32::from_be_bytes(ldm_size_bytes).abs() as usize;
|
||||
|
||||
trace!("Reading LDM record - {} bytes compressed", ldm_size);
|
||||
|
@ -132,7 +143,7 @@ pub fn parse_nx2_chunk(cursor: &mut (impl Read + Seek)) -> Result<Nexrad2Chunk,
|
|||
|
||||
let mut decompressed = Cursor::new(decompressed_buf);
|
||||
|
||||
let mut messages = 0;
|
||||
let mut messages = vec![];
|
||||
|
||||
loop {
|
||||
decompressed.seek(SeekFrom::Current(LEGACY_CTM_HEADER_LEN as i64)).map_err(|e| NexradParseError::TcmChunkReadFailed(e))?;
|
||||
|
@ -140,7 +151,9 @@ pub fn parse_nx2_chunk(cursor: &mut (impl Read + Seek)) -> Result<Nexrad2Chunk,
|
|||
let mut message_header = [0u8; MESSAGE_HEADER_SIZE];
|
||||
match decompressed.read_exact(&mut message_header) {
|
||||
Ok(_) => (),
|
||||
Err(e) if matches!(e.kind(), io::ErrorKind::UnexpectedEof) => { break; },
|
||||
Err(e) if matches!(e.kind(), io::ErrorKind::UnexpectedEof) => {
|
||||
break;
|
||||
},
|
||||
Err(e) => return Err(NexradParseError::TcmChunkReadFailed(e))
|
||||
}
|
||||
|
||||
|
@ -155,22 +168,45 @@ pub fn parse_nx2_chunk(cursor: &mut (impl Read + Seek)) -> Result<Nexrad2Chunk,
|
|||
message_segment_num: u16::from_be_bytes(message_header[14..].try_into().unwrap()),
|
||||
};
|
||||
|
||||
if message_header.message_type == 0 {
|
||||
debug!("Reached EOF on chunk");
|
||||
break;
|
||||
}
|
||||
|
||||
debug!("Message: {:#?}", message_header);
|
||||
|
||||
let mut body_buf = vec![0u8; MESSAGE_BODY_SIZE];
|
||||
|
||||
decompressed.read_exact(&mut body_buf).map_err(|e| NexradParseError::TcmChunkReadFailed(e))?;
|
||||
|
||||
messages += 1;
|
||||
let message = match message_header.message_type {
|
||||
2 => {
|
||||
Message::Msg02(Msg02RDAStatusData::from_body(body_buf[0..68].try_into().unwrap())?)
|
||||
},
|
||||
unknown => {
|
||||
warn!("unrecognized message type {}", unknown);
|
||||
continue;
|
||||
}
|
||||
};
|
||||
|
||||
messages.push(message);
|
||||
}
|
||||
|
||||
debug!("{} messages loaded from chunk", messages);
|
||||
debug!("{} messages loaded from chunk", messages.len());
|
||||
|
||||
break;
|
||||
records.push(messages);
|
||||
}
|
||||
|
||||
let mut messages = 0;
|
||||
for chunk in &records {
|
||||
messages += chunk.len();
|
||||
}
|
||||
|
||||
info!("File loaded successfully! {} messages loaded in {} chunks", messages, records.len());
|
||||
|
||||
Ok(Nexrad2Chunk {
|
||||
volume_header_record: header
|
||||
volume_header_record: header,
|
||||
chunks: records
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
pub const MSG_RDA_STATUS_DATA: u8 = 2;
|
||||
use crate::message2::Msg02RDAStatusData;
|
||||
use crate::NexradParseError;
|
||||
|
||||
pub const MSG_RDA_PERFORMANCE_DATA: u8 = 3;
|
||||
pub const MSG_RDA_VOLUME_COVERAGE_DATA: u8 = 5;
|
||||
pub const MSG_RDA_CLUTTER_FILTER_BYPASS_MAP: u8 = 13;
|
||||
|
@ -21,14 +23,14 @@ pub struct MessageHeader {
|
|||
pub julian_date: u16,
|
||||
pub millis_after_midnight: u32,
|
||||
pub num_of_message_segments: u16,
|
||||
pub message_segment_num: u16
|
||||
|
||||
pub message_segment_num: u16,
|
||||
}
|
||||
|
||||
pub trait FromBody<const BODY_SIZE: usize> {
|
||||
fn from_body(body: [u8; BODY_SIZE]) -> Result<Self, NexradParseError> where Self: Sized;
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum Message {
|
||||
/// Type02
|
||||
RDAStatusData {
|
||||
|
||||
},
|
||||
|
||||
Msg02(Msg02RDAStatusData)
|
||||
}
|
|
@ -0,0 +1,71 @@
|
|||
use crate::message::FromBody;
|
||||
use crate::NexradParseError;
|
||||
|
||||
pub const MSG_RDA_STATUS_DATA: u8 = 2;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Msg02RDAStatusData {
|
||||
rda_status: u16,
|
||||
operability_status: u16,
|
||||
control_status: u16,
|
||||
aux_power_state: u16,
|
||||
average_transmitter_power_watts: u16,
|
||||
horiz_ref_calib_corr: u16,
|
||||
data_tx_enabled: u16,
|
||||
vcp: i16,
|
||||
rdaca: u16,
|
||||
rda_build_no: u16,
|
||||
opmode: u16,
|
||||
super_resolution_status: u16,
|
||||
clutter_mitigation_status: u16,
|
||||
rda_scan_data_flags: u16,
|
||||
rda_alarm_summary: u16,
|
||||
command_ack: u16,
|
||||
channel_con_stat: u16,
|
||||
spot_blank_stat: u16,
|
||||
bypass_map_gen_date: u16,
|
||||
bypass_map_gen_time: u16,
|
||||
clutter_map_gen_date: u16,
|
||||
clutter_map_gen_time: u16,
|
||||
vert_ref_calib_corr: u16,
|
||||
tps_status: u16,
|
||||
rms_control_status: u16,
|
||||
perf_check_status: u16,
|
||||
alarm: u16,
|
||||
extra: [u8; 8],
|
||||
}
|
||||
|
||||
impl FromBody<68> for Msg02RDAStatusData {
|
||||
fn from_body(body: [u8; 68]) -> Result<Self, NexradParseError> {
|
||||
Ok(Self {
|
||||
rda_status: u16::from_be_bytes(body[0..2].try_into().unwrap()),
|
||||
operability_status: u16::from_be_bytes(body[2..4].try_into().unwrap()),
|
||||
control_status: u16::from_be_bytes(body[4..6].try_into().unwrap()),
|
||||
aux_power_state: u16::from_be_bytes(body[6..8].try_into().unwrap()),
|
||||
average_transmitter_power_watts: u16::from_be_bytes(body[8..10].try_into().unwrap()),
|
||||
horiz_ref_calib_corr: u16::from_be_bytes(body[10..12].try_into().unwrap()),
|
||||
data_tx_enabled: u16::from_be_bytes(body[12..14].try_into().unwrap()),
|
||||
vcp: i16::from_be_bytes(body[14..16].try_into().unwrap()),
|
||||
rdaca: u16::from_be_bytes(body[16..18].try_into().unwrap()),
|
||||
rda_build_no: u16::from_be_bytes(body[20..22].try_into().unwrap()),
|
||||
opmode: u16::from_be_bytes(body[22..24].try_into().unwrap()),
|
||||
super_resolution_status: u16::from_be_bytes(body[24..26].try_into().unwrap()),
|
||||
clutter_mitigation_status: u16::from_be_bytes(body[26..28].try_into().unwrap()),
|
||||
rda_scan_data_flags: u16::from_be_bytes(body[30..32].try_into().unwrap()),
|
||||
rda_alarm_summary: u16::from_be_bytes(body[32..34].try_into().unwrap()),
|
||||
command_ack: u16::from_be_bytes(body[34..36].try_into().unwrap()),
|
||||
channel_con_stat: u16::from_be_bytes(body[36..38].try_into().unwrap()),
|
||||
spot_blank_stat: u16::from_be_bytes(body[38..40].try_into().unwrap()),
|
||||
bypass_map_gen_date: u16::from_be_bytes(body[40..42].try_into().unwrap()),
|
||||
bypass_map_gen_time: u16::from_be_bytes(body[42..44].try_into().unwrap()),
|
||||
clutter_map_gen_date: u16::from_be_bytes(body[44..46].try_into().unwrap()),
|
||||
clutter_map_gen_time: u16::from_be_bytes(body[46..48].try_into().unwrap()),
|
||||
vert_ref_calib_corr: u16::from_be_bytes(body[50..52].try_into().unwrap()),
|
||||
tps_status: u16::from_be_bytes(body[52..54].try_into().unwrap()),
|
||||
rms_control_status: u16::from_be_bytes(body[54..56].try_into().unwrap()),
|
||||
perf_check_status: u16::from_be_bytes(body[56..58].try_into().unwrap()),
|
||||
alarm: u16::from_be_bytes(body[58..60].try_into().unwrap()),
|
||||
extra: body[60..].try_into().unwrap(),
|
||||
})
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue