Skip to content

Commit

Permalink
BNX-05 (#278)
Browse files Browse the repository at this point in the history
* Introducing BNX-05 message
* reduce visilibity:
  - User should only use Message.encode() and .decode(), and operate at this level
* update benchmarks

---------

Signed-off-by: Guillaume W. Bres <[email protected]>
  • Loading branch information
gwbres authored Nov 5, 2024
1 parent 11bbc4f commit 36fbfe7
Show file tree
Hide file tree
Showing 22 changed files with 2,034 additions and 133 deletions.
7 changes: 3 additions & 4 deletions binex/benches/decoding.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
use binex::prelude::{
EphemerisFrame, Epoch, Message, Meta, MonumentGeoMetadata, MonumentGeoRecord, Record,
TimeResolution,
};
use criterion::{black_box, criterion_group, criterion_main, Criterion};

Expand All @@ -22,7 +21,7 @@ pub fn criterion_benchmark(c: &mut Criterion) {
record.meta = geo_meta;

let record = Record::new_monument_geo(record);
let msg = Message::new(meta, TimeResolution::QuarterSecond, record);
let msg = Message::new(meta, record);

let mut buf = [0; 256];
msg.encode(&mut buf, 256).unwrap();
Expand All @@ -34,7 +33,7 @@ pub fn criterion_benchmark(c: &mut Criterion) {
});

let record = Record::new_ephemeris_frame(EphemerisFrame::GPSRaw(Default::default()));
let msg = Message::new(meta, TimeResolution::QuarterSecond, record);
let msg = Message::new(meta, record);

let mut buf = [0; 256];
msg.encode(&mut buf, 256).unwrap();
Expand All @@ -46,7 +45,7 @@ pub fn criterion_benchmark(c: &mut Criterion) {
});

let record = Record::new_ephemeris_frame(EphemerisFrame::GPS(Default::default()));
let msg = Message::new(meta, TimeResolution::QuarterSecond, record);
let msg = Message::new(meta, record);

let mut buf = [0; 256];
msg.encode(&mut buf, 256).unwrap();
Expand Down
7 changes: 3 additions & 4 deletions binex/benches/encoding.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
use binex::prelude::{
EphemerisFrame, Epoch, Message, Meta, MonumentGeoMetadata, MonumentGeoRecord, Record,
TimeResolution,
};
use criterion::{black_box, criterion_group, criterion_main, Criterion};

