use std::collections::HashMap;
use std::fmt::Debug;
use serde::{Deserialize, Serialize};
pub struct DataFile {
volume_header: VolumeHeaderRecord,
elevation_scans: HashMap<u8, Vec<Message31>>,
}
impl DataFile {
pub(crate) fn new(file_header: VolumeHeaderRecord) -> Self {
Self {
volume_header: file_header,
elevation_scans: HashMap::new(),
}
}
pub fn volume_header(&self) -> &VolumeHeaderRecord {
&self.volume_header
}
pub fn elevation_scans(&self) -> &HashMap<u8, Vec<Message31>> {
&self.elevation_scans
}
pub(crate) fn elevation_scans_mut(&mut self) -> &mut HashMap<u8, Vec<Message31>> {
&mut self.elevation_scans
}
}
#[repr(C)]
#[derive(Serialize, Deserialize, Debug)]
pub struct VolumeHeaderRecord {
filename: [u8; 12],
file_date: u32,
file_time: u32,
radar_id: [u8; 4],
}
impl VolumeHeaderRecord {
pub fn filename(&self) -> &[u8; 12] {
&self.filename
}
pub fn file_date(&self) -> u32 {
self.file_date
}
pub fn file_time(&self) -> u32 {
self.file_time
}
pub fn radar_id(&self) -> &[u8; 4] {
&self.radar_id
}
}
#[repr(C)]
#[derive(Serialize, Deserialize, Debug)]
pub struct MessageHeader {
rpg: [u8; 12],
msg_size: u16,
channel: u8,
msg_type: u8,
id_seq: u16,
msg_date: u16,
msg_time: u32,
num_segs: u16,
seg_num: u16,
}
impl MessageHeader {
pub fn rpg(&self) -> &[u8; 12] {
&self.rpg
}
pub fn msg_size(&self) -> u16 {
self.msg_size
}
pub fn channel(&self) -> u8 {
self.channel
}
pub fn msg_type(&self) -> u8 {
self.msg_type
}
pub fn id_seq(&self) -> u16 {
self.id_seq
}
pub fn msg_date(&self) -> u16 {
self.msg_date
}
pub fn msg_time(&self) -> u32 {
self.msg_time
}
pub fn num_segs(&self) -> u16 {
self.num_segs
}
pub fn seg_num(&self) -> u16 {
self.seg_num
}
}
pub struct Message31 {
header: Message31Header,
volume_data: Option<VolumeData>,
elevation_data: Option<ElevationData>,
radial_data: Option<RadialData>,
reflectivity_data: Option<DataMoment>,
velocity_data: Option<DataMoment>,
sw_data: Option<DataMoment>,
zdr_data: Option<DataMoment>,
phi_data: Option<DataMoment>,
rho_data: Option<DataMoment>,
cfp_data: Option<DataMoment>,
}
impl Message31 {
pub(crate) fn new(header: Message31Header) -> Self {
Self {
header,
volume_data: None,
elevation_data: None,
radial_data: None,
reflectivity_data: None,
velocity_data: None,
sw_data: None,
zdr_data: None,
phi_data: None,
rho_data: None,
cfp_data: None,
}
}
pub fn header(&self) -> &Message31Header {
&self.header
}
pub fn volume_data(&self) -> Option<&VolumeData> {
self.volume_data.as_ref()
}
pub fn elevation_data(&self) -> Option<&ElevationData> {
self.elevation_data.as_ref()
}
pub fn radial_data(&self) -> Option<&RadialData> {
self.radial_data.as_ref()
}
pub fn reflectivity_data(&self) -> Option<&DataMoment> {
self.reflectivity_data.as_ref()
}
pub fn velocity_data(&self) -> Option<&DataMoment> {
self.velocity_data.as_ref()
}
pub fn sw_data(&self) -> Option<&DataMoment> {
self.sw_data.as_ref()
}
pub fn zdr_data(&self) -> Option<&DataMoment> {
self.zdr_data.as_ref()
}
pub fn phi_data(&self) -> Option<&DataMoment> {
self.phi_data.as_ref()
}
pub fn rho_data(&self) -> Option<&DataMoment> {
self.rho_data.as_ref()
}
pub fn cfp_data(&self) -> Option<&DataMoment> {
self.cfp_data.as_ref()
}
pub(crate) fn set_volume_data(&mut self, volume_data: VolumeData) {
self.volume_data = Some(volume_data);
}
pub(crate) fn set_elevation_data(&mut self, elevation_data: ElevationData) {
self.elevation_data = Some(elevation_data);
}
pub(crate) fn set_radial_data(&mut self, radial_data: RadialData) {
self.radial_data = Some(radial_data);
}
pub(crate) fn set_reflectivity_data(&mut self, reflectivity_data: DataMoment) {
self.reflectivity_data = Some(reflectivity_data);
}
pub(crate) fn set_velocity_data(&mut self, velocity_data: DataMoment) {
self.velocity_data = Some(velocity_data);
}
pub(crate) fn set_sw_data(&mut self, sw_data: DataMoment) {
self.sw_data = Some(sw_data);
}
pub(crate) fn set_zdr_data(&mut self, zdr_data: DataMoment) {
self.zdr_data = Some(zdr_data);
}
pub(crate) fn set_phi_data(&mut self, phi_data: DataMoment) {
self.phi_data = Some(phi_data);
}
pub(crate) fn set_rho_data(&mut self, rho_data: DataMoment) {
self.rho_data = Some(rho_data);
}
pub(crate) fn set_cfp_data(&mut self, cfp_data: DataMoment) {
self.cfp_data = Some(cfp_data);
}
}
#[repr(C)]
#[derive(Serialize, Deserialize, Debug)]
pub struct Message31Header {
radar_id: [u8; 4],
ray_time: u32,
ray_date: u16,
azm_num: u16,
azm: f32,
compression_code: u8,
spare: u8,
radial_len: u16,
azm_res: u8,
radial_status: u8,
elev_num: u8,
sector_cut_num: u8,
elev: f32,
radial_spot_blanking: u8,
azm_indexing_mode: u8,
data_block_count: u16,
}
impl Message31Header {
pub fn radar_id(&self) -> &[u8; 4] {
&self.radar_id
}
pub fn ray_time(&self) -> u32 {
self.ray_time
}
pub fn ray_date(&self) -> u16 {
self.ray_date
}
pub fn azm_num(&self) -> u16 {
self.azm_num
}
pub fn azm(&self) -> f32 {
self.azm
}
pub fn compression_code(&self) -> u8 {
self.compression_code
}
pub fn spare(&self) -> u8 {
self.spare
}
pub fn radial_len(&self) -> u16 {
self.radial_len
}
pub fn azm_res(&self) -> u8 {
self.azm_res
}
pub fn radial_status(&self) -> u8 {
self.radial_status
}
pub fn elev_num(&self) -> u8 {
self.elev_num
}
pub fn sector_cut_num(&self) -> u8 {
self.sector_cut_num
}
pub fn elev(&self) -> f32 {
self.elev
}
pub fn radial_spot_blanking(&self) -> u8 {
self.radial_spot_blanking
}
pub fn azm_indexing_mode(&self) -> u8 {
self.azm_indexing_mode
}
pub fn data_block_count(&self) -> u16 {
self.data_block_count
}
}
#[repr(C)]
#[derive(Serialize, Deserialize, Debug)]
pub struct DataBlockHeader {
data_block_type: [u8; 1],
data_name: [u8; 3],
}
impl DataBlockHeader {
pub fn data_block_type(&self) -> &[u8; 1] {
&self.data_block_type
}
pub fn data_name(&self) -> &[u8; 3] {
&self.data_name
}
}
#[repr(C)]
#[derive(Serialize, Deserialize, Debug)]
pub struct VolumeData {
data_block_header: DataBlockHeader,
lrtup: u16,
version_major: u8,
version_minor: u8,
lat: f32,
long: f32,
site_height: u16,
feedhorn_height: u16,
calibration_constant: f32,
shvtx_power_hor: f32,
shvtx_power_ver: f32,
system_differential_reflectivity: f32,
initial_system_differential_phase: f32,
volume_coverage_pattern_number: u16,
processing_status: u16,
}
impl VolumeData {
pub fn data_block_header(&self) -> &DataBlockHeader {
&self.data_block_header
}
pub fn lrtup(&self) -> u16 {
self.lrtup
}
pub fn version_major(&self) -> u8 {
self.version_major
}
pub fn version_minor(&self) -> u8 {
self.version_minor
}
pub fn lat(&self) -> f32 {
self.lat
}
pub fn long(&self) -> f32 {
self.long
}
pub fn site_height(&self) -> u16 {
self.site_height
}
pub fn feedhorn_height(&self) -> u16 {
self.feedhorn_height
}
pub fn calibration_constant(&self) -> f32 {
self.calibration_constant
}
pub fn shvtx_power_hor(&self) -> f32 {
self.shvtx_power_hor
}
pub fn shvtx_power_ver(&self) -> f32 {
self.shvtx_power_ver
}
pub fn system_differential_reflectivity(&self) -> f32 {
self.system_differential_reflectivity
}
pub fn initial_system_differential_phase(&self) -> f32 {
self.initial_system_differential_phase
}
pub fn volume_coverage_pattern_number(&self) -> u16 {
self.volume_coverage_pattern_number
}
pub fn processing_status(&self) -> u16 {
self.processing_status
}
}
#[repr(C)]
#[derive(Serialize, Deserialize, Debug)]
pub struct ElevationData {
data_block_header: DataBlockHeader,
lrtup: u16,
atmos: [u8; 2],
calib_const: f32,
}
impl ElevationData {
pub fn data_block_header(&self) -> &DataBlockHeader {
&self.data_block_header
}
pub fn lrtup(&self) -> u16 {
self.lrtup
}
pub fn atmos(&self) -> &[u8; 2] {
&self.atmos
}
pub fn calib_const(&self) -> f32 {
self.calib_const
}
}
#[repr(C)]
#[derive(Serialize, Deserialize, Debug)]
pub struct RadialData {
data_block_header: DataBlockHeader,
lrtup: u16,
unambiguous_range: u16,
noise_level_horz: f32,
noise_level_vert: f32,
nyquist_velocity: u16,
radial_flags: u16,
calib_const_horz_chan: f32,
calib_const_vert_chan: f32,
}
impl RadialData {
pub fn data_block_header(&self) -> &DataBlockHeader {
&self.data_block_header
}
pub fn lrtup(&self) -> u16 {
self.lrtup
}
pub fn unambiguous_range(&self) -> u16 {
self.unambiguous_range
}
pub fn noise_level_horz(&self) -> f32 {
self.noise_level_horz
}
pub fn noise_level_vert(&self) -> f32 {
self.noise_level_vert
}
pub fn nyquist_velocity(&self) -> u16 {
self.nyquist_velocity
}
pub fn radial_flags(&self) -> u16 {
self.radial_flags
}
pub fn calib_const_horz_chan(&self) -> f32 {
self.calib_const_horz_chan
}
pub fn calib_const_vert_chan(&self) -> f32 {
self.calib_const_vert_chan
}
}
pub struct DataMoment {
data: GenericData,
moment_data: Vec<u8>,
}
impl DataMoment {
pub(crate) fn new(data: GenericData, moment_data: Vec<u8>) -> Self {
Self { data, moment_data }
}
pub fn data(&self) -> &GenericData {
&self.data
}
pub fn moment_data(&self) -> &[u8] {
&self.moment_data
}
}
#[repr(C)]
#[derive(Serialize, Deserialize, Debug)]
pub struct GenericData {
data_block_type: [u8; 1],
data_name: [u8; 3],
reserved: u32,
number_data_moment_gates: u16,
data_moment_range: u16,
data_moment_range_sample_interval: u16,
tover: u16,
snr_threshold: u16,
control_flags: u8,
data_word_size: u8,
scale: f32,
offset: f32,
}
impl GenericData {
pub fn data_block_type(&self) -> &[u8; 1] {
&self.data_block_type
}
pub fn data_name(&self) -> &[u8; 3] {
&self.data_name
}
pub fn reserved(&self) -> u32 {
self.reserved
}
pub fn number_data_moment_gates(&self) -> u16 {
self.number_data_moment_gates
}
pub fn data_moment_range(&self) -> u16 {
self.data_moment_range
}
pub fn data_moment_range_sample_interval(&self) -> u16 {
self.data_moment_range_sample_interval
}
pub fn tover(&self) -> u16 {
self.tover
}
pub fn snr_threshold(&self) -> u16 {
self.snr_threshold
}
pub fn control_flags(&self) -> u8 {
self.control_flags
}
pub fn data_word_size(&self) -> u8 {
self.data_word_size
}
pub fn scale(&self) -> f32 {
self.scale
}
pub fn offset(&self) -> f32 {
self.offset
}
pub fn moment_size(&self) -> usize {
self.number_data_moment_gates as usize * self.data_word_size as usize / 8
}
}