use crate::error::{Error, Result};
use super::bits::{BitReader, BitWriter};
const ECEF_SCALE_M: f64 = 0.0001;
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct StationCoordinates {
pub message_number: u16,
pub reference_station_id: u16,
pub itrf_realization_year: u8,
pub gps_indicator: bool,
pub glonass_indicator: bool,
pub galileo_indicator: bool,
pub reference_station_indicator: bool,
pub ecef_x: i64,
pub single_receiver_oscillator: bool,
pub reserved: bool,
pub ecef_y: i64,
pub quarter_cycle_indicator: u8,
pub ecef_z: i64,
pub antenna_height: Option<u16>,
}
impl StationCoordinates {
pub fn x_m(&self) -> f64 {
self.ecef_x as f64 * ECEF_SCALE_M
}
pub fn y_m(&self) -> f64 {
self.ecef_y as f64 * ECEF_SCALE_M
}
pub fn z_m(&self) -> f64 {
self.ecef_z as f64 * ECEF_SCALE_M
}
pub fn antenna_height_m(&self) -> Option<f64> {
self.antenna_height.map(|h| f64::from(h) * ECEF_SCALE_M)
}
pub fn decode(body: &[u8]) -> Result<Self> {
let mut r = BitReader::new(body);
let message_number = r.u(12)? as u16;
if message_number != 1005 && message_number != 1006 {
return Err(Error::Parse(format!(
"message {message_number} is not station coordinates 1005/1006"
)));
}
let reference_station_id = r.u(12)? as u16;
let itrf_realization_year = r.u(6)? as u8;
let gps_indicator = r.flag()?;
let glonass_indicator = r.flag()?;
let galileo_indicator = r.flag()?;
let reference_station_indicator = r.flag()?;
let ecef_x = r.i(38)?;
let single_receiver_oscillator = r.flag()?;
let reserved = r.flag()?;
let ecef_y = r.i(38)?;
let quarter_cycle_indicator = r.u(2)? as u8;
let ecef_z = r.i(38)?;
let antenna_height = if message_number == 1006 {
Some(r.u(16)? as u16)
} else {
None
};
Ok(Self {
message_number,
reference_station_id,
itrf_realization_year,
gps_indicator,
glonass_indicator,
galileo_indicator,
reference_station_indicator,
ecef_x,
single_receiver_oscillator,
reserved,
ecef_y,
quarter_cycle_indicator,
ecef_z,
antenna_height,
})
}
pub fn encode(&self) -> Vec<u8> {
let mut w = BitWriter::new();
w.push_u(u64::from(self.message_number), 12);
w.push_u(u64::from(self.reference_station_id), 12);
w.push_u(u64::from(self.itrf_realization_year), 6);
w.push_flag(self.gps_indicator);
w.push_flag(self.glonass_indicator);
w.push_flag(self.galileo_indicator);
w.push_flag(self.reference_station_indicator);
w.push_i(self.ecef_x, 38);
w.push_flag(self.single_receiver_oscillator);
w.push_flag(self.reserved);
w.push_i(self.ecef_y, 38);
w.push_u(u64::from(self.quarter_cycle_indicator), 2);
w.push_i(self.ecef_z, 38);
if let Some(height) = self.antenna_height {
w.push_u(u64::from(height), 16);
}
w.into_bytes()
}
}