Skip to main content

libsbf/
lib.rs

1//! A no_std parser for the SBF (Septentrio Binary Format) using the
2//! [sans-io](https://sans-io.readthedocs.io/) philosophy.
3//!
4//! ## `std` BufReader Iterator
5//! There is also a `std` API that exposes an `SbfReader` that uses a
6//! BufReader. The `SbfReader` implements an `Iterator` that will give
7//! you `libsbf::Messages`. To enable this do `cargo add libsbf -F std`
8
9#![cfg_attr(docsrs, feature(doc_cfg))]
10#![cfg_attr(not(feature = "std"), no_std)]
11use binrw::binrw;
12
13extern crate alloc;
14
15pub mod messages;
16pub mod parser;
17
18#[cfg(feature = "std")]
19#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
20pub mod reader;
21
22#[cfg(all(test, feature = "std"))]
23mod mega_test;
24
25// Constants for DO_NOT_USE values
26const DO_NOT_USE_I1: i8 = -128;
27const DO_NOT_USE_I2: i16 = -32768;
28const DO_NOT_USE_U1: u8 = 255;
29const DO_NOT_USE_U2: u16 = 65535;
30const DO_NOT_USE_U4: u32 = 4294967295;
31const DO_NOT_USE_F4: f32 = -2e10;
32const DO_NOT_USE_F8: f64 = -2e10;
33
34// Re-export all message types at crate level
35pub use messages::{
36    AGCState, AttCovEuler, AttEuler, AttitudeMode, AuxAntPositionSub, AuxAntPositions,
37    BaseVectorCart, BaselineError, BDSIon, Commands, DOP, Datum, DiffCorrIn, DiffCorrType, EndOfMeas,
38    EventPolarity, EventSource, ExtError, ExtEvent, ExtEventINSNavCart, ExtEventINSNavCartAtt,
39    ExtEventINSNavCartAttStdDev, ExtEventINSNavCartPosStdDev, ExtEventINSNavCartVel,
40    ExtEventINSNavCartVelStdDev, ExtEventINSNavGeod, ExtEventINSNavGeodAtt,
41    ExtEventINSNavGeodAttStdDev, ExtEventINSNavGeodPosStdDev, ExtEventINSNavGeodVel,
42    ExtEventINSNavGeodVelStdDev, ExtSensorInfo, ExtSensorMeas, ExtSensorMeasAcceleration,
43    ExtSensorMeasAngularRate, ExtSensorMeasInfo, ExtSensorMeasSet, ExtSensorMeasSetType,
44    ExtSensorMeasVelocity, ExtSensorMeasZeroVelocityFlag, ExtSensorStatus, GALGstGps, GALIon,
45    GALNav, GALUtc, GEONav, GEORawL1, GPSCNav, GPSIon, GPSNav, GPSUtc, GnssMode, INSCouplingMode,
46    INSError, INSNavCart, INSNavCartAtt, INSNavCartAttCov, INSNavCartAttStdDev, INSNavCartPosCov,
47    INSNavCartPosStdDev, INSNavCartVel, INSNavCartVelCov, INSNavCartVelStdDev, INSNavGeod,
48    INSNavGeodAtt, INSNavGeodAttCov, INSNavGeodAttStdDev, INSNavGeodPosCov, INSNavGeodPosStdDev,
49    INSNavGeodVel, INSNavGeodVelCov, INSNavGeodVelStdDev, INSSolutionLocation, INSSupport,
50    ImuSetup, Meas3Doppler, Meas3Ranges, MeasEpoch, MeasEpochChannelType1, MeasEpochChannelType2,
51    MeasExtra, MeasExtraChannelSub, NavCart, PVTCartesian, PVTGeodetic, PosCart, PosCovCartesian,
52    PosCovGeodetic, PvtError, PvtMode, PvtModeFlags, QualityInd, QualityIndicator, RFBand,
53    RFStatus, RaimIntegrity, ReceiverSetup, ReceiverStatus, RxError, RxState, VectorInfoCart,
54    VelCovCartesian, VelCovGeodetic, VelSensorSetup, WACorrFlags,
55};
56
57// Re-export datagram parser
58pub use parser::{parse_datagram, DatagramError, MAX_UDP_PAYLOAD};
59
60#[binrw]
61#[derive(Debug)]
62struct Id {
63    pub bytes: u16,
64}
65
66impl Id {
67    fn message_type(&self) -> MessageKind {
68        MessageKind::from(self.block_number())
69    }
70
71    fn block_number(&self) -> u16 {
72        // NOTE: Bits 0-12 are the actual Block Number
73        self.bytes & 0x1FFF
74    }
75
76    fn _block_rev_number(&self) -> u16 {
77        // NOTE: Bits 13-15 are the Block Revision Number
78        self.bytes & 0xE000
79    }
80}
81
82#[binrw]
83#[derive(Debug)]
84struct Header {
85    pub crc: u16,
86    pub block_id: Id,
87    // NOTE: By definition the length includes the sync, crc, and id fields and the
88    // actual lenth of a block is `length - 8`.
89    pub length: u16,
90}
91
92macro_rules! define_messages {
93    ($($variant:ident => $code:literal,)+) => {
94        /// Typed enum that can be used to determine the type of message
95        /// received.
96        #[derive(Debug)]
97        enum MessageKind {
98            $( $variant, )+
99            Unsupported,
100        }
101
102        impl From<u16> for MessageKind {
103            fn from(block_number: u16) -> Self {
104                match block_number {
105                    $( $code => MessageKind::$variant, )+
106                    _ => MessageKind::Unsupported,
107                }
108            }
109        }
110
111        /// Detailed enum that holds the associated payload.
112        #[derive(Debug)]
113        pub enum Messages {
114            $( $variant($variant), )+
115            Unsupported(u16),
116        }
117    };
118}
119
120define_messages!(
121    MeasExtra => 4000,
122    DOP => 4001,
123    GALNav => 4002,
124    PVTCartesian => 4006,
125    PVTGeodetic => 4007,
126    ReceiverStatus => 4014,
127    Commands => 4015,
128    GEORawL1 => 4020,
129    MeasEpoch => 4027,
130    GALIon => 4030,
131    GALUtc => 4031,
132    GALGstGps => 4032,
133    BaseVectorCart => 4043,
134    PosCart => 4044,
135    GPSCNav => 4042,
136    INSSupport => 4077,
137    Meas3Ranges => 4109,
138    Meas3Doppler => 4111,
139    NavCart => 4272,
140    BDSIon => 4120,
141    ExtSensorStatus => 4223,
142    INSNavCart => 4225,
143    INSNavGeod => 4226,
144    ExtEventINSNavCart => 4229,
145    ExtEventINSNavGeod => 4230,
146    VelSensorSetup => 4244,
147    AttEuler => 5938,
148    AttCovEuler => 5939,
149    AuxAntPositions => 5942,
150    DiffCorrIn => 5919,
151    ExtSensorMeas => 4050,
152    RFStatus => 4092,
153    QualityInd => 4082,
154    ExtSensorInfo => 4222,
155    ImuSetup => 4224,
156    ReceiverSetup => 5902,
157    GEONav => 5896,
158    GPSIon => 5893,
159    GPSNav => 5891,
160    GPSUtc => 5894,
161    PosCovCartesian => 5905,
162    PosCovGeodetic => 5906,
163    VelCovCartesian => 5907,
164    VelCovGeodetic => 5908,
165    EndOfMeas => 5922,
166    ExtEvent => 5924,
167);
168
169pub fn is_sync(bytes: &[u8; 2]) -> bool {
170    bytes == b"$@"
171}