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#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
14#[derive(Debug, Clone, Copy)]
15pub struct Position {
16 pub lon: f64,
18
19 pub lat: f64,
21
22 pub alt: f64,
24}
25
26#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
28#[derive(Debug, Clone, Copy)]
29pub struct PositionECEF {
30 pub x: f64,
32
33 pub y: f64,
35
36 pub z: f64,
38}
39
40#[derive(Debug, Clone, Copy)]
41#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
42pub struct Velocity {
43 pub speed: f64,
45
46 pub heading: f64, }
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}