-
Notifications
You must be signed in to change notification settings - Fork 41
/
wnc.rs
113 lines (103 loc) · 3.65 KB
/
wnc.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
use arrayvec::ArrayString;
use nom::{
bytes::complete::is_not, character::complete::char, combinator::opt, number::complete::float,
};
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
use super::utils::array_string;
use crate::{
parse::{NmeaSentence, TEXT_PARAMETER_MAX_LEN},
Error, SentenceType,
};
/// WNC - Distance - Waypoint to Waypoint
///
/// <https://gpsd.gitlab.io/gpsd/NMEA.html#_wnc_distance_waypoint_to_waypoint>
///
/// Example of WNC sentences:
/// - $GPWNC,200.00,N,370.40,K,Dest,Origin*58
///
/// ```text
/// 1 2 3 4 5 6
/// | | | | | |
/// $--WNC,x.x,N,x.x,K,c--c,c--c*hh
/// ```
///
/// Key:
/// 1. Distance, Nautical Miles
/// 2. N = Nautical Miles
/// 3. Distance, Kilometers
/// 4. K = Kilometers
/// 5. Waypoint ID, Destination
/// 6. Waypoint ID, Origin
#[derive(Debug, PartialEq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "defmt-03", derive(defmt::Format))]
pub struct WncData {
/// Distance, Nautical Miles
pub distance_nautical_miles: Option<f32>,
/// Distance, Kilometers
pub distance_kilometers: Option<f32>,
/// Waypoint ID, Destination
#[cfg_attr(feature = "defmt-03", defmt(Debug2Format))]
pub waypoint_id_destination: Option<ArrayString<TEXT_PARAMETER_MAX_LEN>>,
/// Waypoint ID, Origin
#[cfg_attr(feature = "defmt-03", defmt(Debug2Format))]
pub waypoint_id_origin: Option<ArrayString<TEXT_PARAMETER_MAX_LEN>>,
}
pub fn do_parse_wnc(i: &str) -> Result<WncData, Error> {
let (i, distance_nautical_miles) = opt(float)(i)?;
let (i, _) = char(',')(i)?;
let (i, _) = opt(char('N'))(i)?;
let (i, _) = char(',')(i)?;
let (i, distance_kilometers) = opt(float)(i)?;
let (i, _) = char(',')(i)?;
let (i, _) = opt(char('K'))(i)?;
let (i, _) = char(',')(i)?;
let (i, waypoint_id_destination) = opt(is_not(","))(i)?;
let waypoint_id_destination = waypoint_id_destination
.map(array_string::<TEXT_PARAMETER_MAX_LEN>)
.transpose()?;
let (i, _) = char(',')(i)?;
let (_i, waypoint_id_origin) = opt(is_not(","))(i)?;
let waypoint_id_origin = waypoint_id_origin
.map(array_string::<TEXT_PARAMETER_MAX_LEN>)
.transpose()?;
Ok(WncData {
distance_nautical_miles,
distance_kilometers,
waypoint_id_destination,
waypoint_id_origin,
})
}
pub fn parse_wnc(sentence: NmeaSentence) -> Result<WncData, Error> {
if sentence.message_id != SentenceType::WNC {
Err(Error::WrongSentenceHeader {
expected: SentenceType::WNC,
found: sentence.message_id,
})
} else {
Ok(do_parse_wnc(sentence.data)?)
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::{parse::parse_nmea_sentence, Error};
use approx::assert_relative_eq;
fn run_parse_wnc(line: &str) -> Result<WncData, Error> {
let s = parse_nmea_sentence(line).expect("WNC sentence initial parse failed");
assert_eq!(s.checksum, s.calc_checksum());
parse_wnc(s)
}
#[test]
fn test_parse_wnc() {
let sentence = parse_nmea_sentence("$GPWNC,200.00,N,370.40,K,Dest,Origin*58").unwrap();
assert_eq!(sentence.checksum, sentence.calc_checksum());
assert_eq!(sentence.checksum, 0x58);
let data = run_parse_wnc("$GPWNC,200.00,N,370.40,K,Dest,Origin*58").unwrap();
assert_relative_eq!(data.distance_nautical_miles.unwrap(), 200.00);
assert_relative_eq!(data.distance_kilometers.unwrap(), 370.40);
assert_eq!(data.waypoint_id_destination.as_deref(), Some("Dest"));
assert_eq!(data.waypoint_id_origin.as_deref(), Some("Origin"));
}
}