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 parser;
16pub mod messages;
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_I2: i16 = -32768;
27const DO_NOT_USE_U1: u8  = 255;
28const DO_NOT_USE_U2: u16 = 65535;
29const DO_NOT_USE_U4: u32 = 4294967295;
30const DO_NOT_USE_F4: f32 = -2e10;
31const DO_NOT_USE_F8: f64 = -2e10;
32
33// Re-export all message types at crate level
34pub use messages::{
35    MeasEpoch, MeasEpochChannelType1, MeasEpochChannelType2,
36    MeasExtra, MeasExtraChannelSub,
37    Meas3Ranges, Meas3Doppler,
38    DiffCorrIn,
39    INSSupport,
40    INSNavGeod, INSNavGeodPosStdDev, INSNavGeodAtt, INSNavGeodAttStdDev,
41    INSNavGeodVel, INSNavGeodVelStdDev, INSNavGeodPosCov, INSNavGeodVelCov,
42    INSNavGeodAttCov,
43    AttEuler, AttCovEuler,
44    ExtSensorMeas, ExtSensorMeasSet, ExtSensorMeasAcceleration,
45    ExtSensorMeasAngularRate, ExtSensorMeasVelocity, ExtSensorMeasInfo,
46    ExtSensorMeasZeroVelocityFlag, ExtSensorMeasSetType,
47    QualityInd,
48    ImuSetup,
49    ReceiverSetup,
50    GEORawL1, GEONav,
51    PosCovGeodetic,
52    PVTGeodetic,
53    ReceiverStatus, AGCState,
54    ExtSensorStatus,
55    GALIon,
56    GALUtc,
57    GPSIon,
58    GPSUtc,
59    VelSensorSetup,
60    ExtSensorInfo,
61    GALNav,
62    GALGstGps,
63    GPSNav,
64    Commands,
65    BDSIon,
66    GPSCNav,
67};
68
69#[binrw]
70#[derive(Debug)]
71struct Id {
72    pub bytes: u16,
73}
74
75impl Id {
76    fn message_type(&self) -> MessageKind {
77        MessageKind::from(self.block_number())
78    }
79
80    fn block_number(&self) -> u16 {
81        // NOTE: Bits 0-12 are the actual Block Number
82        self.bytes & 0x1FFF
83    }
84
85    fn _block_rev_number(&self) -> u16 {
86        // NOTE: Bits 13-15 are the Block Revision Number
87        self.bytes & 0xE000
88    }
89}
90
91#[binrw]
92#[derive(Debug)]
93struct Header {
94    pub crc: u16,
95    pub block_id: Id,
96    // NOTE: By definition the length includes the sync, crc, and id fields and the
97    // actual lenth of a block is `length - 8`.
98    pub length: u16,
99}
100
101macro_rules! define_messages {
102    ($($variant:ident => $code:literal,)+) => {
103        /// Typed enum that can be used to determine the type of message
104        /// received.
105        #[derive(Debug)]
106        enum MessageKind {
107            $( $variant, )+
108            Unsupported,
109        }
110
111        impl From<u16> for MessageKind {
112            fn from(block_number: u16) -> Self {
113                match block_number {
114                    $( $code => MessageKind::$variant, )+
115                    _ => MessageKind::Unsupported,
116                }
117            }
118        }
119
120        /// Detailed enum that holds the associated payload.
121        #[derive(Debug)]
122        pub enum Messages {
123            $( $variant($variant), )+
124            Unsupported(u16),
125        }
126    };
127}
128
129define_messages!(
130    MeasExtra => 4000,
131    GALNav => 4002,
132    PVTGeodetic => 4007,
133    ReceiverStatus => 4014,
134    Commands => 4015,
135    GEORawL1 => 4020,
136    MeasEpoch => 4027,
137    GALIon => 4030,
138    GALUtc => 4031,
139    GALGstGps => 4032,
140    GPSCNav => 4042,
141    INSSupport => 4077,
142    Meas3Ranges => 4109,
143    Meas3Doppler => 4111,
144    BDSIon => 4120,
145    ExtSensorStatus => 4223,
146    INSNavGeod => 4226,
147    VelSensorSetup => 4244,
148    AttEuler => 5938,
149    AttCovEuler => 5939,
150    DiffCorrIn => 5919,
151    ExtSensorMeas => 4050,
152    QualityInd => 4082,
153    ExtSensorInfo => 4222,
154    ImuSetup => 4224,
155    ReceiverSetup => 5902,
156    GEONav => 5896,
157    GPSIon => 5893,
158    GPSNav => 5891,
159    GPSUtc => 5894,
160    PosCovGeodetic => 5906,
161);
162
163pub fn is_sync(bytes: &[u8; 2]) -> bool {
164    bytes == b"$@"
165}