Skip to content

Commit

Permalink
Merge pull request #3 from Dushistov/fix-issue-2
Browse files Browse the repository at this point in the history
Fix issue 2
  • Loading branch information
Dushistov authored Sep 17, 2018
2 parents cdbe395 + 8beead9 commit ad262f2
Show file tree
Hide file tree
Showing 5 changed files with 162 additions and 64 deletions.
4 changes: 2 additions & 2 deletions examples/serial.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,9 @@

extern crate nmea;

use std::io::{BufRead, BufReader};
use std::fs::File;
use std::env;
use std::fs::File;
use std::io::{BufRead, BufReader};

fn main() {
let mut nmea = nmea::Nmea::new();
Expand Down
14 changes: 5 additions & 9 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ use chrono::{NaiveDate, NaiveTime};
pub use parse::{parse, GgaData, GsaData, GsvData, ParseResult, RmcData, RmcStatusOfFix, VtgData};

/// NMEA parser
#[derive(Default)]
#[derive(Default, Debug)]
pub struct Nmea {
pub fix_time: Option<NaiveTime>,
pub fix_date: Option<NaiveDate>,
Expand Down Expand Up @@ -172,7 +172,8 @@ impl<'a> Nmea {

fn merge_gsv_data(&mut self, data: GsvData) -> Result<(), &'static str> {
{
let d = self.satellites_scan
let d = self
.satellites_scan
.get_mut(&data.gnss_type)
.ok_or("Invalid GNSS type")?;
// Adjust size to this scan
Expand Down Expand Up @@ -347,7 +348,8 @@ impl<'a> Nmea {
match self.fix_type {
Some(FixType::Invalid) | None => Ok(FixType::Invalid),
Some(ref fix_type)
if self.required_sentences_for_nav
if self
.required_sentences_for_nav
.is_subset(&self.sentences_for_this_time) =>
{
Ok(fix_type.clone())
Expand All @@ -357,12 +359,6 @@ impl<'a> Nmea {
}
}

impl fmt::Debug for Nmea {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{:?}", self)
}
}

impl fmt::Display for Nmea {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
Expand Down
132 changes: 88 additions & 44 deletions src/parse.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@ use chrono::{NaiveDate, NaiveTime};
use nom;
use nom::{digit, AsChar, IError, IResult};

use FixType;
use GnssType;
use Satellite;
use FixType;
use SentenceType;

pub struct NmeaSentence<'a> {
Expand Down Expand Up @@ -69,8 +69,12 @@ named!(
do_parse_nmea_sentence<NmeaSentence>,
map_res!(
do_parse!(
char!('$') >> talker_id: take!(2) >> message_id: take!(3) >> char!(',')
>> data: take_until!("*") >> cs: parse_checksum
char!('$')
>> talker_id: take!(2)
>> message_id: take!(3)
>> char!(',')
>> data: take_until!("*")
>> cs: parse_checksum
>> (talker_id, message_id, data, cs)
),
construct_sentence
Expand Down Expand Up @@ -128,9 +132,12 @@ named!(
parse_gsv_sat_info<Satellite>,
map_res!(
do_parse!(
prn: map_res!(digit, parse_num::<u32>) >> char!(',')
>> elevation: opt!(map_res!(digit, parse_num::<i32>)) >> char!(',')
>> azimuth: opt!(map_res!(digit, parse_num::<i32>)) >> char!(',')
prn: map_res!(digit, parse_num::<u32>)
>> char!(',')
>> elevation: opt!(map_res!(digit, parse_num::<i32>))
>> char!(',')
>> azimuth: opt!(map_res!(digit, parse_num::<i32>))
>> char!(',')
>> signal_noise: opt!(map_res!(complete!(digit), parse_num::<i32>))
>> dbg!(alt!(eof!() | tag!(",")))
>> (prn, elevation, azimuth, signal_noise)
Expand Down Expand Up @@ -163,9 +170,12 @@ named!(
do_parse_gsv<GsvData>,
map_res!(
do_parse!(
number_of_sentences: map_res!(digit, parse_num::<u16>) >> char!(',')
>> sentence_index: map_res!(digit, parse_num::<u16>) >> char!(',')
>> total_number_of_sats: map_res!(digit, parse_num::<u16>) >> char!(',')
number_of_sentences: map_res!(digit, parse_num::<u16>)
>> char!(',')
>> sentence_index: map_res!(digit, parse_num::<u16>)
>> char!(',')
>> total_number_of_sats: map_res!(digit, parse_num::<u16>)
>> char!(',')
>> sat0: opt!(complete!(parse_gsv_sat_info))
>> sat1: opt!(complete!(parse_gsv_sat_info))
>> sat2: opt!(complete!(parse_gsv_sat_info))
Expand Down Expand Up @@ -218,12 +228,13 @@ pub fn parse_gsv(sentence: &NmeaSentence) -> Result<GsvData, String> {
_ => return Err("Unknown GNSS type in GSV sentence".into()),
};
// println!("parse: '{}'", str::from_utf8(sentence.data).unwrap());
let mut res: GsvData = do_parse_gsv(sentence.data)
.to_full_result()
.map_err(|err| match err {
IError::Incomplete(_) => "Incomplete nmea sentence".to_string(),
IError::Error(e) => e.to_string(),
})?;
let mut res: GsvData =
do_parse_gsv(sentence.data)
.to_full_result()
.map_err(|err| match err {
IError::Incomplete(_) => "Incomplete nmea sentence".to_string(),
IError::Error(e) => e.to_string(),
})?;
res.gnss_type = gnss_type.clone();
for sat in &mut res.sats_info {
if let Some(v) = (*sat).as_mut() {
Expand Down Expand Up @@ -319,7 +330,8 @@ named!(
parse_hms<NaiveTime>,
map_res!(
do_parse!(
hour: map_res!(take!(2), parse_num::<u32>) >> min: map_res!(take!(2), parse_num::<u32>)
hour: map_res!(take!(2), parse_num::<u32>)
>> min: map_res!(take!(2), parse_num::<u32>)
>> sec: map_res!(take_until!(","), parse_float_num::<f64>)
>> (hour, min, sec)
),
Expand Down Expand Up @@ -363,10 +375,13 @@ named!(
map_res!(
do_parse!(
lat_deg: map_res!(take!(2), parse_num::<u8>)
>> lat_min: map_res!(float_number, parse_float_num::<f64>) >> char!(',')
>> lat_dir: one_of!("NS") >> char!(',')
>> lat_min: map_res!(float_number, parse_float_num::<f64>)
>> char!(',')
>> lat_dir: one_of!("NS")
>> char!(',')
>> lon_deg: map_res!(take!(3), parse_num::<u8>)
>> lon_min: map_res!(float_number, parse_float_num::<f64>) >> char!(',')
>> lon_min: map_res!(float_number, parse_float_num::<f64>)
>> char!(',')
>> lon_dir: one_of!("EW")
>> (lat_deg, lat_min, lat_dir, lon_deg, lon_min, lon_dir)
),
Expand Down Expand Up @@ -397,20 +412,23 @@ named!(
map_res!(
tag!(",,,"),
|_| -> Result<Option<(f64, f64)>, &'static str> { Ok(None) }
) | map_res!(
do_parse_lat_lon,
|v| -> Result<Option<(f64, f64)>, &'static str> { Ok(Some(v)) }
)
| map_res!(
do_parse_lat_lon,
|v| -> Result<Option<(f64, f64)>, &'static str> { Ok(Some(v)) }
)
)
);

named!(
do_parse_gga<GgaData>,
map_res!(
do_parse!(
time: opt!(complete!(parse_hms)) >> char!(',') >> lat_lon: parse_lat_lon >> char!(',')
>> fix_quality: dbg!(one_of!("012345678")) >> char!(',')
time: opt!(complete!(parse_hms))
>> char!(',')
>> lat_lon: parse_lat_lon
>> char!(',')
>> fix_quality: dbg!(one_of!("012345678"))
>> char!(',')
>> tracked_sats: opt!(complete!(map_res!(digit, parse_num::<u32>)))
>> char!(',')
>> hdop: opt!(complete!(map_res!(float_number, parse_float_num::<f32>)))
Expand All @@ -419,12 +437,17 @@ named!(
opt!(complete!(map_res!(
take_until!(","),
parse_float_num::<f32>
))) >> char!(',') >> opt!(complete!(char!('M'))) >> char!(',')
)))
>> char!(',')
>> opt!(complete!(char!('M')))
>> char!(',')
>> geoid_height:
opt!(complete!(map_res!(
take_until!(","),
parse_float_num::<f32>
))) >> char!(',') >> opt!(complete!(char!('M')))
)))
>> char!(',')
>> opt!(complete!(char!('M')))
>> (
time,
lat_lon,
Expand Down Expand Up @@ -526,9 +549,9 @@ fn test_parse_gga_full() {

#[test]
fn test_parse_gga_with_optional_fields() {
let sentence = parse_nmea_sentence(
b"$GPGGA,133605.0,5521.75946,N,03731.93769,E,0,00,,,M,,M,,*4F",
).unwrap();
let sentence =
parse_nmea_sentence(b"$GPGGA,133605.0,5521.75946,N,03731.93769,E,0,00,,,M,,M,,*4F")
.unwrap();
assert_eq!(sentence.checksum, sentence.calc_checksum());
assert_eq!(sentence.checksum, 0x4f);
let data = parse_gga(&sentence).unwrap();
Expand Down Expand Up @@ -557,8 +580,10 @@ named!(
parse_date<NaiveDate>,
map_res!(
do_parse!(
day: map_res!(take!(2), parse_num::<u8>) >> month: map_res!(take!(2), parse_num::<u8>)
>> year: map_res!(take!(2), parse_num::<u8>) >> (day, month, year)
day: map_res!(take!(2), parse_num::<u8>)
>> month: map_res!(take!(2), parse_num::<u8>)
>> year: map_res!(take!(2), parse_num::<u8>)
>> (day, month, year)
),
|data: (u8, u8, u8)| -> Result<NaiveDate, &'static str> {
let (day, month, year) = (u32::from(data.0), u32::from(data.1), i32::from(data.2));
Expand All @@ -577,13 +602,19 @@ named!(
do_parse_rmc<RmcData>,
map_res!(
do_parse!(
time: opt!(complete!(parse_hms)) >> char!(',') >> status_of_fix: one_of!("ADV")
>> char!(',') >> lat_lon: parse_lat_lon >> char!(',')
time: opt!(complete!(parse_hms))
>> char!(',')
>> status_of_fix: one_of!("ADV")
>> char!(',')
>> lat_lon: parse_lat_lon
>> char!(',')
>> speed_over_ground:
opt!(complete!(map_res!(float_number, parse_float_num::<f32>)))
>> char!(',')
>> true_course: opt!(complete!(map_res!(float_number, parse_float_num::<f32>)))
>> char!(',') >> date: opt!(complete!(parse_date)) >> char!(',')
>> char!(',')
>> date: opt!(complete!(parse_date))
>> char!(',')
>> (
time,
status_of_fix,
Expand Down Expand Up @@ -739,9 +770,12 @@ type GsaTail = (Vec<Option<u32>>, Option<f32>, Option<f32>, Option<f32>);
named!(
do_parse_gsa_tail<GsaTail>,
do_parse!(
prns: gsa_prn_fields_parse >> pdop: map_res!(float_number, parse_float_num::<f32>)
>> char!(',') >> hdop: map_res!(float_number, parse_float_num::<f32>)
>> char!(',') >> vdop: map_res!(float_number, parse_float_num::<f32>)
prns: gsa_prn_fields_parse
>> pdop: map_res!(float_number, parse_float_num::<f32>)
>> char!(',')
>> hdop: map_res!(float_number, parse_float_num::<f32>)
>> char!(',')
>> vdop: map_res!(float_number, parse_float_num::<f32>)
>> (prns, Some(pdop), Some(hdop), Some(vdop))
)
);
Expand All @@ -762,7 +796,10 @@ named!(
do_parse_gsa<GsaData>,
map_res!(
do_parse!(
mode1: one_of!("MA") >> char!(',') >> mode2: one_of!("123") >> char!(',')
mode1: one_of!("MA")
>> char!(',')
>> mode2: one_of!("123")
>> char!(',')
>> tail: alt_complete!(do_parse_empty_gsa_tail | do_parse_gsa_tail)
>> (mode1, mode2, tail)
),
Expand Down Expand Up @@ -948,14 +985,21 @@ named!(
map_res!(
do_parse!(
true_course: opt!(map_res!(complete!(float_number), parse_float_num::<f32>))
>> char!(',') >> opt!(complete!(char!('T'))) >> char!(',')
>> char!(',')
>> opt!(complete!(char!('T')))
>> char!(',')
>> magn_course: opt!(map_res!(complete!(float_number), parse_float_num::<f32>))
>> char!(',') >> opt!(complete!(char!('M'))) >> char!(',')
>> char!(',')
>> opt!(complete!(char!('M')))
>> char!(',')
>> knots_ground_speed:
opt!(map_res!(complete!(float_number), parse_float_num::<f32>))
>> char!(',') >> opt!(complete!(char!('N')))
>> kph_ground_speed: opt!(complete!(map_res!(float_number, parse_float_num::<f32>)))
>> char!(',') >> opt!(complete!(char!('K')))
>> char!(',')
>> opt!(complete!(char!('N')))
>> kph_ground_speed:
opt!(complete!(map_res!(float_number, parse_float_num::<f32>)))
>> char!(',')
>> opt!(complete!(char!('K')))
>> (true_course, knots_ground_speed, kph_ground_speed)
),
|data: (Option<f32>, Option<f32>, Option<f32>)| -> Result<VtgData, String> {
Expand Down
39 changes: 30 additions & 9 deletions tests/file_log_parser.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
extern crate nmea;

use std::path::Path;
use std::error::Error;
use std::io::{BufRead, BufReader};
use std::fs::File;
use std::io::{BufRead, BufReader};
use std::path::Path;

fn err_to_string<E: Error>(e: E) -> String {
e.description().to_string()
Expand All @@ -14,9 +14,11 @@ fn process_file(n: &Path) -> Result<Vec<String>, String> {
let mut nmea = nmea::Nmea::new();
let mut ret = Vec::with_capacity(15_000);
for (num, line) in input.lines().enumerate() {
let line = line.map_err(err_to_string)
let line = line
.map_err(err_to_string)
.map_err(|s| format!("{} at line {}", s, num + 1))?;
let parse_res = nmea.parse(&line)
let parse_res = nmea
.parse(&line)
.map_err(|s| format!("{} at line {}", s, num + 1))?;
ret.push(format!("{:?}", parse_res));
}
Expand All @@ -28,10 +30,29 @@ fn test_parse_file_log() {
let res = process_file(&Path::new("tests").join("nmea1.log"))
.unwrap_or_else(|err| panic!("process file failed with error '{}'", err));

let expected: Vec<_> = BufReader::new(
File::open(&Path::new("tests").join("nmea1.log.expected")).unwrap(),
).lines()
.map(|v| v.unwrap())
.collect();
let expected: Vec<_> =
BufReader::new(File::open(&Path::new("tests").join("nmea1.log.expected")).unwrap())
.lines()
.map(|v| v.unwrap())
.collect();
assert_eq!(expected, res);
}

#[test]
fn test_parse_issue_2() {
let mut input = BufReader::new(File::open(&Path::new("tests").join("nmea2.log")).unwrap());
let mut nmea = nmea::Nmea::new();
for _ in 0..100 {
let mut buffer = String::new();
let size = input.read_line(&mut buffer).unwrap();
eprintln!("buffer = {:?}", buffer);
if size > 0 {
if buffer.as_bytes()[0] == b'$' {
let _ = nmea.parse(&buffer);
println!("{:?}", nmea);
}
} else {
break;
}
}
}
Loading

0 comments on commit ad262f2

Please sign in to comment.