Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

BINEX #274

Merged
merged 48 commits into from
Oct 13, 2024
Merged

BINEX #274

Show file tree
Hide file tree
Changes from 13 commits
Commits
Show all changes
48 commits
Select commit Hold shift + click to select a range
1ddf49a
BINEX
gwbres Oct 10, 2024
df92c33
update
gwbres Oct 10, 2024
bc7d351
decode_bnxi
gwbres Oct 10, 2024
bd0f600
Update
gwbres Oct 11, 2024
8f92e9a
Update
gwbres Oct 11, 2024
d7b0b7c
add time decoding test
gwbres Oct 11, 2024
207a9c0
working on bnxi decoding
gwbres Oct 11, 2024
889d615
working on bnxi decoding
gwbres Oct 11, 2024
1ab0202
Epoch Decoding, Encoding
gwbres Oct 11, 2024
632596c
Validate epoch_encoding
gwbres Oct 12, 2024
081846c
decode_bnxi validated
gwbres Oct 12, 2024
0c29518
Monugment geo decoding
gwbres Oct 12, 2024
b752eaf
update
gwbres Oct 12, 2024
c172beb
basis
gwbres Oct 12, 2024
e296d58
progress towards geo support
gwbres Oct 12, 2024
14eb994
add new test resource
gwbres Oct 12, 2024
43c8d34
Introduce readme
gwbres Oct 12, 2024
26ab989
working on decoder
gwbres Oct 12, 2024
793e62a
ignore this test for the moment
gwbres Oct 12, 2024
b04e32b
add new lib
gwbres Oct 12, 2024
bd13235
update readme
gwbres Oct 12, 2024
7e1e167
add test data
gwbres Oct 12, 2024
e213e3d
message decoding
gwbres Oct 12, 2024
1306409
Fix encoding size (crc still not treated)
gwbres Oct 12, 2024
198e890
implement more msg
gwbres Oct 12, 2024
4c6126a
implement more msg
gwbres Oct 12, 2024
2205f80
fix one byte offset
gwbres Oct 12, 2024
a614de0
Towards GPS Ephemeris support
gwbres Oct 12, 2024
63c3669
towards gps ephemeris
gwbres Oct 12, 2024
9b8c052
add bnx00 benchmark
gwbres Oct 12, 2024
3fe2078
add bnx00 benchmark
gwbres Oct 12, 2024
901299f
add bnx00 benchmark
gwbres Oct 12, 2024
b48cae6
run linter
gwbres Oct 13, 2024
3e0278c
Introducing Benchmarking
gwbres Oct 13, 2024
c0dd514
Fixed several issues
gwbres Oct 13, 2024
aaf7a80
Fixed several issues
gwbres Oct 13, 2024
9bf69fb
Fixed several issues
gwbres Oct 13, 2024
79a426e
need to update benchmarks
gwbres Oct 13, 2024
4d34bb0
Introducing flate2 feature
gwbres Oct 13, 2024
e9c67cf
large message cases
gwbres Oct 13, 2024
515eb80
problem in benchmarking functions
gwbres Oct 13, 2024
9b1ca46
Add glonass ephemeris
gwbres Oct 13, 2024
3138b40
Add glonass ephemeris
gwbres Oct 13, 2024
8b20485
SBAS ephemeris
gwbres Oct 13, 2024
156d8e2
Fix benchmarking
gwbres Oct 13, 2024
556c50b
Introducing encoder
gwbres Oct 13, 2024
5d5158c
Merge branch 'main' into binex
gwbres Oct 13, 2024
f037041
Unlock new frame type
gwbres Oct 13, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
resolver = "2"

