1 /*
2 * Copyright 2023 Trackunit Corporation
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <zephyr/ztest.h>
8 #include <string.h>
9
10 #include "gnss_nmea0183.h"
11
12 #define TEST_DDMM_MMMM_MAX_ROUNDING_ERROR_NDEG (1)
13
14 struct test_ddmm_mmmm_sample {
15 const char *ddmm_mmmm;
16 int64_t ndeg;
17 };
18
19 /*
20 * The conversion from ddmm.mmmm to decimal nano degree is
21 * ((1/60) * mm.mmmm * 1E9) + (dd * 1E9)
22 */
23 static const struct test_ddmm_mmmm_sample ddmm_mmmm_samples[] = {
24 {.ddmm_mmmm = "00.0", .ndeg = 0},
25 {.ddmm_mmmm = "000.0", .ndeg = 0},
26 {.ddmm_mmmm = "9000.0000", .ndeg = 90000000000},
27 {.ddmm_mmmm = "4530.0000", .ndeg = 45500000000},
28 {.ddmm_mmmm = "4530.3000", .ndeg = 45505000000},
29 {.ddmm_mmmm = "4530.3001", .ndeg = 45505001667},
30 {.ddmm_mmmm = "4530.9999", .ndeg = 45516665000},
31 {.ddmm_mmmm = "18000.0000", .ndeg = 180000000000}
32 };
33
ZTEST(gnss_nmea0183,test_ddmm_mmmm)34 ZTEST(gnss_nmea0183, test_ddmm_mmmm)
35 {
36 int64_t min_ndeg;
37 int64_t max_ndeg;
38 int64_t ndeg;
39
40 for (size_t i = 0; i < ARRAY_SIZE(ddmm_mmmm_samples); i++) {
41 zassert_ok(gnss_nmea0183_ddmm_mmmm_to_ndeg(ddmm_mmmm_samples[i].ddmm_mmmm, &ndeg),
42 "Parse failed");
43
44 min_ndeg = ddmm_mmmm_samples[i].ndeg - TEST_DDMM_MMMM_MAX_ROUNDING_ERROR_NDEG;
45 max_ndeg = ddmm_mmmm_samples[i].ndeg + TEST_DDMM_MMMM_MAX_ROUNDING_ERROR_NDEG;
46 zassert_true(ndeg >= min_ndeg, "Parsed value falls below max rounding error");
47 zassert_true(ndeg <= max_ndeg, "Parsed value is above max rounding error");
48 }
49
50 /* Minutes can only go from 0 to 59.9999 */
51 zassert_equal(gnss_nmea0183_ddmm_mmmm_to_ndeg("99.0000", &ndeg), -EINVAL,
52 "Parse should fail");
53
54 zassert_equal(gnss_nmea0183_ddmm_mmmm_to_ndeg("60.0000", &ndeg), -EINVAL,
55 "Parse should fail");
56
57 /* Missing dot */
58 zassert_equal(gnss_nmea0183_ddmm_mmmm_to_ndeg("18000", &ndeg), -EINVAL,
59 "Parse should fail");
60
61 /* Invalid chars */
62 zassert_equal(gnss_nmea0183_ddmm_mmmm_to_ndeg("900#.0a000", &ndeg), -EINVAL,
63 "Parse should fail");
64
65 /* Negative angle */
66 zassert_equal(gnss_nmea0183_ddmm_mmmm_to_ndeg("-18000.0", &ndeg), -EINVAL,
67 "Parse should fail");
68 }
69
70 struct test_knots_to_mms_sample {
71 const char *str;
72 int64_t value;
73 };
74
75 static const struct test_knots_to_mms_sample knots_to_mms_samples[] = {
76 {.str = "1", .value = 514},
77 {.str = "2.2", .value = 1131},
78 {.str = "003241.12543", .value = 1667364}
79 };
80
ZTEST(gnss_nmea0183,test_knots_to_mms)81 ZTEST(gnss_nmea0183, test_knots_to_mms)
82 {
83 int64_t mms;
84
85 for (size_t i = 0; i < ARRAY_SIZE(knots_to_mms_samples); i++) {
86 zassert_ok(gnss_nmea0183_knots_to_mms(knots_to_mms_samples[i].str, &mms),
87 "Parse failed");
88
89 zassert_equal(knots_to_mms_samples[i].value, mms,
90 "Parsed value falls below max rounding error");
91 }
92 }
93
94 struct test_hhmmss_sample {
95 const char *str;
96 uint8_t hour;
97 uint8_t minute;
98 uint16_t millisecond;
99 };
100
101 static const struct test_hhmmss_sample hhmmss_samples[] = {
102 {.str = "000102", .hour = 0, .minute = 1, .millisecond = 2000},
103 {.str = "235959.999", .hour = 23, .minute = 59, .millisecond = 59999},
104 {.str = "000000.0", .hour = 0, .minute = 0, .millisecond = 0}
105 };
106
ZTEST(gnss_nmea0183,test_hhmmss)107 ZTEST(gnss_nmea0183, test_hhmmss)
108 {
109 struct gnss_time utc;
110 int ret;
111
112 for (size_t i = 0; i < ARRAY_SIZE(hhmmss_samples); i++) {
113 zassert_ok(gnss_nmea0183_parse_hhmmss(hhmmss_samples[i].str, &utc),
114 "Parse failed");
115
116 zassert_equal(hhmmss_samples[i].hour, utc.hour, "Failed to parse hour");
117 zassert_equal(hhmmss_samples[i].minute, utc.minute, "Failed to parse minute");
118 zassert_equal(hhmmss_samples[i].millisecond, utc.millisecond,
119 "Failed to parse millisecond");
120 }
121
122 ret = gnss_nmea0183_parse_hhmmss("-101010", &utc);
123 zassert_equal(ret, -EINVAL, "Should fail to parse invalid value");
124
125 ret = gnss_nmea0183_parse_hhmmss("01010", &utc);
126 zassert_equal(ret, -EINVAL, "Should fail to parse invalid value");
127
128 ret = gnss_nmea0183_parse_hhmmss("246060.999", &utc);
129 zassert_equal(ret, -EINVAL, "Should fail to parse invalid value");
130
131 ret = gnss_nmea0183_parse_hhmmss("99a9c9", &utc);
132 zassert_equal(ret, -EINVAL, "Should fail to parse invalid value");
133
134 ret = gnss_nmea0183_parse_hhmmss("12121212", &utc);
135 zassert_equal(ret, -EINVAL, "Should fail to parse invalid value");
136 }
137
138 struct test_ddmmyy_sample {
139 const char *str;
140 uint8_t month_day;
141 uint8_t month;
142 uint16_t century_year;
143 };
144
145 static const struct test_ddmmyy_sample ddmmyy_samples[] = {
146 {.str = "010203", .month_day = 1, .month = 2, .century_year = 3},
147 {.str = "311299", .month_day = 31, .month = 12, .century_year = 99},
148 {.str = "010100", .month_day = 1, .month = 1, .century_year = 0}
149 };
150
ZTEST(gnss_nmea0183,test_ddmmyy)151 ZTEST(gnss_nmea0183, test_ddmmyy)
152 {
153 struct gnss_time utc;
154 int ret;
155
156 for (size_t i = 0; i < ARRAY_SIZE(ddmmyy_samples); i++) {
157 zassert_ok(gnss_nmea0183_parse_ddmmyy(ddmmyy_samples[i].str, &utc),
158 "Parse failed");
159
160 zassert_equal(ddmmyy_samples[i].month_day, utc.month_day,
161 "Failed to parse monthday");
162
163 zassert_equal(ddmmyy_samples[i].month, utc.month, "Failed to parse month");
164 zassert_equal(ddmmyy_samples[i].century_year, utc.century_year,
165 "Failed to parse year");
166 }
167
168 ret = gnss_nmea0183_parse_ddmmyy("000000", &utc);
169 zassert_equal(ret, -EINVAL, "Should fail to parse invalid value");
170
171 ret = gnss_nmea0183_parse_ddmmyy("-12123", &utc);
172 zassert_equal(ret, -EINVAL, "Should fail to parse invalid value");
173
174 ret = gnss_nmea0183_parse_ddmmyy("01010", &utc);
175 zassert_equal(ret, -EINVAL, "Should fail to parse invalid value");
176
177 ret = gnss_nmea0183_parse_ddmmyy("999999", &utc);
178 zassert_equal(ret, -EINVAL, "Should fail to parse invalid value");
179
180 ret = gnss_nmea0183_parse_ddmmyy("99a9c9", &utc);
181 zassert_equal(ret, -EINVAL, "Should fail to parse invalid value");
182
183 ret = gnss_nmea0183_parse_ddmmyy("12121212", &utc);
184 zassert_equal(ret, -EINVAL, "Should fail to parse invalid value");
185 }
186
187 /* "$GNRMC,160833.099,V,,,,,,,090923,,,N,V*27" */
188 const char *rmc_argv_no_fix[15] = {
189 "$GNRMC",
190 "160833.099",
191 "V",
192 "",
193 "",
194 "",
195 "",
196 "",
197 "",
198 "090923",
199 "",
200 "",
201 "N",
202 "V",
203 "27"
204 };
205
206 static struct gnss_data data;
207
ZTEST(gnss_nmea0183,test_parse_rmc_no_fix)208 ZTEST(gnss_nmea0183, test_parse_rmc_no_fix)
209 {
210 int ret;
211
212 /* Corrupt data */
213 memset(&data, 0xFF, sizeof(data));
214
215 ret = gnss_nmea0183_parse_rmc(rmc_argv_no_fix, ARRAY_SIZE(rmc_argv_no_fix), &data);
216 zassert_ok(ret, "NMEA0183 RMC message parse should succeed");
217 }
218
219 /* "$GNGGA,160834.099,,,,,0,0,,,M,,M,,*5E" */
220 const char *gga_argv_no_fix[16] = {
221 "$GNGGA",
222 "160834.099",
223 "",
224 "",
225 "",
226 "",
227 "0",
228 "0",
229 "",
230 "",
231 "M",
232 "",
233 "M",
234 "",
235 "5E"
236 };
237
ZTEST(gnss_nmea0183,test_parse_gga_no_fix)238 ZTEST(gnss_nmea0183, test_parse_gga_no_fix)
239 {
240 int ret;
241
242 /* Corrupt data */
243 memset(&data, 0xFF, sizeof(data));
244
245 ret = gnss_nmea0183_parse_gga(gga_argv_no_fix, ARRAY_SIZE(gga_argv_no_fix), &data);
246 zassert_ok(ret, "NMEA0183 GGA message parse should succeed");
247 zassert_equal(data.info.fix_quality, GNSS_FIX_QUALITY_INVALID,
248 "Incorrectly parsed fix quality");
249
250 zassert_equal(data.info.fix_status, GNSS_FIX_STATUS_NO_FIX,
251 "Incorrectly parsed fix status");
252 }
253
254 /* "$GNRMC,160849.000,A,5709.736602,N,00957.660738,E,0.33,0.00,090923,,,A,V*03" */
255 const char *rmc_argv_fix[15] = {
256 "$GNRMC",
257 "160849.000",
258 "A",
259 "5709.736602",
260 "N",
261 "00957.660738",
262 "E",
263 "0.33",
264 "33.31",
265 "090923",
266 "",
267 "",
268 "A",
269 "V",
270 "03",
271 };
272
ZTEST(gnss_nmea0183,test_parse_rmc_fix)273 ZTEST(gnss_nmea0183, test_parse_rmc_fix)
274 {
275 int ret;
276
277 /* Corrupt data */
278 memset(&data, 0xFF, sizeof(data));
279
280 ret = gnss_nmea0183_parse_rmc(rmc_argv_fix, ARRAY_SIZE(rmc_argv_fix), &data);
281 zassert_ok(ret, "NMEA0183 RMC message parse should succeed");
282 zassert_equal(data.nav_data.latitude, 57162276699, "Incorrectly parsed latitude");
283 zassert_equal(data.nav_data.longitude, 9961012299, "Incorrectly parsed longitude");
284 zassert_equal(data.nav_data.speed, 169, "Incorrectly parsed speed");
285 zassert_equal(data.nav_data.bearing, 33310, "Incorrectly parsed speed");
286 zassert_equal(data.utc.hour, 16, "Incorrectly parsed hour");
287 zassert_equal(data.utc.minute, 8, "Incorrectly parsed minute");
288 zassert_equal(data.utc.millisecond, 49000, "Incorrectly parsed millisecond");
289 zassert_equal(data.utc.month_day, 9, "Incorrectly parsed month day");
290 zassert_equal(data.utc.month, 9, "Incorrectly parsed month");
291 zassert_equal(data.utc.century_year, 23, "Incorrectly parsed century year");
292 }
293
294 /* "$GNGGA,160858.000,5709.734778,N,00957.659514,E,1,6,1.41,15.234,M,42.371,M,,*72" */
295 const char *gga_argv_fix[16] = {
296 "$GNGGA",
297 "160858.000",
298 "5709.734778",
299 "N",
300 "00957.659514",
301 "E",
302 "1",
303 "6",
304 "1.41",
305 "15.234",
306 "M",
307 "42.371",
308 "M",
309 "",
310 "",
311 "72",
312 };
313
ZTEST(gnss_nmea0183,test_parse_gga_fix)314 ZTEST(gnss_nmea0183, test_parse_gga_fix)
315 {
316 int ret;
317
318 /* Corrupt data */
319 memset(&data, 0xFF, sizeof(data));
320
321 ret = gnss_nmea0183_parse_gga(gga_argv_fix, ARRAY_SIZE(gga_argv_fix), &data);
322 zassert_ok(ret, "NMEA0183 GGA message parse should succeed");
323 zassert_equal(data.info.fix_quality, GNSS_FIX_QUALITY_GNSS_SPS,
324 "Incorrectly parsed fix quality");
325
326 zassert_equal(data.info.fix_status, GNSS_FIX_STATUS_GNSS_FIX,
327 "Incorrectly parsed fix status");
328
329 zassert_equal(data.info.satellites_cnt, 6,
330 "Incorrectly parsed number of satellites");
331
332 zassert_equal(data.info.hdop, 1410, "Incorrectly parsed HDOP");
333 zassert_equal(data.nav_data.altitude, 15234, "Incorrectly parsed altitude");
334 }
335
ZTEST(gnss_nmea0183,test_snprintk)336 ZTEST(gnss_nmea0183, test_snprintk)
337 {
338 int ret;
339 char buf[sizeof("$PAIR002,3*27")];
340
341 ret = gnss_nmea0183_snprintk(buf, sizeof(buf), "PAIR%03u,%u", 2, 3);
342 zassert_equal(ret, (sizeof("$PAIR002,3*27") - 1), "Failed to format NMEA0183 message");
343 zassert_ok(strcmp(buf, "$PAIR002,3*27"), "Incorrectly formatted NMEA0183 message");
344
345 ret = gnss_nmea0183_snprintk(buf, sizeof(buf) - 1, "PAIR%03u,%u", 2, 3);
346 zassert_equal(ret, -ENOMEM, "Should fail with -ENOMEM as buffer is too small");
347 }
348
349 /* $GPGSV,8,1,25,21,44,141,47,15,14,049,44,6,31,255,46,3,25,280,44*75 */
350 const char *gpgsv_8_1_25[21] = {
351 "$GPGSV",
352 "8",
353 "1",
354 "25",
355 "21",
356 "44",
357 "141",
358 "47",
359 "15",
360 "14",
361 "049",
362 "44",
363 "6",
364 "31",
365 "255",
366 "46",
367 "3",
368 "25",
369 "280",
370 "44",
371 "75",
372 };
373
374 static const struct gnss_nmea0183_gsv_header gpgsv_8_1_25_header = {
375 .system = GNSS_SYSTEM_GPS,
376 .number_of_messages = 8,
377 .message_number = 1,
378 .number_of_svs = 25
379 };
380
381 static const struct gnss_satellite gpgsv_8_1_25_sats[] = {
382 {.prn = 21, .elevation = 44, .azimuth = 141, .snr = 47,
383 .system = GNSS_SYSTEM_GPS, .is_tracked = true},
384 {.prn = 15, .elevation = 14, .azimuth = 49, .snr = 44,
385 .system = GNSS_SYSTEM_GPS, .is_tracked = true},
386 {.prn = 6, .elevation = 31, .azimuth = 255, .snr = 46,
387 .system = GNSS_SYSTEM_GPS, .is_tracked = true},
388 {.prn = 3, .elevation = 25, .azimuth = 280, .snr = 44,
389 .system = GNSS_SYSTEM_GPS, .is_tracked = true},
390 };
391
392 /* $GPGSV,8,2,25,18,61,057,48,22,68,320,52,27,34,268,47,24,32,076,45*76 */
393 const char *gpgsv_8_2_25[21] = {
394 "$GPGSV",
395 "8",
396 "2",
397 "25",
398 "18",
399 "61",
400 "057",
401 "48",
402 "22",
403 "68",
404 "320",
405 "52",
406 "27",
407 "34",
408 "268",
409 "47",
410 "24",
411 "32",
412 "076",
413 "45",
414 "76",
415 };
416
417 static const struct gnss_nmea0183_gsv_header gpgsv_8_2_25_header = {
418 .system = GNSS_SYSTEM_GPS,
419 .number_of_messages = 8,
420 .message_number = 2,
421 .number_of_svs = 25
422 };
423
424 static const struct gnss_satellite gpgsv_8_2_25_sats[] = {
425 {.prn = 18, .elevation = 61, .azimuth = 57, .snr = 48,
426 .system = GNSS_SYSTEM_GPS, .is_tracked = true},
427 {.prn = 22, .elevation = 68, .azimuth = 320, .snr = 52,
428 .system = GNSS_SYSTEM_GPS, .is_tracked = true},
429 {.prn = 27, .elevation = 34, .azimuth = 268, .snr = 47,
430 .system = GNSS_SYSTEM_GPS, .is_tracked = true},
431 {.prn = 24, .elevation = 32, .azimuth = 76, .snr = 45,
432 .system = GNSS_SYSTEM_GPS, .is_tracked = true},
433 };
434
435 /* $GPGSV,8,3,25,14,51,214,49,19,23,308,46*7E */
436 const char *gpgsv_8_3_25[13] = {
437 "$GPGSV",
438 "8",
439 "3",
440 "25",
441 "14",
442 "51",
443 "214",
444 "49",
445 "19",
446 "23",
447 "308",
448 "46",
449 "7E",
450 };
451
452 static const struct gnss_nmea0183_gsv_header gpgsv_8_3_25_header = {
453 .system = GNSS_SYSTEM_GPS,
454 .number_of_messages = 8,
455 .message_number = 3,
456 .number_of_svs = 25
457 };
458
459 static const struct gnss_satellite gpgsv_8_3_25_sats[] = {
460 {.prn = 14, .elevation = 51, .azimuth = 214, .snr = 49,
461 .system = GNSS_SYSTEM_GPS, .is_tracked = true},
462 {.prn = 19, .elevation = 23, .azimuth = 308, .snr = 46,
463 .system = GNSS_SYSTEM_GPS, .is_tracked = true},
464 };
465
466 /* $GPGSV,8,4,25,51,44,183,49,46,41,169,43,48,36,220,45*47 */
467 const char *gpgsv_8_4_25[17] = {
468 "$GPGSV",
469 "8",
470 "4",
471 "25",
472 "51",
473 "44",
474 "183",
475 "49",
476 "46",
477 "41",
478 "169",
479 "43",
480 "48",
481 "36",
482 "220",
483 "45",
484 "47",
485 };
486
487 static const struct gnss_nmea0183_gsv_header gpgsv_8_4_25_header = {
488 .system = GNSS_SYSTEM_GPS,
489 .number_of_messages = 8,
490 .message_number = 4,
491 .number_of_svs = 25
492 };
493
494 static const struct gnss_satellite gpgsv_8_4_25_sats[] = {
495 {.prn = (51 + 87), .elevation = 44, .azimuth = 183, .snr = 49,
496 .system = GNSS_SYSTEM_SBAS, .is_tracked = true},
497 {.prn = (46 + 87), .elevation = 41, .azimuth = 169, .snr = 43,
498 .system = GNSS_SYSTEM_SBAS, .is_tracked = true},
499 {.prn = (48 + 87), .elevation = 36, .azimuth = 220, .snr = 45,
500 .system = GNSS_SYSTEM_SBAS, .is_tracked = true},
501 };
502
503 /* $GLGSV,8,5,25,82,49,219,52,76,22,051,41,83,37,316,51,67,57,010,51*6C */
504 const char *glgsv_8_5_25[21] = {
505 "$GLGSV",
506 "8",
507 "5",
508 "25",
509 "82",
510 "49",
511 "219",
512 "52",
513 "76",
514 "22",
515 "051",
516 "41",
517 "83",
518 "37",
519 "316",
520 "51",
521 "67",
522 "57",
523 "010",
524 "51",
525 "6C",
526 };
527
528 static const struct gnss_nmea0183_gsv_header glgsv_8_5_25_header = {
529 .system = GNSS_SYSTEM_GLONASS,
530 .number_of_messages = 8,
531 .message_number = 5,
532 .number_of_svs = 25
533 };
534
535 static const struct gnss_satellite glgsv_8_5_25_sats[] = {
536 {.prn = (82 - 64), .elevation = 49, .azimuth = 219, .snr = 52,
537 .system = GNSS_SYSTEM_GLONASS, .is_tracked = true},
538 {.prn = (76 - 64), .elevation = 22, .azimuth = 51, .snr = 41,
539 .system = GNSS_SYSTEM_GLONASS, .is_tracked = true},
540 {.prn = (83 - 64), .elevation = 37, .azimuth = 316, .snr = 51,
541 .system = GNSS_SYSTEM_GLONASS, .is_tracked = true},
542 {.prn = (67 - 64), .elevation = 57, .azimuth = 10, .snr = 51,
543 .system = GNSS_SYSTEM_GLONASS, .is_tracked = true},
544 };
545
546 /* $GLGSV,8,6,25,77,24,108,44,81,10,181,46,78,1,152,34,66,18,060,45*50 */
547 const char *glgsv_8_6_25[21] = {
548 "$GLGSV",
549 "8",
550 "6",
551 "25",
552 "77",
553 "24",
554 "108",
555 "44",
556 "81",
557 "10",
558 "181",
559 "46",
560 "78",
561 "1",
562 "152",
563 "34",
564 "66",
565 "18",
566 "060",
567 "45",
568 "50",
569 };
570
571 static const struct gnss_nmea0183_gsv_header glgsv_8_6_25_header = {
572 .system = GNSS_SYSTEM_GLONASS,
573 .number_of_messages = 8,
574 .message_number = 6,
575 .number_of_svs = 25
576 };
577
578 static const struct gnss_satellite glgsv_8_6_25_sats[] = {
579 {.prn = (77 - 64), .elevation = 24, .azimuth = 108, .snr = 44,
580 .system = GNSS_SYSTEM_GLONASS, .is_tracked = true},
581 {.prn = (81 - 64), .elevation = 10, .azimuth = 181, .snr = 46,
582 .system = GNSS_SYSTEM_GLONASS, .is_tracked = true},
583 {.prn = (78 - 64), .elevation = 1, .azimuth = 152, .snr = 34,
584 .system = GNSS_SYSTEM_GLONASS, .is_tracked = true},
585 {.prn = (66 - 64), .elevation = 18, .azimuth = 60, .snr = 45,
586 .system = GNSS_SYSTEM_GLONASS, .is_tracked = true},
587 };
588
589 /* $GLGSV,8,7,25,68,37,284,50*5C */
590 const char *glgsv_8_7_25[9] = {
591 "$GLGSV",
592 "8",
593 "7",
594 "25",
595 "68",
596 "37",
597 "284",
598 "50",
599 "5C",
600 };
601
602 static const struct gnss_nmea0183_gsv_header glgsv_8_7_25_header = {
603 .system = GNSS_SYSTEM_GLONASS,
604 .number_of_messages = 8,
605 .message_number = 7,
606 .number_of_svs = 25
607 };
608
609 static const struct gnss_satellite glgsv_8_7_25_sats[] = {
610 {.prn = (68 - 64), .elevation = 37, .azimuth = 284, .snr = 50,
611 .system = GNSS_SYSTEM_GLONASS, .is_tracked = true},
612 };
613
614 /* $GBGSV,8,8,25,111,35,221,47,112,4,179,39,114,48,290,48*11 */
615 const char *gbgsv_8_8_25[17] = {
616 "$GBGSV",
617 "8",
618 "8",
619 "25",
620 "111",
621 "35",
622 "221",
623 "47",
624 "112",
625 "4",
626 "179",
627 "39",
628 "114",
629 "48",
630 "290",
631 "48",
632 "11",
633 };
634
635 static const struct gnss_nmea0183_gsv_header gbgsv_8_8_25_header = {
636 .system = GNSS_SYSTEM_BEIDOU,
637 .number_of_messages = 8,
638 .message_number = 8,
639 .number_of_svs = 25
640 };
641
642 static const struct gnss_satellite gbgsv_8_8_25_sats[] = {
643 {.prn = (111 - 100), .elevation = 35, .azimuth = 221, .snr = 47,
644 .system = GNSS_SYSTEM_BEIDOU, .is_tracked = true},
645 {.prn = (112 - 100), .elevation = 4, .azimuth = 179, .snr = 39,
646 .system = GNSS_SYSTEM_BEIDOU, .is_tracked = true},
647 {.prn = (114 - 100), .elevation = 48, .azimuth = 290, .snr = 48,
648 .system = GNSS_SYSTEM_BEIDOU, .is_tracked = true},
649 };
650
651 struct test_gsv_sample {
652 const char **argv;
653 uint16_t argc;
654 const struct gnss_nmea0183_gsv_header *header;
655 const struct gnss_satellite *satellites;
656 uint16_t number_of_svs;
657 };
658
659 static const struct test_gsv_sample gsv_samples[] = {
660 {.argv = gpgsv_8_1_25, .argc = ARRAY_SIZE(gpgsv_8_1_25), .header = &gpgsv_8_1_25_header,
661 .satellites = gpgsv_8_1_25_sats, .number_of_svs = ARRAY_SIZE(gpgsv_8_1_25_sats)},
662 {.argv = gpgsv_8_2_25, .argc = ARRAY_SIZE(gpgsv_8_2_25), .header = &gpgsv_8_2_25_header,
663 .satellites = gpgsv_8_2_25_sats, .number_of_svs = ARRAY_SIZE(gpgsv_8_2_25_sats)},
664 {.argv = gpgsv_8_3_25, .argc = ARRAY_SIZE(gpgsv_8_3_25), .header = &gpgsv_8_3_25_header,
665 .satellites = gpgsv_8_3_25_sats, .number_of_svs = ARRAY_SIZE(gpgsv_8_3_25_sats)},
666 {.argv = gpgsv_8_4_25, .argc = ARRAY_SIZE(gpgsv_8_4_25), .header = &gpgsv_8_4_25_header,
667 .satellites = gpgsv_8_4_25_sats, .number_of_svs = ARRAY_SIZE(gpgsv_8_4_25_sats)},
668 {.argv = glgsv_8_5_25, .argc = ARRAY_SIZE(glgsv_8_5_25), .header = &glgsv_8_5_25_header,
669 .satellites = glgsv_8_5_25_sats, .number_of_svs = ARRAY_SIZE(glgsv_8_5_25_sats)},
670 {.argv = glgsv_8_6_25, .argc = ARRAY_SIZE(glgsv_8_6_25), .header = &glgsv_8_6_25_header,
671 .satellites = glgsv_8_6_25_sats, .number_of_svs = ARRAY_SIZE(glgsv_8_6_25_sats)},
672 {.argv = glgsv_8_7_25, .argc = ARRAY_SIZE(glgsv_8_7_25), .header = &glgsv_8_7_25_header,
673 .satellites = glgsv_8_7_25_sats, .number_of_svs = ARRAY_SIZE(glgsv_8_7_25_sats)},
674 {.argv = gbgsv_8_8_25, .argc = ARRAY_SIZE(gbgsv_8_8_25), .header = &gbgsv_8_8_25_header,
675 .satellites = gbgsv_8_8_25_sats, .number_of_svs = ARRAY_SIZE(gbgsv_8_8_25_sats)},
676 };
677
ZTEST(gnss_nmea0183,test_gsv_parse_headers)678 ZTEST(gnss_nmea0183, test_gsv_parse_headers)
679 {
680 struct gnss_nmea0183_gsv_header header;
681 int ret;
682
683 for (uint16_t i = 0; i < ARRAY_SIZE(gsv_samples); i++) {
684 ret = gnss_nmea0183_parse_gsv_header(gsv_samples[i].argv, gsv_samples[i].argc,
685 &header);
686
687 zassert_ok(ret, "Failed to parse GSV header");
688
689 zassert_equal(header.system, gsv_samples[i].header->system,
690 "Failed to parse GNSS system");
691
692 zassert_equal(header.number_of_messages,
693 gsv_samples[i].header->number_of_messages,
694 "Failed to parse number of messages");
695
696 zassert_equal(header.message_number, gsv_samples[i].header->message_number,
697 "Failed to parse message number");
698
699 zassert_equal(header.number_of_svs, gsv_samples[i].header->number_of_svs,
700 "Failed to parse number of space vehicles");
701 }
702 }
703
ZTEST(gnss_nmea0183,test_gsv_parse_satellites)704 ZTEST(gnss_nmea0183, test_gsv_parse_satellites)
705 {
706 struct gnss_satellite satellites[4];
707 int ret;
708
709 for (uint16_t i = 0; i < ARRAY_SIZE(gsv_samples); i++) {
710 ret = gnss_nmea0183_parse_gsv_svs(gsv_samples[i].argv, gsv_samples[i].argc,
711 satellites, ARRAY_SIZE(satellites));
712
713 zassert_equal(ret, gsv_samples[i].number_of_svs,
714 "Incorrect number of satellites parsed");
715
716 for (uint16_t u = 0; u < gsv_samples[i].number_of_svs; u++) {
717 zassert_equal(gsv_samples[i].satellites[u].prn,
718 satellites[u].prn,
719 "Failed to parse satellite prn");
720 zassert_equal(gsv_samples[i].satellites[u].snr,
721 satellites[u].snr,
722 "Failed to parse satellite snr");
723 zassert_equal(gsv_samples[i].satellites[u].elevation,
724 satellites[u].elevation,
725 "Failed to parse satellite elevation");
726 zassert_equal(gsv_samples[i].satellites[u].azimuth,
727 satellites[u].azimuth,
728 "Failed to parse satellite azimuth");
729 zassert_equal(gsv_samples[i].satellites[u].system,
730 satellites[u].system,
731 "Failed to parse satellite system");
732 zassert_equal(gsv_samples[i].satellites[u].is_tracked,
733 satellites[u].is_tracked,
734 "Failed to parse satellite is_tracked");
735 }
736 }
737 }
738
739 ZTEST_SUITE(gnss_nmea0183, NULL, NULL, NULL, NULL, NULL);
740