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

Use own proc macro to generate code to deal with packets #7

Merged
merged 22 commits into from
Mar 24, 2020
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
483f2d8
Use own proc macro to generate code to deal with packets
Dushistov Mar 9, 2020
681e328
make all names in ubx_packets starts with Ubx for uniformity
Dushistov Mar 13, 2020
0f45945
export packet size as constant
Dushistov Mar 13, 2020
b4ca8cf
feature: make possible to print (+validate) extension field in MonVer
Dushistov Mar 13, 2020
989eee9
feature: new packages: Nav-Dop, Nav-Sol, AckNak
Dushistov Mar 13, 2020
6c5687e
feature: nice method to check if ack for certain message
Dushistov Mar 13, 2020
f2ea490
fix: generted code for handling i8 field in ubx_packet_recv
Dushistov Mar 13, 2020
6238887
cleanups/typo fixes plus formating
Dushistov Mar 16, 2020
e7dbe26
fix several clippy warnings
Dushistov Mar 16, 2020
0ea519c
parser/refactoring: simplify work with &data[pos..]
Dushistov Mar 16, 2020
089de53
parser_tests/refactroing: split big test into small one
Dushistov Mar 16, 2020
3493133
make possible to reuse ublox dump test
Dushistov Mar 19, 2020
d5a0095
feature: automatically calculate max packet size for parser
Dushistov Mar 19, 2020
8938b27
refactoring: rename CfgMsg(3|8) -> CfgMsg(Single|All)Port(s)
Dushistov Mar 19, 2020
4e7518a
feature: Debug implementation for FixStatusInfo
Dushistov Mar 20, 2020
46cc586
ublox_derive/src/input refactoring: use "use syn::Error"
Dushistov Mar 23, 2020
44da3a8
ublox_derive: check that rest_handling not already defined
Dushistov Mar 23, 2020
e9fc996
refactoring: simplify generate_send_code_for_packet
Dushistov Mar 23, 2020
6cb1d84
fix comment grammar
Dushistov Mar 23, 2020
08105f7
ublox_derive/src/input: improve error message
Dushistov Mar 23, 2020
f60f7dc
fix tests
Dushistov Mar 23, 2020
8c53078
refactoring: usage of fold, plus more appropriate names
Dushistov Mar 24, 2020
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
3 changes: 3 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ matrix:
allow_failures:
- rust: nightly
fast_finish: true
before_script:
- rustup component add rustfmt-preview
- which rustfmt
lkolbly marked this conversation as resolved.
Show resolved Hide resolved
script:
- cargo test --verbose --workspace
- cargo test --release --verbose --workspace
Expand Down
12 changes: 6 additions & 6 deletions ublox/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,12 @@ default = []
serial = ["serialport", "crc"]

[dependencies]
serde = "1.0"
serde_derive = "1.0"
bincode = "1.2.1"
chrono = "0.4"
ublox_derive = "0.0.0"
ublox_derive = "0.0.1"
serialport = { version = "3.3.0", optional = true }
crc = { version = "1.8.1", optional = true }
num-derive = "0.3.0"
num-traits = "0.2.11"
bitflags = "1.2.1"

[dev-dependencies]
rand = "0.7.3"
cpu-time = "1.0.0"
29 changes: 14 additions & 15 deletions ublox/examples/serial.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,24 +6,23 @@ mod serial {

pub fn main() {
let mut dev = Device::new("/dev/ttyUSB0").unwrap();

let pos = Position {
lon: -97.5,
lat: 30.2,
alt: 200.0,
};
println!("Setting AID data...");
match dev.load_aid_data(Some(pos), Some(Utc::now())) {
Err(e) => {
println!("Got error setting AID data: {:?}", e);
}
_ => {}
}

/*
let pos = Position {
lon: -97.5,
lat: 30.2,
alt: 200.0,
};
println!("Setting AID data...");
match dev.load_aid_data(Some(pos), Some(Utc::now())) {
Err(e) => {
println!("Got error setting AID data: {:?}", e);
}
_ => {}
}
loop {
dev.poll_for(Duration::from_millis(500)).unwrap();
println!("{:?}", dev.get_solution());
}
} */
}
}

Expand Down
73 changes: 58 additions & 15 deletions ublox/src/error.rs
Original file line number Diff line number Diff line change
@@ -1,25 +1,68 @@
use std::convert;
use std::io;
use std::fmt;

#[derive(Debug)]
pub enum Error {
InvalidChecksum,
UnexpectedPacket,
TimedOutWaitingForAck(u8, u8),
IoError(io::Error),
BincodeError(bincode::Error),
pub enum MemWriterError<E>
where
E: std::error::Error,
{
NotEnoughMem,
Custom(E),
}

impl convert::From<io::Error> for Error {
fn from(error: io::Error) -> Self {
Error::IoError(error)
impl<E> fmt::Display for MemWriterError<E>
where
E: std::error::Error,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
MemWriterError::NotEnoughMem => f.write_str("Not enough memory error"),
MemWriterError::Custom(e) => write!(f, "MemWriterError: {}", e),
}
}
}