Expand All @@ -24,7 +23,7 @@ pub fn criterion_benchmark(c: &mut Criterion) {
record.meta = geo_meta;

let record = Record::new_monument_geo(record);
let msg = Message::new(meta, TimeResolution::QuarterSecond, record);
let msg = Message::new(meta, record);

c.bench_function("encoding-00", |b| {
b.iter(|| {
Expand All @@ -33,7 +32,7 @@ pub fn criterion_benchmark(c: &mut Criterion) {
});

let record = Record::new_ephemeris_frame(EphemerisFrame::GPSRaw(Default::default()));
let msg = Message::new(meta, TimeResolution::QuarterSecond, record);
let msg = Message::new(meta, record);

c.bench_function("encoding-01-00", |b| {
b.iter(|| {
Expand All @@ -42,7 +41,7 @@ pub fn criterion_benchmark(c: &mut Criterion) {
});

let record = Record::new_ephemeris_frame(EphemerisFrame::GPS(Default::default()));
let msg = Message::new(meta, TimeResolution::QuarterSecond, record);
let msg = Message::new(meta, record);

c.bench_function("encoding-01-01", |b| {
b.iter(|| {
Expand Down
7 changes: 5 additions & 2 deletions binex/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,14 @@ pub mod prelude {
decoder::Decoder,
message::{
EphemerisFrame, GALEphemeris, GLOEphemeris, GPSEphemeris, GPSRaw, Message, Meta,
MonumentGeoMetadata, MonumentGeoRecord, Record, SBASEphemeris, TimeResolution,
MonumentGeoMetadata, MonumentGeoRecord, PositionEcef3d, PositionGeo3d, Record,
SBASEphemeris, Solutions, TemporalSolution, Velocity3d, VelocityNED3d,
},
stream::{ClosedSourceElement, Provider, StreamElement},
ClosedSourceMeta, Error,
};
// re-export
pub use hifitime::Epoch;
pub use hifitime::{Epoch, TimeScale};
}

use crate::message::Meta;
Expand Down Expand Up @@ -75,6 +76,8 @@ pub enum Error {
IncompleteMessage(usize),
/// Library limitation: not all open source Messages supported yet
NonSupportedMesssage(usize),
/// Library limtation: not all subrecords supported yet
NonSupportedSubRecord,
/// Library limtation: should never happen, because this library
/// will be designed to parse all open source [Message]s.
/// This may happen as either we're still in development (bad internal design)
Expand Down
131 changes: 102 additions & 29 deletions binex/src/message/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,26 +6,24 @@ mod time; // Epoch encoding/decoding // checksum calc.

pub use record::{
EphemerisFrame, GALEphemeris, GLOEphemeris, GPSEphemeris, GPSRaw, MonumentGeoMetadata,
MonumentGeoRecord, Record, SBASEphemeris,
MonumentGeoRecord, PositionEcef3d, PositionGeo3d, Record, SBASEphemeris, Solutions,
SolutionsFrame, TemporalSolution, Velocity3d, VelocityNED3d,
};

pub use meta::Meta;
pub use time::TimeResolution;

pub(crate) use mid::MessageID;

use checksum::Checksum;

use crate::{stream::Provider, ClosedSourceMeta, Error};
use checksum::Checksum;

#[derive(Debug, Clone, PartialEq, Default)]
pub struct Message {
/// [Meta] data
pub meta: Meta,
/// [Record]
pub record: Record,
/// Time Resolution in use
time_res: TimeResolution,
}

impl Message {
Expand All @@ -38,12 +36,8 @@ impl Message {
const BNXI_BYTE_MASK: u8 = 0x7f;

/// Creates a new [Message] ready to be encoded.
pub fn new(meta: Meta, time_res: TimeResolution, record: Record) -> Self {
Self {
meta,
record,
time_res,
}
pub fn new(meta: Meta, record: Record) -> Self {
Self { meta, record }
}

/// Returns total size required to encode this [Message].
Expand Down Expand Up @@ -73,8 +67,6 @@ impl Message {
pub fn decode(buf: &[u8]) -> Result<Self, Error> {
let buf_len = buf.len();

let time_res = TimeResolution::QuarterSecond;

// 1. locate SYNC byte
let meta = Meta::find_and_parse(buf, buf_len);
if meta.is_none() {
Expand Down Expand Up @@ -113,12 +105,11 @@ impl Message {

// 2. parse MID
let (bnxi, mid_1_4) = Self::decode_bnxi(&buf[ptr..], big_endian);

let mid = MessageID::from(bnxi);

if mid == MessageID::Unknown {
return Err(Error::UnknownMessage);
}

ptr += mid_1_4;

// make sure we can parse up to 4 byte MLEN
Expand All @@ -135,20 +126,25 @@ impl Message {
// buffer does not contain complete message!
return Err(Error::IncompleteMessage(mlen));
}

ptr += mlen_1_4;

// 4. parse RECORD
let record = match mid {
MessageID::SiteMonumentMarker => {
let rec =
MonumentGeoRecord::decode(mlen as usize, time_res, big_endian, &buf[ptr..])?;
let rec = MonumentGeoRecord::decode(mlen as usize, big_endian, &buf[ptr..])?;
Record::new_monument_geo(rec)
},
MessageID::Ephemeris => {
let fr = EphemerisFrame::decode(big_endian, &buf[ptr..])?;
Record::new_ephemeris_frame(fr)
},
MessageID::ProcessedSolutions => {
let solutions = Solutions::decode(mlen as usize, big_endian, &buf[ptr..])?;
Record::new_solutions(solutions)
},
MessageID::Unknown => {
return Err(Error::UnknownMessage);
},
_ => {
// check whether this message is undisclosed or not
if let Some(provider) = Provider::match_any(mid.into()) {
Expand Down Expand Up @@ -184,11 +180,7 @@ impl Message {
if expected != ck {
Err(Error::CorrupctBadCRC)
} else {
Ok(Self {
meta,
record,
time_res,
})
Ok(Self { meta, record })
}
}

Expand Down Expand Up @@ -232,6 +224,9 @@ impl Message {
Record::MonumentGeo(geo) => {
ptr += geo.encode(big_endian, &mut buf[ptr..])?;
},
Record::Solutions(fr) => {
ptr += fr.encode(big_endian, &mut buf[ptr..])?;
},
}

// encode CRC
Expand Down Expand Up @@ -432,8 +427,10 @@ impl Message {
#[cfg(test)]
mod test {
use super::Message;
use crate::message::{EphemerisFrame, GPSRaw, MonumentGeoMetadata, MonumentGeoRecord, Record};
use crate::message::{GALEphemeris, GPSEphemeris, Meta, TimeResolution};
use crate::message::{
EphemerisFrame, GALEphemeris, GPSEphemeris, GPSRaw, Meta, MonumentGeoMetadata,
MonumentGeoRecord, PositionEcef3d, Record, Solutions, SolutionsFrame, Velocity3d,
};
use crate::prelude::Epoch;
use crate::Error;

Expand Down Expand Up @@ -597,7 +594,7 @@ mod test {
let geo_len = geo.encoding_size();
let record = Record::new_monument_geo(geo);

let msg = Message::new(meta, TimeResolution::QuarterSecond, record);
let msg = Message::new(meta, record);

// SYNC + MID(1) +FID + MLEN + CRC(8)
assert_eq!(msg.encoding_size(), 1 + 1 + 1 + geo_len + 1);
Expand All @@ -624,7 +621,7 @@ mod test {
let gps_raw_len = gps_raw.encoding_size();
let record = Record::new_ephemeris_frame(gps_raw);

let msg = Message::new(meta, TimeResolution::QuarterSecond, record);
let msg = Message::new(meta, record);

// SYNC + MID(1) + MLEN(1) + RLEN + CRC(1)
assert_eq!(msg.encoding_size(), 1 + 1 + 1 + gps_raw_len + 1);
Expand Down Expand Up @@ -653,7 +650,7 @@ mod test {

assert_eq!(gps_eph_len, 129);

let msg = Message::new(meta, TimeResolution::QuarterSecond, record);
let msg = Message::new(meta, record);

// SYNC + MID(1) + MLEN(2) + RLEN + CRC(2)
assert_eq!(msg.encoding_size(), 1 + 1 + 2 + gps_eph_len + 2);
Expand All @@ -680,7 +677,7 @@ mod test {

assert_eq!(eph_len, 129);

let msg = Message::new(meta, TimeResolution::QuarterSecond, record);
let msg = Message::new(meta, record);

// SYNC + MID(1) + MLEN(2) + RLEN + CRC(2)
assert_eq!(msg.encoding_size(), 1 + 1 + 2 + eph_len + 2);
Expand All @@ -692,4 +689,80 @@ mod test {
let parsed = Message::decode(&encoded).unwrap();
assert_eq!(parsed, msg);
}

#[test]
fn test_pvt_wgs84() {
let mut meta = Meta::default();

meta.reversed = false;
meta.big_endian = true;
meta.enhanced_crc = false;

let mut solutions = Solutions::new(Epoch::from_gpst_seconds(1.100));

solutions.frames.push(SolutionsFrame::AntennaEcefPosition(
PositionEcef3d::new_wgs84(1.0, 2.0, 3.0),
));

let sol_len = solutions.encoding_size();
assert_eq!(sol_len, 6 + 1 + 3 * 8 + 1); // ts | fid | 3*8 | wgs

let mut buf = [0; 32];
let size = solutions.encode(true, &mut buf).unwrap();
assert_eq!(size, 6 + 1 + 3 * 8 + 1);

assert_eq!(
buf,
[
0, 0, 0, 0, 4, 76, 1, 0, 63, 240, 0, 0, 0, 0, 0, 0, 64, 0, 0, 0, 0, 0, 0, 0, 64, 8,
0, 0, 0, 0, 0, 0
]
);

let record = Record::new_solutions(solutions.clone());
let msg = Message::new(meta, record);

// SYNC + MID(1) + MLEN(1) + RLEN + CRC(1)
let mlen = 1 + 1 + 1 + sol_len + 1;
assert_eq!(msg.encoding_size(), mlen);

let mut encoded = [0; 40];
msg.encode(&mut encoded, 40).unwrap();

assert_eq!(
encoded,
[
226, 5, 32, 0, 0, 0, 0, 4, 76, 1, 0, 63, 240, 0, 0, 0, 0, 0, 0, 64, 0, 0, 0, 0, 0,
0, 0, 64, 8, 0, 0, 0, 0, 0, 0, 171, 0, 0, 0, 0
]
);

// parse back
let parsed = Message::decode(&encoded).unwrap();
assert_eq!(parsed, msg);

// add velocity
solutions
.frames
.push(SolutionsFrame::AntennaEcefVelocity(Velocity3d {
x_m_s: 1.0,
y_m_s: 1.0,
z_m_s: 1.0,
}));

let sol_len = solutions.encoding_size();
assert_eq!(sol_len, 6 + 1 + 3 * 8 + 1 + 3 * 8 + 1);

let mut buf = [0; 64];
let size = solutions.encode(true, &mut buf).unwrap();
assert_eq!(size, sol_len);

let record = Record::new_solutions(solutions.clone());
let msg = Message::new(meta, record);

// add temporal
// add system time
// add comment
// add extra
}
}
4 changes: 2 additions & 2 deletions binex/src/message/record/ephemeris/galileo.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ impl GALEphemeris {
pub(crate) const fn encoding_size() -> usize {
128
}
pub fn encode(&self, big_endian: bool, buf: &mut [u8]) -> Result<usize, Error> {
pub(crate) fn encode(&self, big_endian: bool, buf: &mut [u8]) -> Result<usize, Error> {
let size = Self::encoding_size();
if buf.len() < size {
return Err(Error::NotEnoughBytes);
Expand Down Expand Up @@ -264,7 +264,7 @@ impl GALEphemeris {
Ok(Self::encoding_size())
}

pub fn decode(big_endian: bool, buf: &[u8]) -> Result<Self, Error> {
pub(crate) fn decode(big_endian: bool, buf: &[u8]) -> Result<Self, Error> {
if buf.len() < Self::encoding_size() {
return Err(Error::NotEnoughBytes);
}
Expand Down
4 changes: 2 additions & 2 deletions binex/src/message/record/ephemeris/glonass.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ impl GLOEphemeris {
pub(crate) const fn encoding_size() -> usize {
135
}
pub fn encode(&self, big_endian: bool, buf: &mut [u8]) -> Result<usize, Error> {
pub(crate) fn encode(&self, big_endian: bool, buf: &mut [u8]) -> Result<usize, Error> {
let size = Self::encoding_size();
if buf.len() < size {
return Err(Error::NotEnoughBytes);
Expand Down Expand Up @@ -174,7 +174,7 @@ impl GLOEphemeris {
Ok(135)
}

pub fn decode(big_endian: bool, buf: &[u8]) -> Result<Self, Error> {
pub(crate) fn decode(big_endian: bool, buf: &[u8]) -> Result<Self, Error> {
if buf.len() < Self::encoding_size() {
return Err(Error::NotEnoughBytes);
}
Expand Down
4 changes: 2 additions & 2 deletions binex/src/message/record/ephemeris/gps/eph.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ impl GPSEphemeris {
pub(crate) const fn encoding_size() -> usize {
128
}
pub fn encode(&self, big_endian: bool, buf: &mut [u8]) -> Result<usize, Error> {
pub(crate) fn encode(&self, big_endian: bool, buf: &mut [u8]) -> Result<usize, Error> {
let size = Self::encoding_size();
if buf.len() < size {
return Err(Error::NotEnoughBytes);
Expand Down Expand Up @@ -284,7 +284,7 @@ impl GPSEphemeris {
buf[125..127].copy_from_slice(&uint2);
Ok(size)
}
pub fn decode(big_endian: bool, buf: &[u8]) -> Result<Self, Error> {
pub(crate) fn decode(big_endian: bool, buf: &[u8]) -> Result<Self, Error> {
if buf.len() < Self::encoding_size() {
return Err(Error::NotEnoughBytes);
}
Expand Down
Loading

0 comments on commit 36fbfe7

Please sign in to comment.