Skip to content

Commit 91c63dc

Browse files
authored
NAV (V2, V3, Partial V4) formatting (#328)
* Navgation (ephemeris) frames formatting * NAV (V2) validated * NAV (V3) validated * Ionospheric terms validated --------- Signed-off-by: Guillaume W. Bres <guillaume.bressaix@gmail.com>
1 parent a5c10e6 commit 91c63dc

File tree

13 files changed

+449
-101
lines changed

13 files changed

+449
-101
lines changed

src/error.rs

+2
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,8 @@ pub enum FormattingError {
173173
OutputError(#[from] IoError),
174174
#[error("missing constellation information")]
175175
NoConstellationDefinition,
176+
#[error("missing navigation standard specs")]
177+
MissingNavigationStandards,
176178
#[error("undefined observables")]
177179
UndefinedObservables,
178180
#[error("missing observable definition")]

src/header/formatting.rs

+19
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
//! RINEX header formatting
22
3+
use gnss::constellation;
4+
35
use crate::{
46
fmt_comment, fmt_rinex,
57
header::Header,
@@ -14,6 +16,8 @@ impl Header {
1416
pub fn format<W: Write>(&self, w: &mut BufWriter<W>) -> Result<(), FormattingError> {
1517
const NUM_GLO_CHANNELS_PER_LINE: usize = 8;
1618

19+
let major = self.version.major;
20+
1721
if let Some(obs) = &self.obs {
1822
if let Some(crinex) = &obs.crinex {
1923
crinex.format(w)?;
@@ -92,6 +96,21 @@ impl Header {
9296
)?;
9397
}
9498

99+
// KB model
100+
for (index, (constellation, model)) in self.ionod_corrections.iter().enumerate() {
101+
if let Some(kb) = model.as_klobuchar() {
102+
if major == 2 && index == 0 {
103+
kb.format_v2_header(w)?;
104+
} else if major == 3 {
105+
kb.format_v3_header(w, *constellation)?;
106+
}
107+
} else if let Some(ng) = model.as_nequick_g() {
108+
if major == 3 {
109+
ng.format_header(w, constellation)?;
110+
}
111+
}
112+
}
113+
95114
//TODO
96115
// things that could be nice to squeeze in:
97116
// [+] SBAS detail (detailed vehicle identity)

src/lib.rs

+6-5
Original file line numberDiff line numberDiff line change
@@ -95,11 +95,12 @@ use flate2::{read::GzDecoder, write::GzEncoder, Compression as GzCompression};
9595
#[cfg(feature = "clock")]
9696
use std::collections::BTreeMap;
9797

98-
use epoch::epoch_decompose;
99-
use hatanaka::CRINEX;
100-
use observable::Observable;
101-
102-
use production::{DataSource, DetailedProductionAttributes, ProductionAttributes, FFU, PPU};
98+
use crate::{
99+
epoch::epoch_decompose,
100+
hatanaka::CRINEX,
101+
observable::Observable,
102+
production::{DataSource, DetailedProductionAttributes, ProductionAttributes, FFU, PPU},
103+
};
103104

104105
/// Package to include all basic structures
105106
pub mod prelude {
+126
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
//! Ephemeris message formatting
2+
use crate::{
3+
navigation::{
4+
formatting::NavFormatter, orbits::closest_nav_standards, Ephemeris, NavMessageType,
5+
},
6+
prelude::{Constellation, SV},
7+
FormattingError, Version,
8+
};
9+
10+
use std::io::{BufWriter, Write};
11+
12+
impl Ephemeris {
13+
/// Formats [Ephemeris] according to RINEX standards
14+
pub(crate) fn format<W: Write>(
15+
&self,
16+
w: &mut BufWriter<W>,
17+
sv: SV,
18+
version: Version,
19+
msgtype: NavMessageType,
20+
) -> Result<(), FormattingError> {
21+
let sv_constellation = if sv.constellation.is_sbas() {
22+
Constellation::SBAS
23+
} else {
24+
sv.constellation
25+
};
26+
27+
// retrieve standard specs
28+
let standard_specs = match closest_nav_standards(sv_constellation, version, msgtype) {
29+
Some(specs) => specs,
30+
None => {
31+
return Err(FormattingError::MissingNavigationStandards);
32+
},
33+
};
34+
35+
// starts with (clock_bias, drift, rate)
36+
// epoch has already been buffered
37+
write!(
38+
w,
39+
"{}{}{}",
40+
NavFormatter::new(self.clock_bias),
41+
NavFormatter::new(self.clock_drift),
42+
NavFormatter::new(self.clock_drift_rate),
43+
)?;
44+
45+
// following standard specs
46+
let data_fields = &standard_specs.items;
47+
for i in 0..data_fields.len() {
48+
if let Some(value) = self.get_orbit_f64(data_fields[i].0) {
49+
if i % 4 == 0 {
50+
write!(w, "\n {}", NavFormatter::new(value))?;
51+
} else {
52+
write!(w, "{}", NavFormatter::new(value))?;
53+
}
54+
} else {
55+
if i % 4 == 0 {
56+
write!(w, "\n {}", NavFormatter::new(0.0))?;
57+
} else {
58+
write!(w, "{}", NavFormatter::new(0.0))?;
59+
}
60+
}
61+
}
62+
63+
write!(w, "\n")?;
64+
Ok(())
65+
}
66+
}
67+
68+
#[cfg(test)]
69+
mod test {
70+
71+
use crate::navigation::{Ephemeris, NavMessageType, OrbitItem};
72+
use crate::prelude::{Version, SV};
73+
74+
use std::io::BufWriter;
75+
use std::str::FromStr;
76+
77+
use crate::tests::formatting::Utf8Buffer;
78+
79+
#[test]
80+
fn test_value_formatter() {}
81+
82+
#[test]
83+
fn ephemeris_formatting() {
84+
let g01 = SV::from_str("G01").unwrap();
85+
let version = Version::from_str("2.0").unwrap();
86+
let msgtype = NavMessageType::LNAV;
87+
88+
let ephemeris = Ephemeris {
89+
clock_bias: -1.0e-4,
90+
clock_drift: -2.0e-11,
91+
clock_drift_rate: 0.0,
92+
orbits: [
93+
("iode".to_string(), OrbitItem::F64(1.0)),
94+
("crs".to_string(), OrbitItem::F64(2.0)),
95+
("deltaN".to_string(), OrbitItem::F64(3.0)),
96+
("4".to_string(), OrbitItem::F64(4.0)),
97+
("cuc".to_string(), OrbitItem::F64(5.0)),
98+
]
99+
.into_iter()
100+
.collect(),
101+
};
102+
103+
let utf8 = Utf8Buffer::new(1024);
104+
let mut writer = BufWriter::new(utf8);
105+
106+
ephemeris
107+
.format(&mut writer, g01, version, msgtype)
108+
.unwrap();
109+
110+
let inner = writer.into_inner().unwrap();
111+
112+
let utf8 = inner.to_ascii_utf8();
113+
114+
assert_eq!(
115+
utf8,
116+
"-1.000000000000E-04-2.000000000000E-11 0.000000000000E+00
117+
1.000000000000E+00 2.000000000000E+00 3.000000000000E+00 0.000000000000E+00
118+
5.000000000000E+00 0.000000000000E+00 0.000000000000E+00 0.000000000000E+00
119+
0.000000000000E+00 0.000000000000E+00 0.000000000000E+00 0.000000000000E+00
120+
0.000000000000E+00 0.000000000000E+00 0.000000000000E+00 0.000000000000E+00
121+
0.000000000000E+00 0.000000000000E+00 0.000000000000E+00 0.000000000000E+00
122+
0.000000000000E+00 0.000000000000E+00 0.000000000000E+00 0.000000000000E+00
123+
0.000000000000E+00 0.000000000000E+00\n"
124+
);
125+
}
126+
}

src/navigation/ephemeris/mod.rs

+1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
mod formatting;
12
mod parsing;
23

34
#[cfg(feature = "log")]

0 commit comments

Comments
 (0)