Skip to content

Commit 066fe66

Browse files
authored
Added functions for constructing objects from SBP messages (#42)
1 parent 4316990 commit 066fe66

File tree

6 files changed

+217
-4
lines changed

6 files changed

+217
-4
lines changed

Cargo.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,11 @@ readme = "README.md"
88
repository = "https://github.com/swift-nav/swiftnav-rs"
99
license = "LGPL-3.0"
1010

11+
[features]
12+
sbp-conversions = ["sbp"]
13+
1114
[dependencies]
15+
sbp = { git = "https://github.com/swift-nav/libsbp.git", rev="51660bd02f18216aef7abcdebf27fec72a93c161", optional = true }
1216

1317
[build-dependencies]
1418
bindgen = "0.57"

Jenkinsfile

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ pipeline {
2424
steps {
2525
gitPrep()
2626
script {
27-
sh("cargo check")
27+
sh("cargo check --all-targets --all-features")
2828
}
2929
}
3030
}
@@ -50,7 +50,7 @@ pipeline {
5050
agent { dockerfile { reuseNode true } }
5151
steps {
5252
script {
53-
sh("cargo clippy")
53+
sh("cargo clippy --all-targets --all-features")
5454
}
5555
}
5656
}

src/ephemeris.rs

Lines changed: 132 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -377,7 +377,7 @@ impl Ephemeris {
377377
Ok(doppler)
378378
}
379379

380-
pub fn get_sid(&self) -> std::result::Result<GnssSignal, InvalidGnssSignal> {
380+
pub fn get_sid(&self) -> Result<GnssSignal, InvalidGnssSignal> {
381381
GnssSignal::from_gnss_signal_t(self.0.sid)
382382
}
383383

@@ -405,6 +405,137 @@ impl Ephemeris {
405405
}
406406
}
407407

408+
#[cfg(feature = "sbp-conversions")]
409+
mod sbp_error {
410+
use crate::{signal::InvalidGnssSignal, time::InvalidGpsTime};
411+
use std::error::Error;
412+
use std::fmt;
413+
414+
#[derive(Debug, Copy, Clone, PartialOrd, PartialEq)]
415+
pub enum EphemerisDecodeError {
416+
InvalidTime(InvalidGpsTime),
417+
InvalidSignal(InvalidGnssSignal),
418+
}
419+
420+
impl fmt::Display for EphemerisDecodeError {
421+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
422+
match self {
423+
EphemerisDecodeError::InvalidTime(time_err) => time_err.fmt(f),
424+
EphemerisDecodeError::InvalidSignal(sig_err) => sig_err.fmt(f),
425+
}
426+
}
427+
}
428+
429+
impl Error for EphemerisDecodeError {}
430+
431+
impl From<InvalidGpsTime> for EphemerisDecodeError {
432+
fn from(other: InvalidGpsTime) -> EphemerisDecodeError {
433+
EphemerisDecodeError::InvalidTime(other)
434+
}
435+
}
436+
437+
impl From<InvalidGnssSignal> for EphemerisDecodeError {
438+
fn from(other: InvalidGnssSignal) -> EphemerisDecodeError {
439+
EphemerisDecodeError::InvalidSignal(other)
440+
}
441+
}
442+
}
443+
444+
#[cfg(feature = "sbp-conversions")]
445+
pub use sbp_error::EphemerisDecodeError;
446+
447+
#[cfg(feature = "sbp-conversions")]
448+
impl std::convert::TryFrom<sbp::messages::observation::MsgEphemerisGPS> for Ephemeris {
449+
type Error = EphemerisDecodeError;
450+
451+
fn try_from(
452+
eph: sbp::messages::observation::MsgEphemerisGPS,
453+
) -> Result<Ephemeris, EphemerisDecodeError> {
454+
use std::convert::TryInto;
455+
456+
Ok(Ephemeris::new(
457+
eph.common.sid.try_into()?,
458+
eph.common.toe.try_into()?,
459+
eph.common.ura,
460+
eph.common.fit_interval,
461+
eph.common.valid,
462+
eph.common.health_bits,
463+
0,
464+
EphemerisTerms::new_kepler(
465+
Constellation::Gps,
466+
[eph.tgd, 0.],
467+
eph.c_rc as f64,
468+
eph.c_rs as f64,
469+
eph.c_uc as f64,
470+
eph.c_us as f64,
471+
eph.c_ic as f64,
472+
eph.c_is as f64,
473+
eph.dn,
474+
eph.m0,
475+
eph.ecc,
476+
eph.sqrta,
477+
eph.omega0,
478+
eph.omegadot,
479+
eph.w,
480+
eph.inc,
481+
eph.inc_dot,
482+
eph.af0 as f64,
483+
eph.af1 as f64,
484+
eph.af2 as f64,
485+
eph.toc.try_into()?,
486+
eph.iodc,
487+
eph.iode as u16,
488+
),
489+
))
490+
}
491+
}
492+
493+
#[cfg(feature = "sbp-conversions")]
494+
impl std::convert::TryFrom<sbp::messages::observation::MsgEphemerisGal> for Ephemeris {
495+
type Error = EphemerisDecodeError;
496+
497+
fn try_from(
498+
eph: sbp::messages::observation::MsgEphemerisGal,
499+
) -> Result<Ephemeris, EphemerisDecodeError> {
500+
use std::convert::TryInto;
501+
502+
Ok(Ephemeris::new(
503+
eph.common.sid.try_into()?,
504+
eph.common.toe.try_into()?,
505+
eph.common.ura,
506+
eph.common.fit_interval,
507+
eph.common.valid,
508+
eph.common.health_bits,
509+
eph.source,
510+
EphemerisTerms::new_kepler(
511+
Constellation::Gal,
512+
[eph.bgd_e1e5a, eph.bgd_e1e5b],
513+
eph.c_rc as f64,
514+
eph.c_rs as f64,
515+
eph.c_uc as f64,
516+
eph.c_us as f64,
517+
eph.c_ic as f64,
518+
eph.c_is as f64,
519+
eph.dn,
520+
eph.m0,
521+
eph.ecc,
522+
eph.sqrta,
523+
eph.omega0,
524+
eph.omegadot,
525+
eph.w,
526+
eph.inc,
527+
eph.inc_dot,
528+
eph.af0 as f64,
529+
eph.af1 as f64,
530+
eph.af2 as f64,
531+
eph.toc.try_into()?,
532+
eph.iodc,
533+
eph.iode as u16,
534+
),
535+
))
536+
}
537+
}
538+
408539
impl PartialEq for Ephemeris {
409540
fn eq(&self, other: &Self) -> bool {
410541
unsafe { c_bindings::ephemeris_equal(&self.0, &other.0) }

src/navmeas.rs

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ use std::time::Duration;
1515
const NAV_MEAS_FLAG_CODE_VALID: u16 = 1 << 0;
1616
const NAV_MEAS_FLAG_MEAS_DOPPLER_VALID: u16 = 1 << 2;
1717
const NAV_MEAS_FLAG_CN0_VALID: u16 = 1 << 5;
18+
#[allow(dead_code)]
19+
const NAV_MEAS_FLAG_RAIM_EXCLUSION: u16 = 1 << 6;
1820

1921
/// Represents a single raw GNSS measurement
2022
#[derive(Debug, Clone, PartialOrd, PartialEq)]
@@ -141,6 +143,38 @@ impl Default for NavigationMeasurement {
141143
}
142144
}
143145

146+
#[cfg(feature = "sbp-conversions")]
147+
impl std::convert::TryFrom<sbp::messages::observation::PackedObsContent> for NavigationMeasurement {
148+
type Error = crate::signal::InvalidGnssSignal;
149+
150+
fn try_from(
151+
observation: sbp::messages::observation::PackedObsContent,
152+
) -> Result<NavigationMeasurement, crate::signal::InvalidGnssSignal> {
153+
use std::convert::TryInto;
154+
155+
let mut measurement = NavigationMeasurement::new();
156+
157+
measurement.set_lock_time(decode_lock_time(observation.lock));
158+
measurement.set_sid(observation.sid.try_into()?);
159+
// A CN0 of 0 is considered invalid
160+
if observation.cn0 != 0 {
161+
measurement.set_cn0(observation.cn0 as f64 / 4.);
162+
}
163+
if observation.flags & 0x01 != 0 {
164+
measurement.set_pseudorange(observation.P as f64 / 5e1);
165+
}
166+
if observation.flags & 0x08 != 0 {
167+
measurement
168+
.set_measured_doppler(observation.D.i as f64 + (observation.D.f as f64) / 256.);
169+
}
170+
if observation.flags & 0x80 != 0 {
171+
measurement.0.flags |= NAV_MEAS_FLAG_RAIM_EXCLUSION;
172+
}
173+
174+
Ok(measurement)
175+
}
176+
}
177+
144178
/// Encodes a [`Duration`] as an SBP lock time
145179
///
146180
/// Note: It is encoded according to DF402 from the RTCM 10403.2 Amendment 2

src/signal.rs

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ pub enum Constellation {
2929

3030
/// Invalid constellation integer value
3131
#[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash)]
32-
struct InvalidConstellation(c_bindings::constellation_t);
32+
pub struct InvalidConstellation(c_bindings::constellation_t);
3333

3434
impl fmt::Display for InvalidConstellation {
3535
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
@@ -82,6 +82,13 @@ impl Constellation {
8282
}
8383
}
8484

85+
impl std::convert::TryFrom<u8> for Constellation {
86+
type Error = InvalidConstellation;
87+
fn try_from(value: u8) -> Result<Constellation, InvalidConstellation> {
88+
Self::from_constellation_t(value as c_bindings::constellation_t)
89+
}
90+
}
91+
8592
/// Code identifiers
8693
#[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash)]
8794
pub enum Code {
@@ -395,6 +402,13 @@ impl Code {
395402
}
396403
}
397404

405+
impl std::convert::TryFrom<u8> for Code {
406+
type Error = InvalidCode;
407+
fn try_from(value: u8) -> Result<Code, InvalidCode> {
408+
Self::from_code_t(value as c_bindings::code_t)
409+
}
410+
}
411+
398412
/// GNSS Signal identifier
399413
#[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash)]
400414
pub struct GnssSignal(c_bindings::gnss_signal_t);
@@ -469,6 +483,17 @@ impl GnssSignal {
469483
}
470484
}
471485

486+
#[cfg(feature = "sbp-conversions")]
487+
impl std::convert::TryFrom<sbp::messages::gnss::GnssSignal> for GnssSignal {
488+
type Error = InvalidGnssSignal;
489+
490+
fn try_from(value: sbp::messages::gnss::GnssSignal) -> Result<GnssSignal, InvalidGnssSignal> {
491+
use std::convert::TryInto;
492+
493+
GnssSignal::new(value.sat as u16, value.code.try_into()?)
494+
}
495+
}
496+
472497
#[cfg(test)]
473498
mod tests {
474499
use super::*;

src/time.rs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,25 @@ impl SubAssign<Duration> for GpsTime {
175175
}
176176
}
177177

178+
#[cfg(feature = "sbp-conversions")]
179+
impl std::convert::TryFrom<sbp::messages::gnss::GPSTime> for GpsTime {
180+
type Error = InvalidGpsTime;
181+
182+
fn try_from(msg: sbp::messages::gnss::GPSTime) -> Result<GpsTime, InvalidGpsTime> {
183+
let tow = (msg.tow as f64) * 1e-3 + (msg.ns_residual as f64) * 1e-9;
184+
GpsTime::new(msg.wn as i16, tow)
185+
}
186+
}
187+
188+
#[cfg(feature = "sbp-conversions")]
189+
impl std::convert::TryFrom<sbp::messages::gnss::GPSTimeSec> for GpsTime {
190+
type Error = InvalidGpsTime;
191+
192+
fn try_from(msg: sbp::messages::gnss::GPSTimeSec) -> Result<GpsTime, InvalidGpsTime> {
193+
GpsTime::new(msg.wn as i16, msg.tow as f64)
194+
}
195+
}
196+
178197
#[cfg(test)]
179198
mod tests {
180199
use super::*;

0 commit comments

Comments
 (0)