1use super::*;
17#[derive(Clone, Debug, PartialEq, Serialize)]
19pub struct GsaData {
20 pub source: NavigationSystem,
22
23 pub mode1_automatic: Option<bool>,
25
26 pub mode2_3d: Option<GsaFixMode>,
28
29 pub prn_numbers: Vec<u8>,
31
32 pub pdop: Option<f64>,
34
35 pub hdop: Option<f64>,
37
38 pub vdop: Option<f64>,
40}
41
42#[derive(Clone, Copy, Debug, PartialEq, Serialize)]
44pub enum GsaFixMode {
45 NotAvailable,
47
48 Fix2D,
50
51 Fix3D,
53}
54
55impl core::fmt::Display for GsaFixMode {
56 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
57 match self {
58 GsaFixMode::NotAvailable => write!(f, "no available"),
59 GsaFixMode::Fix2D => write!(f, "2D fix"),
60 GsaFixMode::Fix3D => write!(f, "3D fix"),
61 }
62 }
63}
64
65pub(crate) fn handle(
69 sentence: &str,
70 nav_system: NavigationSystem,
71) -> Result<ParsedMessage, ParseError> {
72 let split: Vec<&str> = sentence.split(',').collect();
73
74 Ok(ParsedMessage::Gsa(GsaData {
75 source: nav_system,
76 mode1_automatic: {
77 let s = split.get(1).unwrap_or(&"");
78 match *s {
79 "M" => Some(false),
80 "A" => Some(true),
81 "" => None,
82 _ => {
83 return Err(format!("Invalid GPGSA mode: {}", s).into());
84 }
85 }
86 },
87 mode2_3d: {
88 let s = split.get(2).unwrap_or(&"");
89 match *s {
90 "1" => Some(GsaFixMode::NotAvailable),
91 "2" => Some(GsaFixMode::Fix2D),
92 "3" => Some(GsaFixMode::Fix3D),
93 "" => None,
94 _ => {
95 return Err(format!("Invalid GPGSA fix type: {}", s).into());
96 }
97 }
98 },
99 prn_numbers: {
100 let mut v = Vec::with_capacity(12);
101 for i in 3..15 {
102 if split.get(i).unwrap_or(&"") != &"" {
103 if let Some(val) = pick_number_field(&split, i)? {
104 v.push(val);
105 }
106 }
107 }
108 v
109 },
110 pdop: pick_number_field(&split, 15)?,
111 hdop: pick_number_field(&split, 16)?,
112 vdop: pick_number_field(&split, 17)?,
113 }))
114}
115
116#[cfg(test)]
119mod test {
120 use super::*;
121
122 #[test]
123 fn test_parse_gpgsa() {
124 let mut p = NmeaParser::new();
125 match p.parse_sentence("$GPGSA,A,3,19,28,14,18,27,22,31,39,,,,,1.7,1.0,1.3*34") {
126 Ok(ps) => {
127 match ps {
128 ParsedMessage::Gsa(gsa) => {
130 assert_eq!(gsa.mode1_automatic, Some(true));
131 assert_eq!(gsa.mode2_3d, Some(GsaFixMode::Fix3D));
132 assert_eq!(gsa.prn_numbers, vec![19, 28, 14, 18, 27, 22, 31, 39]);
133 assert_eq!(gsa.pdop, Some(1.7));
134 assert_eq!(gsa.hdop, Some(1.0));
135 assert_eq!(gsa.vdop, Some(1.3));
136 }
137 ParsedMessage::Incomplete => {
138 assert!(false);
139 }
140 _ => {
141 assert!(false);
142 }
143 }
144 }
145 Err(e) => {
146 assert_eq!(e.to_string(), "OK");
147 }
148 }
149 }
150}