1 /*
2  * Copyright (c) 2023 Trackunit Corporation
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <zephyr/drivers/gnss/gnss_publish.h>
8 #include <zephyr/kernel.h>
9 #include <zephyr/modem/chat.h>
10 
11 #include <string.h>
12 
13 #include "gnss_parse.h"
14 #include "gnss_nmea0183.h"
15 #include "gnss_nmea0183_match.h"
16 
gnss_nmea0183_match_parse_utc(char ** argv,uint16_t argc,uint32_t * utc)17 static int gnss_nmea0183_match_parse_utc(char **argv, uint16_t argc, uint32_t *utc)
18 {
19 	int64_t i64;
20 
21 	if ((gnss_parse_dec_to_milli(argv[1], &i64) < 0) ||
22 	    (i64 < 0) ||
23 	    (i64 > UINT32_MAX)) {
24 		return -EINVAL;
25 	}
26 
27 	*utc = (uint32_t)i64;
28 	return 0;
29 }
30 
31 #if CONFIG_GNSS_SATELLITES
gnss_nmea0183_match_reset_gsv(struct gnss_nmea0183_match_data * data)32 static void gnss_nmea0183_match_reset_gsv(struct gnss_nmea0183_match_data *data)
33 {
34 	data->satellites_length = 0;
35 	data->gsv_message_number = 1;
36 }
37 #endif
38 
gnss_nmea0183_match_publish(struct gnss_nmea0183_match_data * data)39 static void gnss_nmea0183_match_publish(struct gnss_nmea0183_match_data *data)
40 {
41 	if ((data->gga_utc == 0) || (data->rmc_utc == 0)) {
42 		return;
43 	}
44 
45 	if (data->gga_utc == data->rmc_utc) {
46 		gnss_publish_data(data->gnss, &data->data);
47 	}
48 }
49 
gnss_nmea0183_match_gga_callback(struct modem_chat * chat,char ** argv,uint16_t argc,void * user_data)50 void gnss_nmea0183_match_gga_callback(struct modem_chat *chat, char **argv, uint16_t argc,
51 				      void *user_data)
52 {
53 	struct gnss_nmea0183_match_data *data = user_data;
54 
55 	if (gnss_nmea0183_parse_gga((const char **)argv, argc, &data->data) < 0) {
56 		return;
57 	}
58 
59 	if (gnss_nmea0183_match_parse_utc(argv, argc, &data->gga_utc) < 0) {
60 		return;
61 	}
62 
63 	gnss_nmea0183_match_publish(data);
64 }
65 
gnss_nmea0183_match_rmc_callback(struct modem_chat * chat,char ** argv,uint16_t argc,void * user_data)66 void gnss_nmea0183_match_rmc_callback(struct modem_chat *chat, char **argv, uint16_t argc,
67 				      void *user_data)
68 {
69 	struct gnss_nmea0183_match_data *data = user_data;
70 
71 	if (gnss_nmea0183_parse_rmc((const char **)argv, argc, &data->data) < 0) {
72 		return;
73 	}
74 
75 	if (gnss_nmea0183_match_parse_utc(argv, argc, &data->rmc_utc) < 0) {
76 		return;
77 	}
78 
79 	gnss_nmea0183_match_publish(data);
80 }
81 
82 #if CONFIG_GNSS_SATELLITES
gnss_nmea0183_match_gsv_callback(struct modem_chat * chat,char ** argv,uint16_t argc,void * user_data)83 void gnss_nmea0183_match_gsv_callback(struct modem_chat *chat, char **argv, uint16_t argc,
84 				      void *user_data)
85 {
86 	struct gnss_nmea0183_match_data *data = user_data;
87 	struct gnss_nmea0183_gsv_header header;
88 	int ret;
89 
90 	if (gnss_nmea0183_parse_gsv_header((const char **)argv, argc, &header) < 0) {
91 		return;
92 	}
93 
94 	if (header.number_of_svs == 0) {
95 		return;
96 	}
97 
98 	if (header.message_number != data->gsv_message_number) {
99 		gnss_nmea0183_match_reset_gsv(data);
100 		return;
101 	}
102 
103 	data->gsv_message_number++;
104 
105 	ret = gnss_nmea0183_parse_gsv_svs((const char **)argv, argc,
106 					  &data->satellites[data->satellites_length],
107 					  data->satellites_size - data->satellites_length);
108 	if (ret < 0) {
109 		gnss_nmea0183_match_reset_gsv(data);
110 		return;
111 	}
112 
113 	data->satellites_length += (uint16_t)ret;
114 
115 	if (data->satellites_length == header.number_of_svs) {
116 		gnss_publish_satellites(data->gnss, data->satellites, data->satellites_length);
117 		gnss_nmea0183_match_reset_gsv(data);
118 	}
119 }
120 #endif
121 
gnss_nmea0183_match_init(struct gnss_nmea0183_match_data * data,const struct gnss_nmea0183_match_config * config)122 int gnss_nmea0183_match_init(struct gnss_nmea0183_match_data *data,
123 			     const struct gnss_nmea0183_match_config *config)
124 {
125 	__ASSERT(data != NULL, "data argument must be provided");
126 	__ASSERT(config != NULL, "config argument must be provided");
127 
128 	memset(data, 0, sizeof(struct gnss_nmea0183_match_data));
129 	data->gnss = config->gnss;
130 #if CONFIG_GNSS_SATELLITES
131 	data->satellites = config->satellites;
132 	data->satellites_size = config->satellites_size;
133 #endif
134 	return 0;
135 }
136