impl convert::From<bincode::Error> for Error {
fn from(error: bincode::Error) -> Self {
Error::BincodeError(error)
impl<E> std::error::Error for MemWriterError<E> where E: std::error::Error {}

/// Error that possible during packets parsing
#[derive(Debug, PartialEq)]
pub enum ParserError {
InvalidChecksum {
expect: u16,
got: u16,
},
InvalidField {
packet: &'static str,
field: &'static str,
},
InvalidPacketLen {
packet: &'static str,
expect: usize,
got: usize,
},
}

impl fmt::Display for ParserError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
ParserError::InvalidChecksum { expect, got } => write!(
f,
"Not valid packet's checksum, expect {:x}, got {:x}",
expect, got
),
ParserError::InvalidField { packet, field } => {
write!(f, "Invalid field {} of packet {}", field, packet)
}
ParserError::InvalidPacketLen {
packet,
expect,
got,
} => write!(
f,
"Invalid packet({}) length, expect {}, got {}",
packet, expect, got
),
}
}
}

pub type Result<T> = std::result::Result<T, Error>;
impl std::error::Error for ParserError {}
9 changes: 6 additions & 3 deletions ublox/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,16 @@
//! At time of writing this library is developed for a device which behaves like
//! a NEO-6M device.

pub use crate::segmenter::Segmenter;
#[cfg(feature = "serial")]
pub use crate::serialport::{Device, ResetType};
pub use crate::ubx_packets::*;
pub use crate::{
error::{MemWriterError, ParserError},
parser::{Parser, ParserIter},
ubx_packets::*,
};

mod error;
mod segmenter;
mod parser;
#[cfg(feature = "serial")]
mod serialport;
mod ubx_packets;
121 changes: 121 additions & 0 deletions ublox/src/parser.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
use crate::{
error::ParserError,
ubx_packets::{match_packet, ubx_checksum, PacketRef, SYNC_CHAR_1, SYNC_CHAR_2},
};

/// Some big number, TODO: need validation against all known packets
const MAX_PACK_LEN: usize = 1022;
Dushistov marked this conversation as resolved.
Show resolved Hide resolved

/// Streaming parser for UBX protocol with buffer
#[derive(Default)]
pub struct Parser {
buf: Vec<u8>,
}

impl Parser {
pub fn is_buffer_empty(&self) -> bool {
self.buf.is_empty()
}
pub fn buffer_len(&self) -> usize {
Dushistov marked this conversation as resolved.
Show resolved Hide resolved
self.buf.len()
}
pub fn consume<'a, 'b, 'c>(&'a mut self, new_data: &'b [u8]) -> ParserIter<'c>
Dushistov marked this conversation as resolved.
Show resolved Hide resolved
where
'a: 'c,
Dushistov marked this conversation as resolved.
Show resolved Hide resolved
{
match self
.buf
.iter()
.chain(new_data.iter())
.position(|x| *x == SYNC_CHAR_1)
{
Some(mut off) => {
if off >= self.buf.len() {
off -= self.buf.len();
self.buf.clear();
self.buf.extend_from_slice(&new_data[off..]);
off = 0;
} else {
self.buf.extend_from_slice(new_data);
}
ParserIter {
buf: &mut self.buf,
off,
}
}
None => {
self.buf.clear();
ParserIter {
buf: &mut self.buf,
off: 0,
}
}
}
}
}

/// Iterator over data stored in `Parser` buffer
pub struct ParserIter<'a> {
buf: &'a mut Vec<u8>,
off: usize,
}

impl<'a> Drop for ParserIter<'a> {
fn drop(&mut self) {
if self.off <= self.buf.len() {
self.buf.drain(0..self.off);
}
}
}

impl<'a> ParserIter<'a> {
/// Analog of `core::iter::Iterator::next`, should be switched to
/// trait implmentation after merge of https://github.com/rust-lang/rust/issues/44265
pub fn next(&mut self) -> Option<Result<PacketRef, ParserError>> {
while self.off < self.buf.len() {
let data = &self.buf[self.off..];
let pos = match data.iter().position(|x| *x == SYNC_CHAR_1) {
Dushistov marked this conversation as resolved.
Show resolved Hide resolved
Some(x) => x,
None => return None,
};
Dushistov marked this conversation as resolved.
Show resolved Hide resolved

if (pos + 1) >= data.len() {
return None;
}
if data[pos + 1] != SYNC_CHAR_2 {
self.off += pos + 1;
continue;
}

if (pos + 5) >= data.len() {
return None;
}

let pack_len: usize = u16::from_le_bytes([data[pos + 4], data[pos + 5]]).into();
if pack_len > MAX_PACK_LEN {
self.off += pos + 1;
continue;
}
if (pos + pack_len + 6 + 2 - 1) >= data.len() {
Dushistov marked this conversation as resolved.
Show resolved Hide resolved
return None;
}
let (ck_a, ck_b) = ubx_checksum(&data[(pos + 2)..(pos + pack_len + 4 + 2)]);

let (expect_ck_a, expect_ck_b) =
(data[pos + 6 + pack_len], data[pos + 6 + pack_len + 1]);
if (ck_a, ck_b) != (expect_ck_a, expect_ck_b) {
self.off += pos + 2;
return Some(Err(ParserError::InvalidChecksum {
expect: u16::from_le_bytes([expect_ck_a, expect_ck_b]),
got: u16::from_le_bytes([ck_a, ck_b]),
}));
}
let msg_data = &data[(pos + 6)..(pos + 6 + pack_len)];
let class_id = data[pos + 2];
let msg_id = data[pos + 3];
self.off += pos + 6 + pack_len + 2;
return Some(match_packet(class_id, msg_id, msg_data));
}
None
}
}
Loading