1extern crate alloc;
9use alloc::string::ToString;
10use core::fmt::{Display, Formatter};
11
12use irox_tools::format;
13use irox_tools::options::MaybeFrom;
14use irox_units::units::compass::Azimuth;
15
16use crate::coordinate::Elevation;
17
18#[derive(Copy, Clone, Debug, PartialEq)]
19pub struct SatelliteSignal {
20 pub prn: u8,
21 pub azimuth: Azimuth,
22 pub elevation: Elevation,
23 pub snr: u8,
24}
25
26impl Display for SatelliteSignal {
27 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
28 f.write_fmt(format_args!(
29 "PRN: {} Az: {} El: {}, SNR: {}",
30 self.prn, self.azimuth, self.elevation, self.snr
31 ))
32 }
33}
34
35#[derive(Copy, Clone, Debug, Default, PartialEq)]
37pub enum GPSFixType {
38 #[default]
39 Unknown = 0,
40 NoFix = 1,
41 TwoDim = 2,
42 ThreeDim = 3,
43}
44impl From<i32> for GPSFixType {
45 fn from(value: i32) -> Self {
46 match value {
47 1 => GPSFixType::NoFix,
48 2 => GPSFixType::TwoDim,
49 3 => GPSFixType::ThreeDim,
50 _ => GPSFixType::Unknown,
51 }
52 }
53}
54impl From<Option<&str>> for GPSFixType {
55 fn from(value: Option<&str>) -> Self {
56 if let Some(value) = value {
57 if let Ok(value) = value.parse::<i32>() {
58 return value.into();
59 }
60 }
61 GPSFixType::Unknown
62 }
63}
64
65#[derive(Debug, Copy, Clone, PartialOrd, PartialEq, Default)]
66pub struct DilutionOfPrecision(pub f64);
67impl From<f64> for DilutionOfPrecision {
68 fn from(value: f64) -> Self {
69 DilutionOfPrecision(value)
70 }
71}
72impl From<DilutionOfPrecision> for f64 {
73 fn from(value: DilutionOfPrecision) -> Self {
74 value.0
75 }
76}
77impl MaybeFrom<Option<f64>> for DilutionOfPrecision {
78 fn maybe_from(value: Option<f64>) -> Option<Self> {
79 Some(value?.into())
80 }
81}
82impl Display for DilutionOfPrecision {
83 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
84 f.write_fmt(format_args!("{}", self.0))
85 }
86}
87
88#[derive(Debug, Copy, Clone, PartialEq, Default)]
89pub struct DOPs {
90 pub geometric: Option<DilutionOfPrecision>,
91 pub horizontal: Option<DilutionOfPrecision>,
92 pub position: Option<DilutionOfPrecision>,
93 pub time: Option<DilutionOfPrecision>,
94 pub vertical: Option<DilutionOfPrecision>,
95}
96
97impl DOPs {
98 #[must_use]
99 pub fn new() -> DOPs {
100 Default::default()
101 }
102}
103
104impl Display for DOPs {
105 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
106 let print = |x: Option<DilutionOfPrecision>| match x {
107 Some(x) => format!("{:0.3}", x.0),
108 None => "?".to_string(),
109 };
110 write!(
111 f,
112 "hdop: {} vdop: {} pdop: {} gdop: {} tdop: {}",
113 print(self.horizontal),
114 print(self.vertical),
115 print(self.position),
116 print(self.geometric),
117 print(self.time)
118 )
119 }
120}
121
122#[cfg(all(target_os = "windows", feature = "windows"))]
123pub mod windows {
124 use windows::Devices::Geolocation::Geocoordinate;
125 use windows::Foundation::IReference;
126
127 use crate::gps::{DOPs, DilutionOfPrecision};
128
129 impl DOPs {
130 pub fn maybe_from(coord: &Geocoordinate) -> Option<DOPs> {
131 let Ok(sats) = coord.SatelliteData() else {
132 return None;
133 };
134
135 let get_dop = |v: IReference<f64>| -> Option<DilutionOfPrecision> {
136 v.GetDouble().ok().map(DilutionOfPrecision)
137 };
138 let geometric = sats.GeometricDilutionOfPrecision().ok().and_then(get_dop);
139 let horizontal = sats.HorizontalDilutionOfPrecision().ok().and_then(get_dop);
140 let position = sats.PositionDilutionOfPrecision().ok().and_then(get_dop);
141 let time = sats.TimeDilutionOfPrecision().ok().and_then(get_dop);
142 let vertical = sats.VerticalDilutionOfPrecision().ok().and_then(get_dop);
143
144 Some(DOPs {
145 geometric,
146 horizontal,
147 position,
148 time,
149 vertical,
150 })
151 }
152 }
153}