members = [
"binex",
"crx2rnx",
"qc-traits",
"rinex",
Expand Down
23 changes: 10 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,10 @@ You can also open a [Discussion](https://github.com/georust/rinex/discussions) o
## Advantages :rocket:

- Fast
- Parse and render reports in a few seconds
- Perform precise Geodetic surveys in a few seconds
- Open sources
- Read and access all the code
- All examples based on Open data
- Render High level Geodetic survey reports
- Resolve PPP solutions in a few seconds
- Open sources: read and access all the code!
- Self sustained examples and tutorials: data hosted within this repo
- All modern GNSS constellations, codes and signals
- Surveying with GPS, Galileo, BeiDou and QZSS
- Time scales: GPST, QZSST, BDT, GST, UTC, TAI
Expand All @@ -34,21 +33,18 @@ You can also open a [Discussion](https://github.com/georust/rinex/discussions) o
- High Precision Clock RINEX products (for PPP)
- High Precision Orbital [SP3 for PPP](https://docs.rs/sp3/1.0.7/sp3/)
- DORIS (special RINEX)
- Several pre-processing algorithms:
- [File merging](https://github.com/georust/rinex/wiki/file-merging)
- [Time binning](https://github.com/georust/rinex/wiki/time-binning)
- [Filtering](https://github.com/georust/rinex/wiki/Preprocessing)
- Several post-processing operations
- [File Operations](https://github.com/georust/rinex/wiki/fops)
- Many pre-processing algorithms including Filter Designer
- Several file operations: merging, splitting, time binning (batch)
- Post processing:
- [Position solver](https://github.com/georust/rinex/wiki/Positioning)
- [CGGTTS solver](https://github.com/georust/rinex/wiki/CGGTTS)
- [Graphical QC](https://github.com/georust/rinex/wiki/Graph-Mode)

## Disadvantages :warning:

- BINEX support is currently work in progress
- Navigation is currently not feasible with Glonass and IRNSS
- Differential navigation (SBAS, DGNSS or RTK) is not support yet
- Our applications do not accept BINEX or other proprietary formats
- Our applications do not accept proprietary formats like Septentrio for example
- File production might lack some features, mostly because we're currently focused on data processing

## Repository
Expand All @@ -62,6 +58,7 @@ The application is auto-generated for a few architectures, you can directly
* [`tutorials`](tutorials/) is a superset of scripts (Linux/MacOS compatible)
to get started quickly. The examples span pretty much everything our applications allow.
* [`sp3`](sp3/) High Precision Orbits (by IGS)
* [`binex`](binex/) BINEX Encoding and Decoding library
* [`rnx2crx`](rnx2crx/) is a RINEX compressor (RINEX to Compact RINEX)
* [`crx2rnx`](crx2rnx/) is a CRINEX decompresor (Compact RINEX to RINEX)
* [`rinex-qc`](rinex-qc/) is a library dedicated to RINEX files analysis
Expand Down
24 changes: 24 additions & 0 deletions binex/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
[package]
name = "binex"
version = "0.0.1"
license = "MIT OR Apache-2.0"
authors = ["Guillaume W. Bres <[email protected]>"]
description = "BINEX Binary RINEX encoder and decoder"
homepage = "https://github.com/georust/rinex"
repository = "https://github.com/georust/rinex"
keywords = ["rinex", "timing", "gps", "glonass", "galileo"]
categories = ["science", "science::geo", "parsing"]
edition = "2021"
rust-version = "1.64"

[features]
default = []

[package.metadata.docs.rs]
all-features = true
rustdoc-args = ["--cfg", "docrs", "--generate-link-to-definition"]

[dependencies]
log = "0.4"
thiserror = "1"
hifitime = { version = "4.0.0-alpha", features = ["serde", "std"] }
35 changes: 35 additions & 0 deletions binex/src/constants.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
pub struct Constants {}

impl Constants {
/// Forward Little Endian stream with standard CRC
pub const FWDSYNC_LE_STANDARD_CRC: u8 = 0xC2;

/// Forward Big Endian stream with standard CRC
pub const FWDSYNC_BE_STANDARD_CRC: u8 = 0xE2;

/// Forward Little Endian stream with enhanced CRC
pub const FWDSYNC_LE_ENHANCED_CRC: u8 = 0xC8;

/// Forward Big Endian stream with enhanced CRC
pub const FWDSYNC_BE_ENHANCED_CRC: u8 = 0xE8;

/// Rerversed Little Endian stream with standard CRC
pub const REVSYNC_LE_STANDARD_CRC: u8 = 0xD2;

/// Rerversed Big Endian stream with standard CRC
pub const REVSYNC_BE_STANDARD_CRC: u8 = 0xF2;

/// Rerversed Little Endian stream with enhanced CRC
pub const REVSYNC_LE_ENHANCED_CRC: u8 = 0xD8;

/// Rerversed Big Endian stream with enhanced CRC
pub const REVSYNC_BE_ENHANCED_CRC: u8 = 0xF8;

/// Keep going byte mask in the BNXI algorithm,
/// as per [https://www.unavco.org/data/gps-gnss/data-formats/binex/conventions.html/#ubnxi_details]
pub const BNXI_KEEP_GOING_MASK: u8 = 0x80;

/// Data byte mask in the BNXI algorithm,
/// as per [https://www.unavco.org/data/gps-gnss/data-formats/binex/conventions.html/#ubnxi_details]
pub const BNXI_BYTE_MASK: u8 = 0x7f;
}
64 changes: 64 additions & 0 deletions binex/src/decoder.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
use std::io::Read;

use log::{debug, error};

use crate::{constants::Constants, message::Message, utils::Utils, Error};

#[derive(Debug, Copy, Clone, PartialEq, Default)]
pub enum State {
/// Searching for SYNC byte, defining a start of stream
#[default]
Synchronizing = 0,
/// Message ID byte follows SYNC byte and is BNXI encoded
MID = 1,
/// Message length follows MID bytes and is BNXI encoded
MLength = 2,
/// Message content follows MLength bytes
Message = 3,
}

/// [BINEX] Stream Decoder
pub struct Decoder<R: Read> {
/// [R]
reader: R,
/// Buffer read pointer
ptr: usize,
/// Internal buffer
buffer: Vec<u8>,
/// Current Message being decoded
msg: Message,
/// Internal [State]
state: State,
/// Minimal number of bytes for current [State]
next_read: usize,
}

impl<R: Read> Decoder<R> {
pub fn new(reader: R) -> Self {
Self {
ptr: 0,
reader,
next_read: 128,
state: State::default(),
msg: Default::default(),
buffer: [0; 128].to_vec(),
}
}
}

impl<R: Read> Iterator for Decoder<R> {
type Item = Result<Message, Error>;
/// Parse next message in stream
fn next(&mut self) -> Option<Self::Item> {
match self.reader.read(&mut self.buffer) {
Ok(size) => {},
Err(e) => {
gwbres marked this conversation as resolved.
Show resolved Hide resolved
return None; // EOS
},
}
match Message::decode(&self.buffer) {
Ok(msg) => Some(Ok(msg)),
Err(e) => None,
gwbres marked this conversation as resolved.
Show resolved Hide resolved
}
}
}
44 changes: 44 additions & 0 deletions binex/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
//! BINEX: Binary RINEX encoding and decoding
use thiserror::Error;

mod decoder;
mod message;

pub(crate) mod constants;
pub(crate) mod utils;

pub mod prelude {
pub use crate::decoder::Decoder;
pub use crate::message::Message;
pub use crate::Error;
// re-export
pub use hifitime::Epoch;
}

#[derive(Error, Debug)]
pub enum Error {
#[error("not enough bytes available")]
NotEnoughBytes,
#[error("i/o error")]
IoError(#[from] std::io::Error),
#[error("invalid start of stream")]
InvalidStartofStream,
#[error("no SYNC byte found")]
NoSyncByte,
#[error("reversed streams are not supported yet")]
ReversedStream,
#[error("little endian encoded streams not supported yet")]
LittleEndianStream,
#[error("enhanced crc is not supported yet")]
EnhancedCrc,
#[error("non supported timescale")]
NonSupportedTimescale,
#[error("U32 decoding error")]
U32Decoding,
#[error("unknown message")]
UnknownMessage,
#[error("unknown record field id")]
UnknownRecordFieldId,
#[error("utf8 error")]
Utf8Error,
}
68 changes: 68 additions & 0 deletions binex/src/message/checksum.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
use crate::Message;

/// BINEX Checksum Calculator
pub enum Checksum {
/// For [1 - 2^8-1] message
/// CRC is 1 byte XOR
XOR8,
/// For [2^8, 2^12-1] message
POLY12,
/// For [2^12, 2^20-1] message,
POLY20,
}

impl Checksum {
const fn binary_mask(&self) -> u32 {
match self {
Self::XOR8 => 0xff,
Self::POLY12 => 0x7ff,
Self::POLY20 => 0xfff,
}
}
const fn look_up_table(&self) -> &[u8] {
match self {
Self::XOR8 => &[0, 0, 0, 0],
Self::POLY12 => {
// CRC12 table
// x^16 + x^12 + x^5 +1
&[0, 1, 2, 3]
},
Self::POLY20 => {
// CRC16 table
// x^32 + x^26 + x^23 + x^22 + x^16 + x^12 + x^11 + x^10 + x^8 + x^7 + x^5 + x^4 + x^2 + x^1 +1
&[0, 1, 2, 3]
},
}
}
pub fn new(msg: &Message) -> Self {
if msg.len() < 127 {
Self::XOR8
} else if msg.len() < 4096 {
Self::POLY12
} else {
Self::POLY20
}
}
/// Calculates CRC from [Message]
pub fn calc_from_msg(msg: &Message) -> u32 {
let bytes = msg.to_bytes();
Self::calc_from_bytes(bytes)
}
/// Macro that verifies this [Message] contains correct CRC
pub fn crc_ok(msg: &Message) -> bool {
let crc = msg.crc();
Self::calc_from_msg(msg) == crc
}
/// Calculates CRC from buffer content.
/// Correct content must be correctly extracted beforehand.
pub fn calc_from_bytes(raw: &[u8]) -> u32 {
let size = raw.len();
if size < 128 {
// 0-127 bytes: 1 byte checksum XOR all bytes
} else if size < 4096 {
// 128-4095 x^16 + x^12 + x^5 + x^0 polynomial
//let lut = self.look_up_table();
}
0
}
}
63 changes: 63 additions & 0 deletions binex/src/message/mid.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
//! Message ID from and to binary

/// MessageID stands for Record ID byte
/// and follows the Sync Byte
#[derive(Debug, Copy, Clone, Default, PartialEq)]
pub enum MessageID {
/// Geodetic Marker, Site and Refenrece point info:
/// Geodetic metadata
SiteMonumentMarker = 0,
// /// Decode Ephemeris frame
// Ephemeris = 0x01,
// /// Observation time tag and receiver info
// ObservationTimeTagRxInfo = 0x02,
// /// Local Meteorological and Geophysical information
// Meteo = 0x03,
// /// Receiver info: BINEX specific
// ReceiverInfo = 0x04,
// /// Processed Solutions like PVT
// ProcessedSolutions = 0x05,
// /// Receiver info prototyping: BINEX specific
// ReceiverInfoPrototyping = 0x7d,
// /// Meteo prototyping: BINEX specific
// MeteoPrototyping = 0x7e,
// /// Observation time tag prototyping: BINEX specific
// ObservationTimeTagRxPrototyping = 0x7f,
// /// Unknown is used when building MessageID from buffer content
#[default]
Unknown = 0xffffffff,
}

impl From<u32> for MessageID {
fn from(val: u32) -> Self {
match val {
0 => Self::SiteMonumentMarker,
// 0x01 => Self::Ephemeris,
// 0x02 => Self::ObservationTimeTagRxInfo,
// 0x03 => Self::Meteo,
// 0x04 => Self::ReceiverInfo,
// 0x05 => Self::ProcessedSolutions,
// 0x7d => Self::ReceiverInfoPrototyping,
// 0x7e => Self::MeteoPrototyping,
// 0x7f => Self::ObservationTimeTagRxPrototyping,
_ => Self::Unknown,
}
}
}

impl From<MessageID> for u32 {
fn from(val: MessageID) -> u32 {
match val {
MessageID::SiteMonumentMarker => 0,
// MessageID::Ephemeris => 0x01,
// MessageID::ObservationTimeTagRxInfo => 0x02,
// MessageID::Meteo => 0x03,
// MessageID::ReceiverInfo => 0x04,
// MessageID::ProcessedSolutions => 0x05,
// MessageID::ReceiverInfoPrototyping => 0x7d,
// MessageID::MeteoPrototyping => 0x7e,
// MessageID::ObservationTimeTagRxPrototyping => 0x7f,
_ => 0xffffffff,
}
}
}
Loading
Loading