ublox/ubx_packets/
types.rs

1use super::packets::{
2    nav_hp_pos_ecef::{NavHpPosEcefOwned, NavHpPosEcefRef},
3    nav_hp_pos_llh::{NavHpPosLlhOwned, NavHpPosLlhRef},
4    nav_pos_llh::{NavPosLlhOwned, NavPosLlhRef},
5    nav_pvt,
6    nav_vel_ned::{NavVelNedOwned, NavVelNedRef},
7};
8use crate::error::DateTimeError;
9use chrono::prelude::*;
10use core::{convert::TryFrom, fmt};
11
12/// Represents a world position, can be constructed from NavPosLlh and NavPvt packets.
13#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
14#[derive(Debug, Clone, Copy)]
15pub struct Position {
16    /// Longitude in degrees
17    pub lon: f64,
18
19    /// Latitude in degrees
20    pub lat: f64,
21
22    /// Altitude in meters
23    pub alt: f64,
24}
25
26/// Represents a world position in the ECEF coordinate system
27#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
28#[derive(Debug, Clone, Copy)]
29pub struct PositionECEF {
30    /// x coordinates in meters
31    pub x: f64,
32
33    /// y coordinates in meters
34    pub y: f64,
35
36    /// z coordinates in meters
37    pub z: f64,
38}
39
40#[derive(Debug, Clone, Copy)]
41#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
42pub struct Velocity {
43    /// m/s over the ground
44    pub speed: f64,
45
46    /// Heading in degrees
47    pub heading: f64, // degrees
48}
49
50impl<'a> From<&NavPosLlhRef<'a>> for Position {
51    fn from(packet: &NavPosLlhRef<'a>) -> Self {
52        Position {
53            lon: packet.lon_degrees(),
54            lat: packet.lat_degrees(),
55            alt: packet.height_msl(),
56        }
57    }
58}
59
60impl From<&NavPosLlhOwned> for Position {
61    fn from(packet: &NavPosLlhOwned) -> Self {
62        Position {
63            lon: packet.lon_degrees(),
64            lat: packet.lat_degrees(),
65            alt: packet.height_msl(),
66        }
67    }
68}
69
70impl<'a> From<&NavHpPosLlhRef<'a>> for Position {
71    fn from(packet: &NavHpPosLlhRef<'a>) -> Self {
72        Position {
73            lon: packet.lon_degrees() + packet.lon_hp_degrees(),
74            lat: packet.lat_degrees() + packet.lat_hp_degrees(),
75            alt: packet.height_msl() + packet.height_hp_msl(),
76        }
77    }
78}
79
80impl From<&NavHpPosLlhOwned> for Position {
81    fn from(packet: &NavHpPosLlhOwned) -> Self {
82        Position {
83            lon: packet.lon_degrees() + packet.lon_hp_degrees(),
84            lat: packet.lat_degrees() + packet.lat_hp_degrees(),
85            alt: packet.height_msl() + packet.height_hp_msl(),
86        }
87    }
88}
89
90fn ecef_from_cm_hp(cm: f64, hp_mm: f64) -> f64 {
91    10e-2 * (cm + 0.1 * hp_mm)
92}
93
94impl<'a> From<&NavHpPosEcefRef<'a>> for PositionECEF {
95    fn from(p: &NavHpPosEcefRef<'a>) -> Self {
96        PositionECEF {
97            x: ecef_from_cm_hp(p.ecef_x_cm(), p.ecef_x_hp_mm()),
98            y: ecef_from_cm_hp(p.ecef_y_cm(), p.ecef_y_hp_mm()),
99            z: ecef_from_cm_hp(p.ecef_z_cm(), p.ecef_z_hp_mm()),
100        }
101    }
102}
103
104impl From<&NavHpPosEcefOwned> for PositionECEF {
105    fn from(p: &NavHpPosEcefOwned) -> Self {
106        PositionECEF {
107            x: ecef_from_cm_hp(p.ecef_x_cm(), p.ecef_x_hp_mm()),
108            y: ecef_from_cm_hp(p.ecef_y_cm(), p.ecef_y_hp_mm()),
109            z: ecef_from_cm_hp(p.ecef_z_cm(), p.ecef_z_hp_mm()),
110        }
111    }
112}
113
114impl<'a> From<&NavVelNedRef<'a>> for Velocity {
115    fn from(packet: &NavVelNedRef<'a>) -> Self {
116        Velocity {
117            speed: packet.ground_speed(),
118            heading: packet.heading_degrees(),
119        }
120    }
121}
122
123impl From<&NavVelNedOwned> for Velocity {
124    fn from(packet: &NavVelNedOwned) -> Self {
125        Velocity {
126            speed: packet.ground_speed(),
127            heading: packet.heading_degrees(),
128        }
129    }
130}
131
132#[cfg(any(feature = "ubx_proto27", feature = "ubx_proto31"))]
133impl<'a> From<&nav_pvt::proto27_31::NavPvtRef<'a>> for Position {
134    fn from(packet: &nav_pvt::proto27_31::NavPvtRef<'a>) -> Self {
135        Position {
136            lon: packet.longitude(),
137            lat: packet.latitude(),
138            alt: packet.height_msl(),
139        }
140    }
141}
142
143#[cfg(feature = "ubx_proto23")]
144impl<'a> From<&nav_pvt::proto23::NavPvtRef<'a>> for Position {
145    fn from(packet: &nav_pvt::proto23::NavPvtRef<'a>) -> Self {
146        Position {
147            lon: packet.longitude(),
148            lat: packet.latitude(),
149            alt: packet.height_msl(),
150        }
151    }
152}
153
154#[cfg(feature = "ubx_proto14")]
155impl<'a> From<&nav_pvt::proto14::NavPvtRef<'a>> for Position {
156    fn from(packet: &nav_pvt::proto14::NavPvtRef<'a>) -> Self {
157        Position {
158            lon: packet.longitude(),
159            lat: packet.latitude(),
160            alt: packet.height_msl(),
161        }
162    }
163}
164
165#[cfg(any(feature = "ubx_proto27", feature = "ubx_proto31"))]
166impl From<&nav_pvt::proto27_31::NavPvtOwned> for Position {
167    fn from(packet: &nav_pvt::proto27_31::NavPvtOwned) -> Self {
168        Position {
169            lon: packet.longitude(),
170            lat: packet.latitude(),
171            alt: packet.height_msl(),
172        }
173    }
174}
175
176#[cfg(feature = "ubx_proto23")]
177impl From<&nav_pvt::proto23::NavPvtOwned> for Position {
178    fn from(packet: &nav_pvt::proto23::NavPvtOwned) -> Self {
179        Position {
180            lon: packet.longitude(),
181            lat: packet.latitude(),
182            alt: packet.height_msl(),
183        }
184    }
185}
186
187#[cfg(feature = "ubx_proto14")]
188impl From<&nav_pvt::proto14::NavPvtOwned> for Position {
189    fn from(packet: &nav_pvt::proto14::NavPvtOwned) -> Self {
190        Position {
191            lon: packet.longitude(),
192            lat: packet.latitude(),
193            alt: packet.height_msl(),
194        }
195    }
196}
197
198#[cfg(any(feature = "ubx_proto27", feature = "ubx_proto31"))]
199impl<'a> From<&nav_pvt::proto27_31::NavPvtRef<'a>> for Velocity {
200    fn from(packet: &nav_pvt::proto27_31::NavPvtRef<'a>) -> Self {
201        Velocity {
202            speed: packet.ground_speed_2d(),
203            heading: packet.heading_motion(),
204        }
205    }
206}
207
208#[cfg(feature = "ubx_proto23")]
209impl<'a> From<&nav_pvt::proto23::NavPvtRef<'a>> for Velocity {
210    fn from(packet: &nav_pvt::proto23::NavPvtRef<'a>) -> Self {
211        Velocity {
212            speed: packet.ground_speed_2d(),
213            heading: packet.heading_motion(),
214        }
215    }
216}
217
218#[cfg(feature = "ubx_proto14")]
219impl<'a> From<&nav_pvt::proto14::NavPvtRef<'a>> for Velocity {
220    fn from(packet: &nav_pvt::proto14::NavPvtRef<'a>) -> Self {
221        Velocity {
222            speed: packet.ground_speed_2d(),
223            heading: packet.heading_motion(),
224        }
225    }
226}
227
228#[cfg(any(feature = "ubx_proto27", feature = "ubx_proto31"))]
229impl From<&nav_pvt::proto27_31::NavPvtOwned> for Velocity {
230    fn from(packet: &nav_pvt::proto27_31::NavPvtOwned) -> Self {
231        Velocity {
232            speed: packet.ground_speed_2d(),
233            heading: packet.heading_motion(),
234        }
235    }
236}
237#[cfg(feature = "ubx_proto23")]
238impl From<&nav_pvt::proto23::NavPvtOwned> for Velocity {
239    fn from(packet: &nav_pvt::proto23::NavPvtOwned) -> Self {
240        Velocity {
241            speed: packet.ground_speed_2d(),
242            heading: packet.heading_motion(),
243        }
244    }
245}
246#[cfg(feature = "ubx_proto14")]
247impl From<&nav_pvt::proto14::NavPvtOwned> for Velocity {
248    fn from(packet: &nav_pvt::proto14::NavPvtOwned) -> Self {
249        Velocity {
250            speed: packet.ground_speed_2d(),
251            heading: packet.heading_motion(),
252        }
253    }
254}
255
256fn datetime_from_nav_pvt(
257    year: u16,
258    month: u8,
259    day: u8,
260    hour: u8,
261    min: u8,
262    sec: u8,
263    nanos: i32,
264) -> Result<DateTime<Utc>, DateTimeError> {
265    let date = NaiveDate::from_ymd_opt(i32::from(year), u32::from(month), u32::from(day))
266        .ok_or(DateTimeError::InvalidDate)?;
267
268    let time = NaiveTime::from_hms_opt(u32::from(hour), u32::from(min), u32::from(sec))
269        .ok_or(DateTimeError::InvalidTime)?;
270
271    const NANOS_LIM: u32 = 1_000_000_000;
272    if (nanos.wrapping_abs() as u32) >= NANOS_LIM {
273        return Err(DateTimeError::InvalidNanoseconds);
274    }
275
276    let dt = NaiveDateTime::new(date, time) + chrono::Duration::nanoseconds(i64::from(nanos));
277    Ok(DateTime::from_naive_utc_and_offset(dt, Utc))
278}
279
280#[cfg(any(feature = "ubx_proto27", feature = "ubx_proto31"))]
281impl<'a> TryFrom<&nav_pvt::proto27_31::NavPvtRef<'a>> for DateTime<Utc> {
282    type Error = DateTimeError;
283    fn try_from(sol: &nav_pvt::proto27_31::NavPvtRef<'a>) -> Result<Self, Self::Error> {
284        datetime_from_nav_pvt(
285            sol.year(),
286            sol.month(),
287            sol.day(),
288            sol.hour(),
289            sol.min(),
290            sol.sec(),
291            sol.nanosec(),
292        )
293    }
294}
295
296#[cfg(feature = "ubx_proto23")]
297impl<'a> TryFrom<&nav_pvt::proto23::NavPvtRef<'a>> for DateTime<Utc> {
298    type Error = DateTimeError;
299    fn try_from(sol: &nav_pvt::proto23::NavPvtRef<'a>) -> Result<Self, Self::Error> {
300        datetime_from_nav_pvt(
301            sol.year(),
302            sol.month(),
303            sol.day(),
304            sol.hour(),
305            sol.min(),
306            sol.sec(),
307            sol.nanosec(),
308        )
309    }
310}
311
312#[cfg(feature = "ubx_proto14")]
313impl<'a> TryFrom<&nav_pvt::proto14::NavPvtRef<'a>> for DateTime<Utc> {
314    type Error = DateTimeError;
315    fn try_from(sol: &nav_pvt::proto14::NavPvtRef<'a>) -> Result<Self, Self::Error> {
316        datetime_from_nav_pvt(
317            sol.year(),
318            sol.month(),
319            sol.day(),
320            sol.hour(),
321            sol.min(),
322            sol.sec(),
323            sol.nanosec(),
324        )
325    }
326}
327
328#[cfg(any(feature = "ubx_proto27", feature = "ubx_proto31"))]
329impl TryFrom<&nav_pvt::proto27_31::NavPvtOwned> for DateTime<Utc> {
330    type Error = DateTimeError;
331    fn try_from(sol: &nav_pvt::proto27_31::NavPvtOwned) -> Result<Self, Self::Error> {
332        datetime_from_nav_pvt(
333            sol.year(),
334            sol.month(),
335            sol.day(),
336            sol.hour(),
337            sol.min(),
338            sol.sec(),
339            sol.nanosec(),
340        )
341    }
342}
343
344#[cfg(feature = "ubx_proto23")]
345impl TryFrom<&nav_pvt::proto23::NavPvtOwned> for DateTime<Utc> {
346    type Error = DateTimeError;
347    fn try_from(sol: &nav_pvt::proto23::NavPvtOwned) -> Result<Self, Self::Error> {
348        datetime_from_nav_pvt(
349            sol.year(),
350            sol.month(),
351            sol.day(),
352            sol.hour(),
353            sol.min(),
354            sol.sec(),
355            sol.nanosec(),
356        )
357    }
358}
359
360#[cfg(feature = "ubx_proto14")]
361impl TryFrom<&nav_pvt::proto14::NavPvtOwned> for DateTime<Utc> {
362    type Error = DateTimeError;
363    fn try_from(sol: &nav_pvt::proto14::NavPvtOwned) -> Result<Self, Self::Error> {
364        datetime_from_nav_pvt(
365            sol.year(),
366            sol.month(),
367            sol.day(),
368            sol.hour(),
369            sol.min(),
370            sol.sec(),
371            sol.nanosec(),
372        )
373    }
374}
375
376#[allow(dead_code, reason = "It is only dead code in some feature sets")]
377pub(crate) struct FieldIter<I>(pub(crate) I);
378
379impl<I> fmt::Debug for FieldIter<I>
380where
381    I: fmt::Debug,
382{
383    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
384        self.0.fmt(f)
385    }
386}
387
388#[cfg(feature = "serde")]
389impl<I> serde::Serialize for FieldIter<I>
390where
391    I: Iterator + Clone,
392    I::Item: serde::Serialize,
393{
394    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
395    where
396        S: serde::Serializer,
397    {
398        serializer.collect_seq(self.0.clone())
399    }
400}