use thiserror::Error;
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
mod method;
mod modeling;
mod solver;
pub use crate::{
carrier::Signal,
cfg::solver::SolverOpts,
cfg::{method::Method, modeling::Modeling},
prelude::TimeScale,
};
#[derive(Debug, Error)]
pub enum Error {
#[error("invalid troposphere model")]
InvalidTroposphereModel,
#[error("invalid user profile")]
InvalidUserProfile,
#[error("invalid clock profile")]
InvalidClockProfile,
}
const fn default_timescale() -> TimeScale {
TimeScale::GPST
}
const fn max_tropo_bias() -> f64 {
30.0
}
const fn max_iono_bias() -> f64 {
10.0
}
const fn min_sv_elev() -> Option<f64> {
Some(12.5)
}
const fn default_code_smoothing() -> usize {
0
}
const fn default_eclipse_rate_percent() -> f64 {
10.0
}
#[derive(Default, Debug, Clone, PartialEq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct InternalDelay {
pub delay: f64,
pub frequency: f64,
}
#[derive(Debug, Clone)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct Config {
#[cfg_attr(feature = "serde", serde(default = "default_timescale"))]
pub timescale: TimeScale,
#[cfg_attr(feature = "serde", serde(default))]
pub method: Method,
#[cfg_attr(feature = "serde", serde(default))]
pub prefered_signal: Option<Signal>,
#[cfg_attr(feature = "serde", serde(default))]
pub fixed_altitude: Option<f64>,
#[cfg_attr(feature = "serde", serde(default = "default_code_smoothing"))]
pub code_smoothing: usize,
#[cfg_attr(feature = "serde", serde(default))]
pub int_delay: Vec<InternalDelay>,
#[cfg_attr(feature = "serde", serde(default))]
pub arp_enu: Option<(f64, f64, f64)>,
#[cfg_attr(feature = "serde", serde(default))]
pub solver: SolverOpts,
#[cfg_attr(feature = "serde", serde(default))]
pub externalref_delay_s: Option<f64>,
#[cfg_attr(
feature = "serde",
serde(alias = "max_eclipse_rate", default = "default_eclipse_rate_percent")
)]
pub max_eclipse_rate_percent: f64,
#[cfg_attr(feature = "serde", serde(default = "min_sv_elev"))]
pub min_sv_elev: Option<f64>,
#[cfg_attr(feature = "serde", serde(default))]
pub min_sv_azim: Option<f64>,
#[cfg_attr(feature = "serde", serde(default))]
pub max_sv_azim: Option<f64>,
#[cfg_attr(feature = "serde", serde(default))]
pub min_snr: Option<f64>,
#[cfg_attr(feature = "serde", serde(default = "max_tropo_bias"))]
pub max_tropo_bias: f64,
#[cfg_attr(feature = "serde", serde(default = "max_iono_bias"))]
pub max_iono_bias: f64,
#[cfg_attr(feature = "serde", serde(default))]
pub modeling: Modeling,
}
impl Default for Config {
fn default() -> Self {
Self {
timescale: default_timescale(),
method: Method::default(),
solver: SolverOpts::default(),
int_delay: Default::default(),
modeling: Modeling::default(),
fixed_altitude: None,
prefered_signal: None,
arp_enu: None,
min_snr: None, min_sv_azim: None,
max_sv_azim: None,
externalref_delay_s: None,
min_sv_elev: min_sv_elev(),
max_iono_bias: max_iono_bias(),
max_tropo_bias: max_tropo_bias(),
code_smoothing: default_code_smoothing(),
max_eclipse_rate_percent: default_eclipse_rate_percent(),
}
}
}
impl Config {
pub fn with_navigation_method(&self, method: Method) -> Self {
let mut s = self.clone();
s.method = method;
s
}
pub fn with_modeling(&self, modeling: Modeling) -> Self {
let mut s = self.clone();
s.modeling = modeling;
s
}
}
#[cfg(test)]
#[cfg(feature = "serde")]
mod test {
use super::*;
use std::io::Write;
#[test]
fn generate_default_preset() {
let cfg = Config::default();
let string = serde_json::to_string_pretty(&cfg).unwrap();
let mut fd = std::fs::File::create("default.json").unwrap();
write!(fd, "{}", string).unwrap();
}
}