1use std::str::FromStr;
3
4use crate::{
5 navigation::ephemeris::flags::{
6 bds::{
7 BdsB1cIntegrity, BdsB2aB1cIntegrity, BdsB2bIntegrity, BdsHealth, BdsSatH1,
8 BdsSatelliteType,
9 },
10 gal::{GalDataSource, GalHealth},
11 geo::GeoHealth,
12 glonass::{GlonassHealth, GlonassHealth2, GlonassStatus},
13 gps::{GpsQzssl1cHealth, GpsQzssl1l2l5Health},
14 irnss::IrnssHealth,
15 },
16 prelude::ParsingError,
17};
18
19#[cfg(feature = "serde")]
20use serde::Serialize;
21
22include!(concat!(env!("OUT_DIR"), "/nav_orbits.rs"));
23
24#[derive(Debug, Clone, PartialEq, PartialOrd)]
28#[cfg_attr(feature = "serde", derive(Serialize))]
29pub enum OrbitItem {
30 U8(u8),
32
33 I8(i8),
35
36 U32(u32),
38
39 F64(f64),
41
42 Gpsl2pFlag(bool),
46
47 GpsQzssl1cHealth(GpsQzssl1cHealth),
49
50 GpsQzssl1l2l5Health(GpsQzssl1l2l5Health),
52
53 GeoHealth(GeoHealth),
55
56 GalHealth(GalHealth),
58
59 GalDataSource(GalDataSource),
61
62 IrnssHealth(IrnssHealth),
64
65 GlonassHealth(GlonassHealth),
67
68 GlonassHealth2(GlonassHealth2),
70
71 GlonassStatus(GlonassStatus),
73
74 BdsSatH1(BdsSatH1),
76
77 BdsHealth(BdsHealth),
79
80 BdsSatelliteType(BdsSatelliteType),
82
83 BdsB1cIntegrity(BdsB1cIntegrity),
85
86 BdsB2aB1cIntegrity(BdsB2aB1cIntegrity),
88
89 BdsB2bIntegrity(BdsB2bIntegrity),
91}
92
93impl std::fmt::Display for OrbitItem {
94 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
95 match self {
96 Self::U8(val) => write!(f, "{:02x}", val),
97 Self::I8(val) => write!(f, "{:02x}", val),
98 Self::U32(val) => write!(f, "{:08X}", val),
99 Self::F64(val) => write!(f, "{}", val),
100 Self::Gpsl2pFlag(val) => write!(f, "l2p={:?}", val),
101 Self::GeoHealth(val) => write!(f, "{:?}", val),
102 Self::GalHealth(val) => write!(f, "{:?}", val),
103 Self::GalDataSource(val) => write!(f, "{:?}", val),
104 Self::IrnssHealth(val) => write!(f, "{:?}", val),
105 Self::GlonassHealth(val) => write!(f, "{:?}", val),
106 Self::GlonassStatus(val) => write!(f, "{:?}", val),
107 Self::BdsSatH1(val) => write!(f, "{:?}", val),
108 Self::BdsHealth(val) => write!(f, "{:?}", val),
109 Self::BdsSatelliteType(val) => write!(f, "{:?}", val),
110 Self::GlonassHealth2(val) => write!(f, "{:?}", val),
111 Self::GpsQzssl1cHealth(val) => write!(f, "{:?}", val),
112 Self::GpsQzssl1l2l5Health(val) => write!(f, "{:?}", val),
113 Self::BdsB1cIntegrity(val) => write!(f, "{:?}", val),
114 Self::BdsB2aB1cIntegrity(val) => write!(f, "{:?}", val),
115 Self::BdsB2bIntegrity(val) => write!(f, "{:?}", val),
116 }
117 }
118}
119
120impl From<u32> for OrbitItem {
121 fn from(value: u32) -> Self {
122 Self::U32(value)
123 }
124}
125
126impl From<f64> for OrbitItem {
127 fn from(value: f64) -> Self {
128 Self::F64(value)
129 }
130}
131
132impl OrbitItem {
133 pub fn new(
135 name_str: &str,
136 type_str: &str,
137 val_str: &str,
138 msgtype: &NavMessageType,
139 constellation: Constellation,
140 ) -> Result<OrbitItem, ParsingError> {
141 let float =
143 f64::from_str(&val_str.replace('D', "e")).map_err(|_| ParsingError::NavNullOrbit)?;
144
145 match type_str {
147 "u8" | "i8" | "u32" | "f64" => {
148 if float == 0.0 {
149 return Err(ParsingError::NavNullOrbit);
150 }
151 },
152 _ => {}, }
154
155 match type_str {
157 "u8" => {
158 let unsigned = float.round() as u8;
159 return Ok(OrbitItem::U8(unsigned));
160 },
161
162 "i8" => {
163 let signed = float.round() as i8;
164 return Ok(OrbitItem::I8(signed));
165 },
166
167 "u32" => {
168 let unsigned = float.round() as u32;
169 return Ok(OrbitItem::U32(unsigned));
170 },
171
172 "f64" => {
173 return Ok(OrbitItem::F64(float));
174 },
175 _ => {},
176 };
177
178 match type_str {
180 "flag" => {
181 let unsigned = float.round() as u32;
183
184 match name_str {
185 "health" => {
186 if constellation.is_sbas() {
190 match msgtype {
191 NavMessageType::LNAV | NavMessageType::SBAS => {
192 let flags = GeoHealth::from_bits(unsigned)
193 .ok_or(ParsingError::NavFlagsMapping)?;
194
195 return Ok(OrbitItem::GeoHealth(flags));
196 },
197 _ => return Err(ParsingError::NavHealthFlagDefinition),
198 }
199 }
200
201 match (msgtype, constellation) {
203 (
204 NavMessageType::LNAV | NavMessageType::CNAV,
205 Constellation::GPS | Constellation::QZSS,
206 ) => {
207 let flags = GpsQzssl1l2l5Health::from(unsigned);
208
209 Ok(OrbitItem::GpsQzssl1l2l5Health(flags))
210 },
211 (NavMessageType::CNV2, Constellation::GPS | Constellation::QZSS) => {
212 let flags = GpsQzssl1cHealth::from_bits(unsigned)
213 .ok_or(ParsingError::NavFlagsMapping)?;
214
215 Ok(OrbitItem::GpsQzssl1cHealth(flags))
216 },
217 (
218 NavMessageType::LNAV | NavMessageType::INAV | NavMessageType::FNAV,
219 Constellation::Galileo,
220 ) => {
221 let flags = GalHealth::from_bits(unsigned)
222 .ok_or(ParsingError::NavFlagsMapping)?;
223
224 Ok(OrbitItem::GalHealth(flags))
225 },
226 (
227 NavMessageType::LNAV | NavMessageType::FDMA,
228 Constellation::Glonass,
229 ) => {
230 let flags = GlonassHealth::from_bits(unsigned)
231 .ok_or(ParsingError::NavFlagsMapping)?;
232
233 Ok(OrbitItem::GlonassHealth(flags))
234 },
235 (
236 NavMessageType::LNAV | NavMessageType::D1 | NavMessageType::D2,
237 Constellation::BeiDou,
238 ) => {
239 let flags = BdsSatH1::from_bits(unsigned)
241 .ok_or(ParsingError::NavFlagsMapping)?;
242
243 Ok(OrbitItem::BdsSatH1(flags))
244 },
245 (
246 NavMessageType::CNV1 | NavMessageType::CNV2 | NavMessageType::CNV3,
247 Constellation::BeiDou,
248 ) => {
249 let flags = BdsHealth::from(unsigned);
251
252 Ok(OrbitItem::BdsHealth(flags))
253 },
254 _ => Err(ParsingError::NavHealthFlagDefinition),
255 }
256 },
257 "health2" => {
258 match (msgtype, constellation) {
260 (NavMessageType::FDMA, Constellation::Glonass) => {
261 let flags = GlonassHealth2::from_bits(unsigned)
262 .ok_or(ParsingError::NavFlagsMapping)?;
263
264 Ok(OrbitItem::GlonassHealth2(flags))
265 },
266 _ => Err(ParsingError::NavHealthFlagDefinition),
267 }
268 },
269 "source" => {
270 match (msgtype, constellation) {
272 (
273 NavMessageType::LNAV | NavMessageType::INAV | NavMessageType::FNAV,
274 Constellation::Galileo,
275 ) => {
276 let flags = GalDataSource::from_bits(unsigned)
277 .ok_or(ParsingError::NavFlagsMapping)?;
278
279 Ok(OrbitItem::GalDataSource(flags))
280 },
281 _ => Err(ParsingError::NavDataSourceDefinition),
282 }
283 },
284 "satType" => match (msgtype, constellation) {
285 (NavMessageType::CNV1 | NavMessageType::CNV2, Constellation::BeiDou) => {
286 let flags = BdsSatelliteType::from(unsigned);
287
288 Ok(OrbitItem::BdsSatelliteType(flags))
289 },
290 _ => Err(ParsingError::NavDataSourceDefinition),
291 },
292 "integrity" => match (msgtype, constellation) {
293 (NavMessageType::CNV1, Constellation::BeiDou) => {
294 let flags = BdsB1cIntegrity::from_bits(unsigned)
295 .ok_or(ParsingError::NavFlagsMapping)?;
296
297 Ok(OrbitItem::BdsB1cIntegrity(flags))
298 },
299 (NavMessageType::CNV2, Constellation::BeiDou) => {
300 let flags = BdsB2aB1cIntegrity::from_bits(unsigned)
301 .ok_or(ParsingError::NavFlagsMapping)?;
302
303 Ok(OrbitItem::BdsB2aB1cIntegrity(flags))
304 },
305 (NavMessageType::CNV3, Constellation::BeiDou) => {
306 let flags = BdsB2bIntegrity::from_bits(unsigned)
307 .ok_or(ParsingError::NavFlagsMapping)?;
308
309 Ok(OrbitItem::BdsB2bIntegrity(flags))
310 },
311 _ => Err(ParsingError::NavDataSourceDefinition),
312 },
313 "status" => {
314 match (msgtype, constellation) {
316 (NavMessageType::FDMA, Constellation::Glonass) => {
317 let flags = GlonassStatus::from(unsigned);
318
319 Ok(OrbitItem::GlonassStatus(flags))
320 },
321 _ => Err(ParsingError::NavHealthFlagDefinition),
322 }
323 },
324 "l2p" => {
325 Ok(OrbitItem::Gpsl2pFlag(unsigned > 0))
327 },
328 _ => Err(ParsingError::NavFlagsDefinition),
329 }
330 },
331 _ => {
332 Err(ParsingError::NavUnknownComplexType)
334 },
335 }
336 }
337
338 pub fn as_f64(&self) -> f64 {
340 match self {
341 OrbitItem::F64(f) => *f,
342 OrbitItem::U8(val) => *val as f64,
343 OrbitItem::I8(val) => *val as f64,
344 OrbitItem::U32(val) => *val as f64,
345 OrbitItem::Gpsl2pFlag(flag) => (*flag as u8) as f64,
346 OrbitItem::GalHealth(flags) => flags.bits() as f64,
347 OrbitItem::GpsQzssl1cHealth(flags) => flags.bits() as f64,
348 OrbitItem::GpsQzssl1l2l5Health(flags) => flags.0 as f64,
349 OrbitItem::GeoHealth(flags) => flags.bits() as f64,
350 OrbitItem::IrnssHealth(flags) => flags.bits() as f64,
351 OrbitItem::GlonassHealth(flags) => flags.bits() as f64,
352 OrbitItem::GlonassStatus(status) => status.0 as f64,
353 OrbitItem::GalDataSource(source) => source.bits() as f64,
354 OrbitItem::GlonassHealth2(health) => health.bits() as f64,
355 OrbitItem::BdsSatH1(sat_h1) => sat_h1.bits() as f64,
356 OrbitItem::BdsHealth(health) => (*health as u32) as f64,
357 OrbitItem::BdsSatelliteType(sat) => (*sat as u32) as f64,
358 OrbitItem::BdsB1cIntegrity(integrity) => integrity.bits() as f64,
359 OrbitItem::BdsB2aB1cIntegrity(integrity) => integrity.bits() as f64,
360 OrbitItem::BdsB2bIntegrity(integrity) => integrity.bits() as f64,
361 }
362 }
363
364 pub fn as_u32(&self) -> u32 {
366 match self {
367 OrbitItem::U32(v) => *v,
368 OrbitItem::U8(val) => *val as u32,
369 OrbitItem::I8(val) => *val as u32,
370 OrbitItem::F64(val) => val.round() as u32,
371 OrbitItem::Gpsl2pFlag(flag) => *flag as u32,
372 OrbitItem::GalHealth(health) => health.bits(),
373 OrbitItem::GpsQzssl1cHealth(flags) => flags.bits(),
374 OrbitItem::GpsQzssl1l2l5Health(flags) => flags.0,
375 OrbitItem::GeoHealth(health) => health.bits(),
376 OrbitItem::IrnssHealth(health) => health.bits(),
377 OrbitItem::GlonassHealth(health) => health.bits(),
378 OrbitItem::GlonassStatus(status) => status.0,
379 OrbitItem::GalDataSource(source) => source.bits(),
380 OrbitItem::GlonassHealth2(health) => health.bits(),
381 OrbitItem::BdsSatH1(sat_h1) => sat_h1.bits(),
382 OrbitItem::BdsHealth(health) => *health as u32,
383 OrbitItem::BdsSatelliteType(sat) => *sat as u32,
384 OrbitItem::BdsB1cIntegrity(integrity) => integrity.bits(),
385 OrbitItem::BdsB2aB1cIntegrity(integrity) => integrity.bits(),
386 OrbitItem::BdsB2bIntegrity(integrity) => integrity.bits(),
387 }
388 }
389
390 pub fn as_u8(&self) -> u8 {
392 match self {
393 OrbitItem::U32(v) => *v as u8,
394 OrbitItem::U8(val) => *val,
395 OrbitItem::I8(val) => *val as u8,
396 OrbitItem::F64(val) => val.round() as u8,
397 OrbitItem::Gpsl2pFlag(flag) => *flag as u8,
398 OrbitItem::GalHealth(health) => health.bits() as u8,
399 OrbitItem::GpsQzssl1cHealth(flags) => flags.bits() as u8,
400 OrbitItem::GpsQzssl1l2l5Health(flags) => flags.0 as u8,
401 OrbitItem::GeoHealth(health) => health.bits() as u8,
402 OrbitItem::IrnssHealth(health) => health.bits() as u8,
403 OrbitItem::GlonassHealth(health) => health.bits() as u8,
404 OrbitItem::GlonassStatus(status) => status.0 as u8,
405 OrbitItem::GlonassHealth2(health) => health.bits() as u8,
406 OrbitItem::GalDataSource(source) => source.bits() as u8,
407 OrbitItem::BdsSatH1(sat_h1) => sat_h1.bits() as u8,
408 OrbitItem::BdsHealth(health) => (*health as u32) as u8,
409 OrbitItem::BdsSatelliteType(sat) => (*sat as u32) as u8,
410 OrbitItem::BdsB1cIntegrity(integrity) => integrity.bits() as u8,
411 OrbitItem::BdsB2aB1cIntegrity(integrity) => integrity.bits() as u8,
412 OrbitItem::BdsB2bIntegrity(integrity) => integrity.bits() as u8,
413 }
414 }
415
416 pub fn as_i8(&self) -> i8 {
418 match self {
419 OrbitItem::U32(v) => *v as i8,
420 OrbitItem::I8(val) => *val,
421 OrbitItem::U8(val) => *val as i8,
422 OrbitItem::F64(val) => val.round() as i8,
423 OrbitItem::Gpsl2pFlag(flag) => *flag as i8,
424 OrbitItem::GalHealth(health) => health.bits() as i8,
425 OrbitItem::GpsQzssl1cHealth(flags) => flags.bits() as i8,
426 OrbitItem::GpsQzssl1l2l5Health(flags) => flags.0 as i8,
427 OrbitItem::GeoHealth(health) => health.bits() as i8,
428 OrbitItem::IrnssHealth(health) => health.bits() as i8,
429 OrbitItem::GlonassHealth(health) => health.bits() as i8,
430 OrbitItem::GlonassStatus(status) => status.0 as i8,
431 OrbitItem::GalDataSource(source) => source.bits() as i8,
432 OrbitItem::GlonassHealth2(health) => health.bits() as i8,
433 OrbitItem::BdsSatH1(sat_h1) => sat_h1.bits() as i8,
434 OrbitItem::BdsHealth(health) => (*health as u32) as i8,
435 OrbitItem::BdsSatelliteType(sat) => (*sat as u32) as i8,
436 OrbitItem::BdsB1cIntegrity(integrity) => integrity.bits() as i8,
437 OrbitItem::BdsB2aB1cIntegrity(integrity) => integrity.bits() as i8,
438 OrbitItem::BdsB2bIntegrity(integrity) => integrity.bits() as i8,
439 }
440 }
441
442 pub fn as_gps_l2p_flag(&self) -> Option<bool> {
444 match self {
445 OrbitItem::Gpsl2pFlag(flag) => Some(*flag),
446 _ => None,
447 }
448 }
449
450 pub fn as_gps_qzss_l1l2l5_health_flag(&self) -> Option<GpsQzssl1l2l5Health> {
452 match self {
453 OrbitItem::GpsQzssl1l2l5Health(h) => Some(h.clone()),
454 _ => None,
455 }
456 }
457
458 pub fn as_gps_qzss_l1c_health_flag(&self) -> Option<GpsQzssl1cHealth> {
460 match self {
461 OrbitItem::GpsQzssl1cHealth(h) => Some(h.clone()),
462 _ => None,
463 }
464 }
465
466 pub fn as_geo_health_flag(&self) -> Option<GeoHealth> {
468 match self {
469 OrbitItem::GeoHealth(h) => Some(h.clone()),
470 _ => None,
471 }
472 }
473
474 pub fn as_glonass_health_flag(&self) -> Option<GlonassHealth> {
476 match self {
477 OrbitItem::GlonassHealth(h) => Some(h.clone()),
478 _ => None,
479 }
480 }
481
482 pub fn as_glonass_health2_flag(&self) -> Option<GlonassHealth2> {
484 match self {
485 OrbitItem::GlonassHealth2(h) => Some(h.clone()),
486 _ => None,
487 }
488 }
489
490 pub fn as_glonass_status_mask(&self) -> Option<GlonassStatus> {
492 match self {
493 OrbitItem::GlonassStatus(h) => Some(h.clone()),
494 _ => None,
495 }
496 }
497
498 pub fn as_galileo_health_flag(&self) -> Option<GalHealth> {
500 match self {
501 OrbitItem::GalHealth(h) => Some(*h),
502 _ => None,
503 }
504 }
505
506 pub fn as_bds_sat_h1_flag(&self) -> Option<BdsSatH1> {
508 match self {
509 OrbitItem::BdsSatH1(h) => Some(h.clone()),
510 _ => None,
511 }
512 }
513
514 pub fn as_bds_health_flag(&self) -> Option<BdsHealth> {
516 match self {
517 OrbitItem::BdsHealth(h) => Some(h.clone()),
518 _ => None,
519 }
520 }
521
522 pub fn as_bds_satellite_type(&self) -> Option<BdsSatelliteType> {
524 match self {
525 OrbitItem::BdsSatelliteType(h) => Some(h.clone()),
526 _ => None,
527 }
528 }
529
530 pub fn as_bds_b1c_integrity(&self) -> Option<BdsB1cIntegrity> {
532 match self {
533 OrbitItem::BdsB1cIntegrity(h) => Some(h.clone()),
534 _ => None,
535 }
536 }
537
538 pub fn as_bds_b2a_b1c_integrity(&self) -> Option<BdsB2aB1cIntegrity> {
540 match self {
541 OrbitItem::BdsB2aB1cIntegrity(h) => Some(h.clone()),
542 _ => None,
543 }
544 }
545
546 pub fn as_bds_b2b_integrity(&self) -> Option<BdsB2bIntegrity> {
548 match self {
549 OrbitItem::BdsB2bIntegrity(h) => Some(h.clone()),
550 _ => None,
551 }
552 }
553
554 pub fn as_irnss_health_flag(&self) -> Option<IrnssHealth> {
556 match self {
557 OrbitItem::IrnssHealth(h) => Some(h.clone()),
558 _ => None,
559 }
560 }
561}
562
563pub(crate) fn closest_nav_standards(
569 constellation: Constellation,
570 revision: Version,
571 msg: NavMessageType,
572) -> Option<&'static NavHelper<'static>> {
573 let database = &NAV_ORBITS;
574 let (mut major, mut minor): (u8, u8) = revision.into();
577
578 loop {
579 let items: Vec<_> = database
581 .iter()
582 .filter(|item| {
583 item.constellation == constellation
584 && item.msg == msg
585 && item.version == Version::new(major, minor)
586 })
587 .collect();
588
589 if items.is_empty() {
590 if minor == 0 {
591 if major == 0 {
596 break;
598 } else {
599 major -= 1;
600 minor = 10;
601 }
602 } else {
603 minor -= 1;
604 }
605 } else {
606 return Some(items[0]);
607 }
608 } None
611}
612
613#[cfg(test)]
614mod test {
615 use super::*;
616 use crate::navigation::NavMessageType;
617
618 #[test]
619 fn orbit_database_sanity() {
620 for frame in NAV_ORBITS.iter() {
621 let nav_msg = frame.msg;
622 let constellation = frame.constellation;
623
624 for (name_str, type_str) in frame.items.iter() {
625 let val_str = "1.2345";
626
627 let e = OrbitItem::new(name_str, type_str, val_str, &nav_msg, constellation);
628 assert!(
629 e.is_ok(),
630 "{}({}) {}:{} orbit item failed",
631 constellation,
632 nav_msg,
633 name_str,
634 type_str,
635 );
636 }
637 }
638 }
639
640 #[test]
641 fn nav_standards_finder() {
642 assert_eq!(
644 closest_nav_standards(
645 Constellation::Mixed,
646 Version::default(),
647 NavMessageType::LNAV
648 ),
649 None,
650 "Mixed GNSS constellation is or should not exist in the DB"
651 );
652
653 for (constellation, rev, msg) in [
655 (Constellation::GPS, Version::new(1, 0), NavMessageType::LNAV),
656 (Constellation::GPS, Version::new(2, 0), NavMessageType::LNAV),
657 (Constellation::GPS, Version::new(4, 0), NavMessageType::LNAV),
658 (Constellation::GPS, Version::new(4, 0), NavMessageType::CNAV),
659 (Constellation::GPS, Version::new(4, 0), NavMessageType::CNV2),
660 (
661 Constellation::Glonass,
662 Version::new(2, 0),
663 NavMessageType::LNAV,
664 ),
665 (
666 Constellation::Glonass,
667 Version::new(3, 0),
668 NavMessageType::LNAV,
669 ),
670 (
671 Constellation::Galileo,
672 Version::new(3, 0),
673 NavMessageType::LNAV,
674 ),
675 (
676 Constellation::Galileo,
677 Version::new(4, 0),
678 NavMessageType::INAV,
679 ),
680 (
681 Constellation::Galileo,
682 Version::new(4, 0),
683 NavMessageType::FNAV,
684 ),
685 (
686 Constellation::QZSS,
687 Version::new(3, 0),
688 NavMessageType::LNAV,
689 ),
690 (
691 Constellation::QZSS,
692 Version::new(4, 0),
693 NavMessageType::LNAV,
694 ),
695 (
696 Constellation::QZSS,
697 Version::new(4, 0),
698 NavMessageType::CNAV,
699 ),
700 (
701 Constellation::QZSS,
702 Version::new(4, 0),
703 NavMessageType::CNV2,
704 ),
705 (
706 Constellation::BeiDou,
707 Version::new(3, 0),
708 NavMessageType::LNAV,
709 ),
710 (
712 Constellation::BeiDou,
713 Version::new(4, 0),
714 NavMessageType::D1,
715 ),
716 (
717 Constellation::BeiDou,
718 Version::new(4, 0),
719 NavMessageType::D2,
720 ),
721 (
722 Constellation::BeiDou,
723 Version::new(4, 0),
724 NavMessageType::CNV1,
725 ),
726 (
727 Constellation::BeiDou,
728 Version::new(4, 0),
729 NavMessageType::CNV2,
730 ),
731 (
732 Constellation::BeiDou,
733 Version::new(4, 0),
734 NavMessageType::CNV3,
735 ),
736 (
737 Constellation::SBAS,
738 Version::new(4, 0),
739 NavMessageType::SBAS,
740 ),
741 ] {
742 let found = closest_nav_standards(constellation, rev, msg);
743 assert!(
744 found.is_some(),
745 "should have identified {}:V{} ({}) frame that actually exists in DB",
746 constellation,
747 rev,
748 msg
749 );
750
751 let standards = found.unwrap();
752
753 assert!(
754 standards.constellation == constellation,
755 "bad constellation identified \"{}\", expecting \"{}\"",
756 constellation,
757 standards.constellation
758 );
759
760 assert!(
761 standards.version == rev,
762 "should have matched {} V{} exactly, because it exists in DB",
763 constellation,
764 rev,
765 );
766 }
767
768 for (constellation, desired, expected, msg) in [
770 (
771 Constellation::GPS,
772 Version::new(5, 0),
773 Version::new(4, 0),
774 NavMessageType::LNAV,
775 ),
776 (
777 Constellation::GPS,
778 Version::new(4, 1),
779 Version::new(4, 0),
780 NavMessageType::LNAV,
781 ),
782 (
783 Constellation::Glonass,
784 Version::new(3, 4),
785 Version::new(3, 0),
786 NavMessageType::LNAV,
787 ),
788 (
789 Constellation::BeiDou,
790 Version::new(4, 2),
791 Version::new(4, 0),
792 NavMessageType::CNV1,
793 ),
794 (
795 Constellation::BeiDou,
796 Version::new(4, 2),
797 Version::new(4, 0),
798 NavMessageType::CNV2,
799 ),
800 (
801 Constellation::BeiDou,
802 Version::new(4, 2),
803 Version::new(4, 0),
804 NavMessageType::CNV3,
805 ),
806 (
807 Constellation::Galileo,
808 Version::new(4, 2),
809 Version::new(4, 0),
810 NavMessageType::INAV,
811 ),
812 (
813 Constellation::QZSS,
814 Version::new(4, 2),
815 Version::new(4, 0),
816 NavMessageType::LNAV,
817 ),
818 (
819 Constellation::QZSS,
820 Version::new(4, 2),
821 Version::new(4, 0),
822 NavMessageType::CNAV,
823 ),
824 ] {
825 let found = closest_nav_standards(constellation, desired, msg);
826
827 assert!(
828 found.is_some(),
829 "should have converged for \"{}\" V\"{}\" (\"{}\") to nearest frame revision",
830 constellation,
831 desired,
832 msg
833 );
834
835 let standards = found.unwrap();
836
837 assert!(
838 standards.constellation == constellation,
839 "bad constellation identified \"{}\", expecting \"{}\"",
840 constellation,
841 standards.constellation
842 );
843
844 assert!(
845 standards.version == expected,
846 "closest_nav_standards() converged to wrong revision {}:{}({}) while \"{}\" was expected",
847 constellation,
848 desired,
849 msg,
850 expected);
851 }
852 }
853
854 #[test]
855 fn test_db_item() {
856 let e = OrbitItem::U8(10);
857 assert_eq!(e.as_u8(), 10);
858
859 let e = OrbitItem::F64(10.0);
860 assert_eq!(e.as_u8(), 10);
861 assert_eq!(e.as_u32(), 10);
862 assert_eq!(e.as_f64(), 10.0);
863
864 let e = OrbitItem::U32(1);
865 assert_eq!(e.as_u32(), 1);
866 assert_eq!(e.as_f64(), 1.0);
867 }
868
869 #[test]
870 fn test_orbit_channel_5() {
871 let lnav = NavMessageType::LNAV;
872
873 let _ = OrbitItem::new(
874 "channel",
875 "i8",
876 "5.000000000000D+00",
877 &lnav,
878 Constellation::Glonass,
879 )
880 .unwrap();
881 }
882}