1use crate::message::ParsedSentence;
55use crate::types::{MessageType, TalkerId};
56
57#[derive(Debug, Clone)]
59pub struct GsaData {
60 pub talker_id: TalkerId,
61 pub mode: char,
62 pub fix_type: u8,
63 pub satellite_ids: [Option<u8>; 12],
64 pub pdop: Option<f32>,
65 pub hdop: Option<f32>,
66 pub vdop: Option<f32>,
67}
68
69impl ParsedSentence {
70 pub fn as_gsa(&self) -> Option<GsaData> {
110 if self.message_type != MessageType::GSA {
111 return None;
112 }
113
114 let mode = self.parse_field_char(1)?;
116 let fix_type: u8 = self.parse_field(2)?;
117
118 Some(GsaData {
119 talker_id: self.talker_id,
120 mode,
121 fix_type,
122 satellite_ids: [
123 self.parse_field(3),
124 self.parse_field(4),
125 self.parse_field(5),
126 self.parse_field(6),
127 self.parse_field(7),
128 self.parse_field(8),
129 self.parse_field(9),
130 self.parse_field(10),
131 self.parse_field(11),
132 self.parse_field(12),
133 self.parse_field(13),
134 self.parse_field(14),
135 ],
136 pdop: self.parse_field(15),
137 hdop: self.parse_field(16),
138 vdop: self.parse_field(17),
139 })
140 }
141}
142
143#[cfg(test)]
144mod tests {
145 use crate::NmeaParser;
146
147 #[test]
148 fn test_gsa_complete_message() {
149 let parser = NmeaParser::new();
150 let sentence = b"$GPGSA,A,3,04,05,,09,12,,,24,,,,,2.5,1.3,2.1*39\r\n";
151
152 let result = parser.parse_sentence_complete(sentence);
153
154 assert!(result.is_some());
155 let msg = result.unwrap();
156 let gsa = msg.as_gsa();
157 assert!(gsa.is_some());
158
159 let gsa_data = gsa.unwrap();
160 assert_eq!(gsa_data.mode, 'A');
161 assert_eq!(gsa_data.fix_type, 3);
162 assert_eq!(gsa_data.satellite_ids[0], Some(4));
163 assert_eq!(gsa_data.satellite_ids[1], Some(5));
164 assert_eq!(gsa_data.satellite_ids[2], None);
165 assert_eq!(gsa_data.satellite_ids[3], Some(9));
166 assert_eq!(gsa_data.satellite_ids[4], Some(12));
167 assert_eq!(gsa_data.pdop, Some(2.5));
168 assert_eq!(gsa_data.hdop, Some(1.3));
169 assert_eq!(gsa_data.vdop, Some(2.1));
170 }
171
172 #[test]
173 fn test_gsa_manual_mode() {
174 let parser = NmeaParser::new();
175 let sentence = b"$GPGSA,M,3,04,05,,09,12,,,24,,,,,2.5,1.3,2.1*39\r\n";
176
177 let result = parser.parse_sentence_complete(sentence);
178
179 assert!(result.is_some());
180 let msg = result.unwrap();
181 let gsa = msg.as_gsa();
182 assert!(gsa.is_some());
183
184 let gsa_data = gsa.unwrap();
185 assert_eq!(gsa_data.mode, 'M');
186 }
187
188 #[test]
189 fn test_gsa_2d_fix() {
190 let parser = NmeaParser::new();
191 let sentence = b"$GPGSA,A,2,04,05,,09,12,,,24,,,,,2.5,1.3,2.1*39\r\n";
192
193 let result = parser.parse_sentence_complete(sentence);
194
195 assert!(result.is_some());
196 let msg = result.unwrap();
197 let gsa = msg.as_gsa();
198 assert!(gsa.is_some());
199
200 let gsa_data = gsa.unwrap();
201 assert_eq!(gsa_data.fix_type, 2);
202 }
203
204 #[test]
205 fn test_gsa_no_fix() {
206 let parser = NmeaParser::new();
207 let sentence = b"$GPGSA,A,1,,,,,,,,,,,,,,,*39\r\n";
208
209 let result = parser.parse_sentence_complete(sentence);
210
211 assert!(result.is_some());
212 let msg = result.unwrap();
213 let gsa = msg.as_gsa();
214 assert!(gsa.is_some());
215
216 let gsa_data = gsa.unwrap();
217 assert_eq!(gsa_data.fix_type, 1);
218 assert_eq!(gsa_data.satellite_ids[0], None);
219 }
220
221 #[test]
222 fn test_gsa_partial_satellites() {
223 let parser = NmeaParser::new();
224 let sentence = b"$GPGSA,A,3,01,,,,,,,,,,,,2.5,1.3,2.1*39\r\n";
225
226 let result = parser.parse_sentence_complete(sentence);
227
228 assert!(result.is_some());
229 let msg = result.unwrap();
230 let gsa = msg.as_gsa();
231 assert!(gsa.is_some());
232
233 let gsa_data = gsa.unwrap();
234 assert_eq!(gsa_data.satellite_ids[0], Some(1));
235 assert_eq!(gsa_data.satellite_ids[1], None);
236 assert_eq!(gsa_data.satellite_ids[11], None);
237 }
238
239 #[test]
240 fn test_gsa_all_satellites() {
241 let parser = NmeaParser::new();
242 let sentence = b"$GPGSA,A,3,01,02,03,04,05,06,07,08,09,10,11,12,2.5,1.3,2.1*39\r\n";
243
244 let result = parser.parse_sentence_complete(sentence);
245
246 assert!(result.is_some());
247 let msg = result.unwrap();
248 let gsa = msg.as_gsa();
249 assert!(gsa.is_some());
250
251 let gsa_data = gsa.unwrap();
252 for i in 0..12 {
253 assert_eq!(gsa_data.satellite_ids[i], Some((i + 1) as u8));
254 }
255 }
256
257 #[test]
258 fn test_gsa_without_dop() {
259 let parser = NmeaParser::new();
260 let sentence = b"$GPGSA,A,3,04,05,,09,12,,,24,,,,,,,*39\r\n";
261
262 let result = parser.parse_sentence_complete(sentence);
263
264 assert!(result.is_some());
265 let msg = result.unwrap();
266 let gsa = msg.as_gsa();
267 assert!(gsa.is_some());
268
269 let gsa_data = gsa.unwrap();
270 assert_eq!(gsa_data.pdop, None);
271 assert_eq!(gsa_data.hdop, None);
272 assert_eq!(gsa_data.vdop, None);
273 }
274
275 #[test]
276 fn test_gsa_missing_mode() {
277 let parser = NmeaParser::new();
278 let sentence = b"$GPGSA,,3,04,05,,09,12,,,24,,,,,2.5,1.3,2.1*39\r\n";
279
280 let result = parser.parse_sentence_complete(sentence);
281
282 assert!(result.is_none());
284 }
285
286 #[test]
287 fn test_gsa_missing_fix_type() {
288 let parser = NmeaParser::new();
289 let sentence = b"$GPGSA,A,,04,05,,09,12,,,24,,,,,2.5,1.3,2.1*39\r\n";
290
291 let result = parser.parse_sentence_complete(sentence);
292
293 assert!(result.is_none());
295 }
296
297 #[test]
298 fn test_gsa_dop_precision() {
299 let parser = NmeaParser::new();
300 let sentence = b"$GPGSA,A,3,04,05,,09,12,,,24,,,,,2.5,1.3,2.1*39\r\n";
301
302 let result = parser.parse_sentence_complete(sentence);
303
304 assert!(result.is_some());
305 let msg = result.unwrap();
306 let gsa = msg.as_gsa();
307 assert!(gsa.is_some());
308
309 let gsa_data = gsa.unwrap();
310 assert!((gsa_data.pdop.unwrap() - 2.5).abs() < 0.01);
311 assert!((gsa_data.hdop.unwrap() - 1.3).abs() < 0.01);
312 assert!((gsa_data.vdop.unwrap() - 2.1).abs() < 0.01);
313 }
314
315 #[test]
316 fn test_gsa_different_talker_id() {
317 let parser = NmeaParser::new();
318 let sentence = b"$GNGSA,A,3,04,05,,09,12,,,24,,,,,2.5,1.3,2.1*39\r\n";
320
321 let result = parser.parse_sentence_complete(sentence);
322
323 assert!(result.is_some());
324 let msg = result.unwrap();
325 let gsa = msg.as_gsa();
326 assert!(gsa.is_some());
327
328 let gsa_data = gsa.unwrap();
329 assert_eq!(gsa_data.talker_id, crate::types::TalkerId::GN);
330 }
331
332 #[test]
333 fn test_gsa_constellation_tracking() {
334 let parser = NmeaParser::new();
335
336 let bd_sentence = b"$BDGSA,A,3,04,05,,09,12,,,24,,,,,2.5,1.3,2.1*39\r\n";
338 let bd_result = parser.parse_sentence_complete(bd_sentence);
339 assert!(bd_result.is_some());
340 let bd_msg = bd_result.unwrap();
341 let bd_gsa = bd_msg.as_gsa().unwrap();
342 assert_eq!(bd_gsa.talker_id, crate::types::TalkerId::BD);
343
344 let qz_sentence = b"$QZGSA,A,3,04,05,,09,12,,,24,,,,,2.5,1.3,2.1*39\r\n";
346 let qz_result = parser.parse_sentence_complete(qz_sentence);
347 assert!(qz_result.is_some());
348 let qz_msg = qz_result.unwrap();
349 let qz_gsa = qz_msg.as_gsa().unwrap();
350 assert_eq!(qz_gsa.talker_id, crate::types::TalkerId::QZ);
351 }
352}