rinex/navigation/
frame.rs

1use crate::{
2    navigation::{EarthOrientation, Ephemeris, IonosphereModel, TimeOffset},
3    prelude::ParsingError,
4};
5
6#[cfg(doc)]
7use crate::prelude::TimeScale;
8
9#[cfg(feature = "serde")]
10use serde::{Deserialize, Serialize};
11
12/// Navigation Frame classes, describes the [NavFrame] to follow.
13#[derive(Default, Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
14#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
15pub enum NavFrameType {
16    /// Ephemeris frames, exists in all RINEX revisions.
17    #[default]
18    Ephemeris,
19
20    /// System Time Offset frames, only exist in newer revisions.
21    SystemTimeOffset,
22
23    /// Earth Orientation frames, only exist in newer revisions.
24    EarthOrientation,
25
26    /// Ionosphere models, only exist in newer revisions.
27    IonosphereModel,
28}
29
30impl std::fmt::Display for NavFrameType {
31    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
32        match self {
33            Self::Ephemeris => f.write_str("EPH"),
34            Self::SystemTimeOffset => f.write_str("STO"),
35            Self::EarthOrientation => f.write_str("EOP"),
36            Self::IonosphereModel => f.write_str("ION"),
37        }
38    }
39}
40
41impl std::str::FromStr for NavFrameType {
42    type Err = ParsingError;
43    fn from_str(s: &str) -> Result<Self, Self::Err> {
44        let c = s.to_uppercase();
45        let c = c.trim();
46        match c {
47            "EPH" => Ok(Self::Ephemeris),
48            "STO" => Ok(Self::SystemTimeOffset),
49            "EOP" => Ok(Self::EarthOrientation),
50            "ION" => Ok(Self::IonosphereModel),
51            _ => Err(ParsingError::NavFrameClass),
52        }
53    }
54}
55
56/// [NavFrame] describes the navigation message to follow.
57/// Several types exist
58#[derive(Debug, Clone, PartialEq)]
59#[cfg_attr(feature = "serde", derive(Serialize))]
60pub enum NavFrame {
61    /// [Ephemeris] exist in all revisions and give
62    /// the (interpreted) content of the radio message.
63    /// Usually aligned at midnight and published at
64    EPH(Ephemeris),
65
66    /// [EarthOrientation] frames appeared in RINEXv4 to describe
67    /// the Earth state precisely.
68    EOP(EarthOrientation),
69
70    /// [IonosphereModel]s were introduced in RINEXv4 to describe
71    /// the state of the ionosphere during the day course. Until
72    /// RINEXv3 (included), the model is refreshed once per RINEX publication,
73    /// so usually a 24h period.
74    ION(IonosphereModel),
75
76    /// [TimeOffset] frames were introduced in RINEXv4 to describe
77    /// the state of GNSS [Timescale]s more precisely during the course of the day.
78    /// Until RINEXv3 (included), their state is updated one per RINEX publication,
79    /// so typically once per day.
80    STO(TimeOffset),
81}
82
83impl NavFrame {
84    /// Unwrap this [NavFrame] as [Ephemeris] (if possible).
85    pub fn as_ephemeris(&self) -> Option<&Ephemeris> {
86        match self {
87            Self::EPH(eph) => Some(eph),
88            _ => None,
89        }
90    }
91
92    /// Unwrap this [NavFrame] as mutable [Ephemeris] (if possible).
93    pub fn as_mut_ephemeris(&mut self) -> Option<&mut Ephemeris> {
94        match self {
95            Self::EPH(eph) => Some(eph),
96            _ => None,
97        }
98    }
99
100    /// Unwrap this [NavFrame] as [TimeOffset] (if possible).
101    pub fn as_system_time(&self) -> Option<&TimeOffset> {
102        match self {
103            Self::STO(fr) => Some(fr),
104            _ => None,
105        }
106    }
107
108    /// Unwrap this [NavFrame] as mutable [TimeOffset] (if possible).
109    pub fn as_mut_system_time(&mut self) -> Option<&mut TimeOffset> {
110        match self {
111            Self::STO(fr) => Some(fr),
112            _ => None,
113        }
114    }
115
116    /// Unwrap this [NavFrame] as [IonosphereModel] (if possible).
117    pub fn as_ionosphere_model(&self) -> Option<&IonosphereModel> {
118        match self {
119            Self::ION(fr) => Some(fr),
120            _ => None,
121        }
122    }
123
124    /// Unwrap this [NavFrame] as mutable [IonosphereModel] (if possible).
125    pub fn as_mut_ionosphere_model(&mut self) -> Option<&mut IonosphereModel> {
126        match self {
127            Self::ION(fr) => Some(fr),
128            _ => None,
129        }
130    }
131
132    /// Unwrap this [NavFrame] as [EarthOrientation] parameters (if possible).
133    pub fn as_earth_orientation(&self) -> Option<&EarthOrientation> {
134        match self {
135            Self::EOP(fr) => Some(fr),
136            _ => None,
137        }
138    }
139
140    /// Unwrap this [NavFrame] as mutable [EarthOrientation] parameters (if possible).
141    pub fn as_mut_earth_orientation(&mut self) -> Option<&mut EarthOrientation> {
142        match self {
143            Self::EOP(fr) => Some(fr),
144            _ => None,
145        }
146    }
147}