-
Notifications
You must be signed in to change notification settings - Fork 42
/
Copy pathgll.rs
135 lines (125 loc) · 4.27 KB
/
gll.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
use chrono::NaiveTime;
use nom::{
character::complete::{anychar, char, one_of},
combinator::opt,
IResult,
};
use super::{faa_mode::parse_faa_mode, nom_parse_failure, FaaMode};
use crate::{
parse::NmeaSentence,
sentences::utils::{parse_hms, parse_lat_lon},
Error, SentenceType,
};
/// GLL - Geographic Position - Latitude/Longitude
///
/// <https://gpsd.gitlab.io/gpsd/NMEA.html#_gll_geographic_position_latitudelongitude>
///
/// ```text
/// 1 2 3 4 5 6 7
/// | | | | | | |
/// $--GLL,ddmm.mm,a,dddmm.mm,a,hhmmss.ss,a*hh<CR><LF>
/// ```
///
/// NMEA 2.3:
/// ```text
/// 1 2 3 4 5 6 7
/// | | | | | | |
/// $--GLL,ddmm.mm,a,dddmm.mm,a,hhmmss.ss,a,m*hh<CR><LF>
/// ```
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "defmt-03", derive(defmt::Format))]
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct GllData {
pub latitude: Option<f64>,
pub longitude: Option<f64>,
#[cfg_attr(feature = "defmt-03", defmt(Debug2Format))]
pub fix_time: NaiveTime,
pub valid: bool,
pub faa_mode: Option<FaaMode>,
}
/// # Parse GLL (Geographic position) message
///
/// From <https://docs.novatel.com/OEM7/Content/Logs/GPGLL.htm>
///
/// | Field | Structure | Description
/// |-------|-------------|---------------------------------------------------------------------
/// | 1 | $GPGLL | Log header.
/// | 2 | lat | Latitude (DDmm.mm)
/// | 3 | lat dir | Latitude direction (N = North, S = South)
/// | 4 | lon | Longitude (DDDmm.mm)
/// | 5 | lon dir | Longitude direction (E = East, W = West)
/// | 6 | utc | UTC time status of position (hours/minutes/seconds/decimal seconds)
/// | 7 | data status | Data status: A = Data valid, V = Data invalid
/// | 8 | mode ind | Positioning system mode indicator, see `PosSystemIndicator`
/// | 9 | *xx | Check sum
pub fn parse_gll(sentence: NmeaSentence) -> Result<GllData, Error> {
if sentence.message_id != SentenceType::GLL {
Err(Error::WrongSentenceHeader {
expected: SentenceType::GLL,
found: sentence.message_id,
})
} else {
Ok(do_parse_gll(sentence.data)?.1)
}
}
fn do_parse_gll(i: &str) -> IResult<&str, GllData> {
let (i, lat_lon) = parse_lat_lon(i)?;
let (i, _) = char(',')(i)?;
let (i, fix_time) = parse_hms(i)?;
let (i, _) = char(',')(i)?;
let (i, valid) = one_of("AV")(i)?; // A: valid, V: invalid
let valid = match valid {
'A' => true,
'V' => false,
_ => unreachable!(),
};
let (i, _) = char(',')(i)?;
let (rest, mode) = opt(anychar)(i)?;
let faa_mode = mode
.map(|mode| parse_faa_mode(mode).ok_or_else(|| nom_parse_failure(i)))
.transpose()?;
Ok((
rest,
GllData {
latitude: lat_lon.map(|x| x.0),
longitude: lat_lon.map(|x| x.1),
valid,
fix_time,
faa_mode,
},
))
}
#[cfg(test)]
mod tests {
use approx::assert_relative_eq;
use super::*;
use crate::parse::parse_nmea_sentence;
#[test]
fn test_parse_gpgll() {
let parse = |data, checksum| {
let s = parse_nmea_sentence(data).unwrap();
assert_eq!(s.checksum, s.calc_checksum());
assert_eq!(s.checksum, checksum);
s
};
let s = parse(
"$GPGLL,5107.0013414,N,11402.3279144,W,205412.00,A,A*73",
0x73,
);
let gll_data = parse_gll(s).unwrap();
assert_relative_eq!(gll_data.latitude.unwrap(), 51.0 + (7.0013414 / 60.0));
assert_relative_eq!(gll_data.longitude.unwrap(), -(114.0 + (2.3279144 / 60.0)));
assert_eq!(
gll_data.fix_time,
NaiveTime::from_hms_milli_opt(20, 54, 12, 0).expect("invalid time")
);
assert_eq!(gll_data.faa_mode, Some(FaaMode::Autonomous));
let s = parse("$GNGLL,,,,,181604.00,V,N*5E", 0x5e);
let gll_data = parse_gll(s).unwrap();
assert_eq!(
NaiveTime::from_hms_milli_opt(18, 16, 4, 0).expect("invalid time"),
gll_data.fix_time
);
assert!(!gll_data.valid);
}
}