use crate::helper_functions::{get_f64_value, get_path, Path};
use crate::{SignalKGetError, V1CommonValueFields, V1NumberValue};
use log::debug;
use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize, PartialEq, Debug, Default, Clone)]
#[serde(rename_all = "camelCase")]
pub struct V1gnss {
#[serde(rename = "type")]
type_: Option<V1gnssType>,
method_quality: Option<V1gnssMethodQuality>,
integrity: Option<V1gnssIntegrity>,
satellites: Option<V1NumberValue>,
antenna_altitude: Option<V1NumberValue>,
horizontal_dilution: Option<V1NumberValue>,
position_dilution: Option<V1NumberValue>,
geoidal_separation: Option<V1NumberValue>,
differential_age: Option<V1NumberValue>,
satellites_in_view: Option<V1gnssSatellitesInView>,
}
impl Path<f64> for V1gnss {
fn get_path(&self, path: &[&str]) -> Result<f64, SignalKGetError> {
debug!("get_path({:?}): ...", path);
match path[0] {
"type" => Err(SignalKGetError::WrongDataType),
"methodQuality" => Err(SignalKGetError::WrongDataType),
"integrity" => Err(SignalKGetError::WrongDataType),
"satellites" => get_f64_value(&self.satellites),
"antennaAltitude" => get_f64_value(&self.antenna_altitude),
"horizontalDilution" => get_f64_value(&self.horizontal_dilution),
"positionDilution" => get_f64_value(&self.position_dilution),
"geoidalSeparation" => get_f64_value(&self.geoidal_separation),
"differentialAge" => get_f64_value(&self.differential_age),
"satellitesInView" => get_path(path, &self.satellites_in_view.as_ref()),
&_ => Err(SignalKGetError::NoSuchPath),
}
}
}
impl V1gnss {
pub fn builder() -> V1gnssBuilder {
V1gnssBuilder::default()
}
pub fn update(&mut self, path: &mut Vec<&str>, value: &serde_json::value::Value) {
match path[0] {
"type" => {
let type_result: Result<V1gnssType, serde_json::Error> =
serde_json::from_value(value.clone());
if let Ok(type_value) = type_result {
self.type_ = Some(type_value);
} else {
log::error!("Invalid GNSS type: {:?}", type_result);
self.type_ = None;
}
}
"methodQuality" => {
let quality_result: Result<V1gnssMethodQuality, serde_json::Error> =
serde_json::from_value(value.clone());
if let Ok(quality_value) = quality_result {
self.method_quality = Some(quality_value);
} else {
log::error!("Invalid GNSS Method Quality: {:?}", quality_result);
self.method_quality = None;
}
}
"integrity" => {
let integrity_result: Result<V1gnssIntegrity, serde_json::Error> =
serde_json::from_value(value.clone());
if let Ok(integrity_value) = integrity_result {
self.integrity = Some(integrity_value);
} else {
log::error!("Invalid GNSS Integrity: {:?}", integrity_result);
self.integrity = None;
}
}
"satellites" => {
self.satellites = Some(V1NumberValue::builder().json_value(value).build())
}
"satellitesInView" => {
let satellites_in_view_result: Result<V1gnssSatellitesInView, serde_json::Error> =
serde_json::from_value(value.clone());
if let Ok(satellites_in_view_value) = satellites_in_view_result {
self.satellites_in_view = Some(satellites_in_view_value);
} else {
log::error!(
"Invalid GNSS Satellites In View: {:?}",
satellites_in_view_result
);
self.satellites_in_view = None;
}
}
"antennaAltitude" => {
self.antenna_altitude = Some(V1NumberValue::builder().json_value(value).build())
}
"horizontalDilution" => {
self.horizontal_dilution = Some(V1NumberValue::builder().json_value(value).build())
}
"positionDilution" => {
self.position_dilution = Some(V1NumberValue::builder().json_value(value).build())
}
"geoidalSeparation" => {
self.geoidal_separation = Some(V1NumberValue::builder().json_value(value).build())
}
"differentialAge" => {
self.differential_age = Some(V1NumberValue::builder().json_value(value).build())
}
&_ => {
log::warn!("V1gnss: Unknown value to update: {:?}::{:?}", path, value);
}
}
}
pub fn get_f64_for_path(&self, path: &mut Vec<&str>) -> Result<f64, SignalKGetError> {
self.get_path(path)
}
}
#[derive(Serialize, Deserialize, PartialEq, Debug, Clone)]
#[serde(untagged)]
pub enum V1gnssType {
Expanded(V1gnssExpandedType),
Value(V1gnssTypeValue),
}
#[derive(Serialize, Deserialize, PartialEq, Debug, Default, Clone)]
pub struct V1gnssExpandedType {
value: Option<V1gnssTypeValue>,
#[serde(flatten)]
pub common_value_fields: Option<V1CommonValueFields>,
}
#[derive(Serialize, Deserialize, PartialEq, Debug, Default, Clone)]
pub enum V1gnssTypeValue {
#[default]
Undefined,
#[serde(rename = "GPS")]
Gps,
#[serde(rename = "GLONASS")]
Glonass,
#[serde(rename = "Combined GPS/GLONASS")]
CombinedGpsGlonass,
#[serde(rename = "Loran-C")]
LoranC,
Chayka,
#[serde(rename = "Integrated navigation system")]
IntegratedNavigationSystem,
Surveyed,
Galileo,
}
#[derive(Serialize, Deserialize, PartialEq, Debug, Clone)]
#[serde(untagged)]
pub enum V1gnssMethodQuality {
Expanded(V1gnssExpandedMethodQuality),
Value(V1gnssMethodQualityValue),
}
#[derive(Serialize, Deserialize, PartialEq, Debug, Default, Clone)]
pub struct V1gnssExpandedMethodQuality {
value: V1gnssMethodQualityValue,
#[serde(flatten)]
pub common_value_fields: Option<V1CommonValueFields>,
}
#[derive(Serialize, Deserialize, PartialEq, Debug, Default, Clone)]
pub enum V1gnssMethodQualityValue {
#[default]
#[serde(rename = "no GPS")]
NoGps,
#[serde(rename = "GNSS Fix")]
GNSSFix,
#[serde(rename = "DGNSS Fix")]
DGNSSFix,
#[serde(rename = "Precise GNSS")]
PreciseGNSS,
#[serde(rename = "RTK fixed integer")]
RTKFixedInteger,
#[serde(rename = "RTK float")]
RTKFloat,
#[serde(rename = "Estimated (DR) mode")]
EstimatedDRMode,
#[serde(rename = "Manual input")]
ManualInput,
#[serde(rename = "Simulator mode")]
SimulatorMode,
#[serde(rename = "Error")]
Error,
}
#[derive(Serialize, Deserialize, PartialEq, Debug, Clone)]
#[serde(untagged)]
pub enum V1gnssIntegrity {
Expanded(V1gnssExpandedIntegrity),
Value(V1gnssIntegrityValue),
}
#[derive(Serialize, Deserialize, PartialEq, Debug, Default, Clone)]
pub struct V1gnssExpandedIntegrity {
value: V1gnssIntegrityValue,
#[serde(flatten)]
pub common_value_fields: Option<V1CommonValueFields>,
}
#[derive(Serialize, Deserialize, PartialEq, Debug, Default, Clone)]
pub enum V1gnssIntegrityValue {
#[default]
#[serde(rename = "no Integrity checking")]
NoIntegrityChecking,
Safe,
Caution,
Unsafe,
}
#[derive(Serialize, Deserialize, PartialEq, Debug, Clone)]
#[serde(untagged)]
pub enum V1gnssSatellitesInView {
Expanded(V1gnssExpandedSatellitesInView),
Value(V1gnssSatellitesInViewValue),
}
impl Path<f64> for V1gnssSatellitesInView {
fn get_path(&self, path: &[&str]) -> Result<f64, SignalKGetError> {
debug!("get_path({:?}): ...", path);
match self {
V1gnssSatellitesInView::Expanded(val) => val.get_path(path),
V1gnssSatellitesInView::Value(val) => val.get_path(path),
}
}
}
#[derive(Serialize, Deserialize, PartialEq, Debug, Default, Clone)]
pub struct V1gnssExpandedSatellitesInView {
value: V1gnssSatellitesInViewValue,
#[serde(flatten)]
pub common_value_fields: Option<V1CommonValueFields>,
}
impl Path<f64> for V1gnssExpandedSatellitesInView {
fn get_path(&self, path: &[&str]) -> Result<f64, SignalKGetError> {
self.value.get_path(path)
}
}
#[derive(Serialize, Deserialize, PartialEq, Debug, Default, Clone)]
pub struct V1gnssSatellitesInViewValue {
count: i64,
satellites: Option<Vec<V1gnssSatellite>>,
}
impl Path<f64> for V1gnssSatellitesInViewValue {
fn get_path(&self, path: &[&str]) -> Result<f64, SignalKGetError> {
debug!("get_path({:?}): ...", path);
if path.is_empty() {
Err(SignalKGetError::WrongDataType)
} else {
match path[0] {
"count" => Err(SignalKGetError::WrongDataType),
"satellites" => Err(SignalKGetError::TBD),
&_ => Err(SignalKGetError::NoSuchPath),
}
}
}
}
#[derive(Serialize, Deserialize, PartialEq, Debug, Default, Clone)]
pub struct V1gnssSatellite {
id: Option<i64>,
elevation: Option<f64>,
azimuth: Option<f64>,
#[serde(rename = "SNR")]
signal_to_noise_ratio: Option<i64>,
}
#[derive(Default)]
pub struct V1gnssBuilder {}
#[cfg(test)]
mod tests {
use crate::navigation_gnss::{V1gnssExpandedSatellitesInView, V1gnssSatellite};
#[test]
fn satellite_value_object_json() {
let j = r#"
{
"id": 17,
"elevation": 0.3665,
"azimuth": 5.5676,
"SNR": 39
}"#;
let satellite: V1gnssSatellite = serde_json::from_str(j).unwrap();
assert_eq!(satellite.id.unwrap(), 17);
}
#[test]
fn satellites_in_view_value_object_json() {
let j = r#"
{
"meta": {},
"value": {
"count": 11,
"satellites": [
{
"id": 32,
"elevation": 1.2043,
"azimuth": 3.8921,
"SNR": 32
}
]
},
"$source": "n2k-sample-data.160",
"timestamp": "2014-08-15T19:00:51.130Z",
"pgn": 129540
}"#;
let satellites_in_view: V1gnssExpandedSatellitesInView = serde_json::from_str(j).unwrap();
assert_eq!(satellites_in_view.value.count, 11)
}
}