mod antenna;
pub(crate) mod bits;
pub(crate) mod crc;
mod ephemeris;
mod framing;
mod lli;
mod msm;
mod ssr;
mod station;
#[cfg(test)]
mod tests;
use crate::error::Result;
use bits::BitReader;
pub use antenna::AntennaDescriptor;
pub use ephemeris::{GlonassEphemeris, GpsEphemeris};
pub use framing::{
decode_frame, encode_frame, DecodedFrame, FrameScanner, FRAME_OVERHEAD, MAX_BODY_LEN, PREAMBLE,
};
pub use lli::{
derive_lli, minimum_lock_time_ms, msm_epoch_dt_ms, msm_signal_rinex_code, CellLli,
LockTimeTracker, PreviousLock, LLI_HALF_CYCLE, LLI_LOSS_OF_LOCK,
};
pub use msm::{MsmHeader, MsmKind, MsmMessage, MsmSatellite, MsmSignal};
pub use ssr::{
SsrClockRecord, SsrCodeBiasRecord, SsrHeader, SsrKind, SsrMessage, SsrOrbitRecord,
SsrPhaseBiasRecord, SsrPhaseBiasSignal,
};
pub use station::StationCoordinates;
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct UnsupportedMessage {
pub message_number: u16,
pub body: Vec<u8>,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct RtcmStream {
pub messages: Vec<Message>,
pub diagnostics: StreamDiagnostics,
}
#[derive(Clone, Debug, Default, PartialEq, Eq)]
pub struct StreamDiagnostics {
pub resync_bytes: usize,
pub skipped_frames: Vec<FrameSkip>,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct FrameSkip {
pub offset: usize,
pub message_number: Option<u16>,
pub reason: FrameSkipReason,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum FrameSkipReason {
Truncated,
Malformed(String),
}
pub(crate) type DecodeResult<T> = std::result::Result<T, DecodeError>;
#[derive(Debug)]
pub(crate) enum DecodeError {
OutOfInput(bits::OutOfInput),
Error(crate::error::Error),
}
impl From<bits::OutOfInput> for DecodeError {
fn from(error: bits::OutOfInput) -> Self {
Self::OutOfInput(error)
}
}
impl From<crate::error::Error> for DecodeError {
fn from(error: crate::error::Error) -> Self {
Self::Error(error)
}
}
impl From<DecodeError> for crate::error::Error {
fn from(error: DecodeError) -> Self {
match error {
DecodeError::OutOfInput(error) => error.into(),
DecodeError::Error(error) => error,
}
}
}
#[derive(Debug)]
struct DecodeFailure {
kind: FrameSkipReason,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum Message {
Msm(MsmMessage),
StationCoordinates(StationCoordinates),
AntennaDescriptor(AntennaDescriptor),
GpsEphemeris(GpsEphemeris),
GlonassEphemeris(GlonassEphemeris),
Ssr(SsrMessage),
Unsupported(UnsupportedMessage),
}
pub fn message_number(body: &[u8]) -> Result<u16> {
message_number_classified(body).map_err(Into::into)
}
fn message_number_classified(body: &[u8]) -> DecodeResult<u16> {
let mut r = BitReader::new(body);
Ok(r.u(12)? as u16)
}
impl Message {
pub fn decode(body: &[u8]) -> Result<Self> {
Self::decode_inner(body).map_err(Into::into)
}
fn decode_inner(body: &[u8]) -> DecodeResult<Self> {
let number = message_number_classified(body)?;
let message = match number {
1005 | 1006 => Message::StationCoordinates(StationCoordinates::decode_inner(body)?),
1007 | 1008 | 1033 => {
Message::AntennaDescriptor(AntennaDescriptor::decode_inner(body)?)
}
1019 => Message::GpsEphemeris(GpsEphemeris::decode_inner(body)?),
1020 => Message::GlonassEphemeris(GlonassEphemeris::decode_inner(body)?),
n if msm::is_supported_msm(n) => Message::Msm(MsmMessage::decode_inner(body)?),
n if ssr::is_supported_ssr(n) => Message::Ssr(SsrMessage::decode_inner(body)?),
_ => Message::Unsupported(UnsupportedMessage {
message_number: number,
body: body.to_vec(),
}),
};
Ok(message)
}
fn decode_classified(body: &[u8]) -> std::result::Result<Self, DecodeFailure> {
Self::decode_inner(body).map_err(|error| DecodeFailure {
kind: match error {
DecodeError::OutOfInput(_) => FrameSkipReason::Truncated,
DecodeError::Error(crate::error::Error::Parse(message)) => {
FrameSkipReason::Malformed(message)
}
DecodeError::Error(other) => FrameSkipReason::Malformed(other.to_string()),
},
})
}
pub fn encode(&self) -> Vec<u8> {
match self {
Message::Msm(m) => m.encode(),
Message::StationCoordinates(s) => s.encode(),
Message::AntennaDescriptor(a) => a.encode(),
Message::GpsEphemeris(e) => e.encode(),
Message::GlonassEphemeris(e) => e.encode(),
Message::Ssr(s) => s.encode(),
Message::Unsupported(u) => u.body.clone(),
}
}
pub fn message_number(&self) -> u16 {
match self {
Message::Msm(m) => m.message_number,
Message::StationCoordinates(s) => s.message_number,
Message::AntennaDescriptor(a) => a.message_number,
Message::GpsEphemeris(_) => 1019,
Message::GlonassEphemeris(_) => 1020,
Message::Ssr(s) => s.message_number,
Message::Unsupported(u) => u.message_number,
}
}
pub fn to_frame(&self) -> Result<Vec<u8>> {
encode_frame(&self.encode())
}
}
pub fn decode_messages(bytes: &[u8]) -> Vec<Message> {
decode_stream(bytes).messages
}
pub fn decode_stream(bytes: &[u8]) -> RtcmStream {
let mut stream = RtcmStream {
messages: Vec::new(),
diagnostics: StreamDiagnostics::default(),
};
let mut pos = 0usize;
while pos < bytes.len() {
let Some(rel) = bytes[pos..].iter().position(|&b| b == PREAMBLE) else {
stream.diagnostics.resync_bytes += bytes.len() - pos;
break;
};
stream.diagnostics.resync_bytes += rel;
pos += rel;
if bytes.len() - pos < FRAME_OVERHEAD {
stream.diagnostics.resync_bytes += 1;
pos += 1;
continue;
}
let body_len = ((usize::from(bytes[pos + 1] & 0x03)) << 8) | usize::from(bytes[pos + 2]);
let frame_len = 3 + body_len + 3;
if bytes.len() - pos < frame_len {
stream.diagnostics.resync_bytes += 1;
pos += 1;
continue;
}
match decode_frame(&bytes[pos..pos + frame_len]) {
Ok(frame) => {
match Message::decode_classified(frame.body) {
Ok(message) => stream.messages.push(message),
Err(failure) => stream.diagnostics.skipped_frames.push(FrameSkip {
offset: pos,
message_number: message_number(frame.body).ok(),
reason: failure.kind,
}),
}
pos += frame.frame_len;
}
Err(_) => {
stream.diagnostics.resync_bytes += 1;
pos += 1;
}
}
}
stream
}
#[derive(Clone, Debug, Default, PartialEq, Eq)]
pub struct SsrStreamAssembler {
buf: Vec<u8>,
}
impl SsrStreamAssembler {
pub fn new() -> Self {
Self { buf: Vec::new() }
}
pub fn push(&mut self, chunk: &[u8]) -> Vec<Result<Message>> {
self.buf.extend_from_slice(chunk);
let mut out = Vec::new();
let mut pos = 0usize;
while pos < self.buf.len() {
let Some(rel) = self.buf[pos..].iter().position(|&b| b == PREAMBLE) else {
pos = self.buf.len();
break;
};
pos += rel;
if self.buf.len() - pos < FRAME_OVERHEAD {
break;
}
let body_len =
((usize::from(self.buf[pos + 1] & 0x03)) << 8) | usize::from(self.buf[pos + 2]);
let frame_len = 3 + body_len + 3;
if self.buf.len() - pos < frame_len {
break;
}
match decode_frame(&self.buf[pos..pos + frame_len]) {
Ok(frame) => {
out.push(Message::decode(frame.body));
pos += frame.frame_len;
}
Err(_) => {
pos += 1;
}
}
}
if pos > 0 {
self.buf.drain(..pos);
}
out
}
pub fn retained_len(&self) -> usize {
self.buf.len()
}
}