use crate::common;
use crate::coords::{Altitude, Latitude, Longitude};
use crate::datetime::Time;
use crate::Source;
use core::time::Duration;
#[derive(Debug, PartialEq, Clone)]
pub struct GGA {
pub source: Source,
pub time: Time,
pub latitude: Latitude,
pub longitude: Longitude,
pub gps_quality: GPSQuality,
pub sat_in_use: u8,
pub hdop: f32,
pub altitude: Altitude,
pub geoidal_separation: Option<f32>,
pub age_dgps: Option<Duration>,
pub dgps_station_id: Option<u16>,
}
impl GGA {
pub(crate) fn parse<'a>(
source: Source,
fields: &mut core::str::Split<'a, char>,
) -> Result<Option<Self>, &'static str> {
let time = Time::parse_from_hhmmss(fields.next())?;
let latitude = Latitude::parse(fields.next(), fields.next())?;
let longitude = Longitude::parse(fields.next(), fields.next())?;
let gps_quality = GPSQuality::parse(fields.next())?;
let sat_in_use = common::parse_u8(fields.next())?;
let hdop = common::parse_f32(fields.next())?;
let altitude = Altitude::parse(fields.next())?;
fields.next(); let geoidal_separation = common::parse_f32(fields.next())?;
fields.next(); let age_dgps = common::parse_f32(fields.next())?
.and_then(|a| Some(Duration::from_millis((a * 1000f32) as u64)));
let dgps_station_id = common::parse_u16(fields.next())?;
if let (
Some(time),
Some(latitude),
Some(longitude),
Some(gps_quality),
Some(sat_in_use),
Some(hdop),
Some(altitude),
) = (
time,
latitude,
longitude,
gps_quality,
sat_in_use,
hdop,
altitude,
) {
Ok(Some(GGA {
source,
time,
latitude,
longitude,
gps_quality,
sat_in_use,
hdop,
altitude,
geoidal_separation,
age_dgps,
dgps_station_id,
}))
} else {
Ok(None)
}
}
}
#[derive(Debug, PartialEq, Clone)]
pub enum GPSQuality {
NoFix,
GPS,
DGPS,
PPS,
RTK,
FRTK,
Estimated,
Manual,
Simulated,
}
impl GPSQuality {
pub(crate) fn parse(input: Option<&str>) -> Result<Option<GPSQuality>, &'static str> {
match input {
Some("0") => Ok(Some(GPSQuality::NoFix)),
Some("1") => Ok(Some(GPSQuality::GPS)),
Some("2") => Ok(Some(GPSQuality::DGPS)),
Some("3") => Ok(Some(GPSQuality::PPS)),
Some("4") => Ok(Some(GPSQuality::RTK)),
Some("5") => Ok(Some(GPSQuality::FRTK)),
Some("6") => Ok(Some(GPSQuality::Estimated)),
Some("7") => Ok(Some(GPSQuality::Manual)),
Some("8") => Ok(Some(GPSQuality::Simulated)),
Some("") => Ok(None),
None => Ok(None),
_ => Err("Wrong GPSQuality indicator type!"),
}
}
}
#[test]
fn test_parse_gpsquality() {
assert_eq!(GPSQuality::parse(Some("0")), Ok(Some(GPSQuality::NoFix)));
assert_eq!(GPSQuality::parse(Some("1")), Ok(Some(GPSQuality::GPS)));
assert_eq!(GPSQuality::parse(Some("2")), Ok(Some(GPSQuality::DGPS)));
assert_eq!(GPSQuality::parse(Some("3")), Ok(Some(GPSQuality::PPS)));
assert_eq!(GPSQuality::parse(Some("4")), Ok(Some(GPSQuality::RTK)));
assert_eq!(GPSQuality::parse(Some("5")), Ok(Some(GPSQuality::FRTK)));
assert_eq!(
GPSQuality::parse(Some("6")),
Ok(Some(GPSQuality::Estimated))
);
assert_eq!(GPSQuality::parse(Some("7")), Ok(Some(GPSQuality::Manual)));
assert_eq!(
GPSQuality::parse(Some("8")),
Ok(Some(GPSQuality::Simulated))
);
assert_eq!(GPSQuality::parse(Some("")), Ok(None));
assert_eq!(GPSQuality::parse(None), Ok(None));
assert!(GPSQuality::parse(Some("9")).is_err());
}