4 * Copyright (c) 2011-2013 Samsung Electronics Co., Ltd. All rights reserved.
6 * Contact: Youngae Kang <youngae.kang@samsung.com>, Minjune Kim <sena06.kim@samsung.com>
7 * Genie Kim <daejins.kim@samsung.com>
9 * Licensed under the Apache License, Version 2.0 (the "License");
10 * you may not use this file except in compliance with the License.
11 * You may obtain a copy of the License at
13 * http://www.apache.org/licenses/LICENSE-2.0
15 * Unless required by applicable law or agreed to in writing, software
16 * distributed under the License is distributed on an "AS IS" BASIS,
17 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18 * See the License for the specific language governing permissions and
19 * limitations under the License.
26 #include <gps_plugin_intf.h>
28 #include "gps_plugin_debug.h"
29 #include "nmea_parser.h"
32 #define MAX_NMEA_SENTENCES 32
35 #define DECIMAL_TO_DEGREE 60.0
36 #define METER_TO_FEET 3.2808399
37 #define KNOT_TO_MPS 0.5144444
38 #define KMPH_TO_MPS 0.2777778
45 int used_sat[MAX_GPS_NUM_SAT_USED] = { 0, };
47 static unsigned char nmea_parser_c2n(unsigned char ch)
52 return (ch - 'A') + 10;
55 int nmea_parser_verify_checksum(char *nmea_sen)
62 for (i = 0; i < strlen(nmea_sen) && (nmea_sen[i] != '*'); i++)
63 checksum ^= nmea_sen[i];
65 if (++i + 1 < strlen(nmea_sen))
66 sum = (nmea_parser_c2n(nmea_sen[i]) << 4) + nmea_parser_c2n(nmea_sen[i + 1]);
68 if (sum == checksum) {
71 LOG_PLUGIN(DBG_LOW, "NMEA checksum is INVALID");
77 int nmea_parser_tokenize(char input[], char *token[])
83 token[num_tokens] = s;
86 /* LOG_PLUGIN(DBG_LOW, "input:%s \n", input); */
88 while ((*s != 0) && (num_tokens < MAX_TOEKNS)) {
97 token[num_tokens++] = s;
110 static double nmea_parser_get_latitude(const char *lat, const char *bearing)
112 double latitude = 0.0;
117 if ((*lat == 0) || (*bearing == 0))
120 ns = (*bearing == 'N') ? NORTH : SOUTH;
122 latitude = atof(lat);
123 deg = (int)(latitude / 100.0);
124 remainder = latitude - (deg * 100.0);
125 latitude = (deg + (remainder / DECIMAL_TO_DEGREE)) * ns;
130 static double nmea_parser_get_longitude(const char *lon, const char *bearing)
132 double longitude = 0.0;
137 if (*lon == 0 || (*bearing == 0))
140 ew = (*bearing == 'E') ? EAST : WEST;
142 longitude = atof(lon);
143 deg = (int)(longitude / 100.0);
144 remainder = longitude - (deg * 100.0);
145 longitude = (deg + (remainder / DECIMAL_TO_DEGREE)) * ew;
150 static double nmea_parser_get_altitude(const char *alt, const char *unit)
157 altitude = atof(alt);
158 altitude = (*unit == 'M') ? altitude : altitude * METER_TO_FEET;
163 static int nmea_parser_gpgga(char *token[], pos_data_t *pos, sv_data_t *sv)
165 double latitude, longitude, altitude;
168 quality = atoi(token[6]);
171 LOG_PLUGIN(DBG_LOW, "Not fixed");
172 sv->pos_valid = FALSE;
173 return READ_NOT_FIXED;
176 /* utctime = atoi(token[1]); */
177 latitude = nmea_parser_get_latitude(token[2], token[3]);
178 longitude = nmea_parser_get_longitude(token[4], token[5]);
179 altitude = nmea_parser_get_altitude(token[9], token[10]);
180 /* num_of_sat_used = atoi(token[7]); */
181 /* eph = atof(token[8]); */
182 /* geoid = nmea_parser_get_altitude(token[11], token[12]); */
184 pos->latitude = latitude;
185 pos->longitude = longitude;
186 pos->altitude = altitude;
188 sv->pos_valid = TRUE;
193 static int nmea_parser_gprmc(char *token[], pos_data_t *pos)
196 double latitude, longitude, speed, bearing;
198 status = token[2]; /*warn = *token[2]; */
199 if (strcmp(status, "V") == 0) {
200 /* LOG_PLUGIN(DBG_LOW, "Not fixed"); */
201 return READ_NOT_FIXED;
204 /* utctime = atoi(token[1]); */
205 latitude = nmea_parser_get_latitude(token[3], token[4]);
206 longitude = nmea_parser_get_longitude(token[5], token[6]);
207 speed = atof(token[7]);
208 bearing = atof(token[8]);
209 /* date = atoi(token[9]); */
210 /* magvar = atof(token[10]); */
212 pos->latitude = latitude;
213 pos->longitude = longitude;
214 pos->speed = speed * KNOT_TO_MPS;
215 pos->bearing = bearing;
220 static int nmea_parser_gpgll(char *token[], pos_data_t *pos)
223 double latitude, longitude;
225 status = token[6]; /*warn = *token[2]; */
226 if (strcmp(status, "V") == 0) {
227 /* LOG_PLUGIN(DBG_LOW, "Not fixed"); */
228 return READ_NOT_FIXED;
231 latitude = nmea_parser_get_latitude(token[1], token[2]);
232 longitude = nmea_parser_get_longitude(token[3], token[4]);
234 pos->latitude = latitude;
235 pos->longitude = longitude;
240 static int nmea_parser_gpgsa(char *token[], pos_data_t *pos)
244 fix_type = atoi(token[2]);
246 /* LOG_PLUGIN(DBG_LOW, "Not fixed"); */
247 return READ_NOT_FIXED;
250 /* selection_type = *token[1]; */
252 memset(used_sat, 0, sizeof(used_sat));
253 for (i = 0; i < MAX_GPS_NUM_SAT_USED; i++)
254 used_sat[i] = atoi(token[i + 3]);
257 /* pdop = atof(token[15]); */
258 /* hdop = atof(token[16]); */
259 /* vdop = atof(token[17]); */
264 static int nmea_parser_gpvtg(char *token[], pos_data_t *pos)
266 double true_course, kmh_speed;
268 true_course = atof(token[1]);
269 /* magnetic_course = atof(token[3]); */
270 /* knot_speed = atof(token[5]); */
271 kmh_speed = atof(token[7]);
273 pos->speed = kmh_speed * KMPH_TO_MPS;
274 pos->bearing = true_course;
279 static int nmea_parser_gpgsv(char *token[], sv_data_t *sv)
285 /* num_sen = atoi(token[1]); */
286 msg_num = atoi(token[2]);
288 LOG_PLUGIN(DBG_LOW, "There is not GSV message");
292 num_sv = atoi(token[3]);
293 if (num_sv > MAX_GPS_NUM_SAT_IN_VIEW) {
294 LOG_PLUGIN(DBG_LOW, "num_of_sat(num_sv) size error");
298 sv->num_of_sat = num_sv;
299 iter = ((num_sv < (msg_num * 4)) ? (num_sv - ((msg_num - 1) * 4)) : 4);
300 for (i = 0; i < iter; i++) {
302 p = i + 4 * (msg_num - 1);
304 LOG_PLUGIN(DBG_LOW, "Out of bounds");
307 sv->sat[p].prn = atoi(token[q]);
308 for (j = 0; j < MAX_GPS_NUM_SAT_USED; j++) {
309 if (sv->sat[p].prn == used_sat[j]) {
316 sv->sat[p].elevation = atoi(token[q + 1]);
317 sv->sat[p].azimuth = atoi(token[q + 2]);
318 sv->sat[p].snr = atoi(token[q + 3]);
323 int nmea_parser_sentence(char *sentence, char *token[], pos_data_t *pos, sv_data_t *sv)
325 int ret = READ_SUCCESS;
326 if (strcmp(sentence, "GPGGA") == 0)
327 ret = nmea_parser_gpgga(token, pos, sv);
328 else if (strcmp(sentence, "GPRMC") == 0)
329 ret = nmea_parser_gprmc(token, pos);
330 else if (strcmp(sentence, "GPGLL") == 0)
331 ret = nmea_parser_gpgll(token, pos);
332 else if (strcmp(sentence, "GPGSA") == 0)
333 ret = nmea_parser_gpgsa(token, pos);
334 else if (strcmp(sentence, "GPVTG") == 0)
335 ret = nmea_parser_gpvtg(token, pos);
336 else if (strcmp(sentence, "GPGSV") == 0)
337 ret = nmea_parser_gpgsv(token, sv);
339 LOG_PLUGIN(DBG_LOW, "Unsupported sentence : [%s]\n", sentence);
345 int nmea_parser(char *data, pos_data_t *pos, sv_data_t *sv)
347 int ret = READ_SUCCESS;
352 char *nmea_sen[MAX_NMEA_SENTENCES] = { 0, };
353 char *token[MAX_TOEKNS] = { 0, };
355 nmea_sen[num_sen] = (char *)strtok_r((char *)data, "$", &last);
356 while (nmea_sen[num_sen] != NULL) {
358 nmea_sen[num_sen] = (char *)strtok_r(NULL, "$", &last);
360 /* LOG_PLUGIN(DBG_LOW, "Number of NMEA sentences:%d \n", num_sen); */
362 while (num_sen > 0) {
363 if (nmea_parser_verify_checksum(nmea_sen[count]) == 0) {
364 nmea_parser_tokenize(nmea_sen[count], token);
365 err = nmea_parser_sentence(token[0], token, pos, sv);
366 if (err == READ_NOT_FIXED) {
367 /* LOG_PLUGIN(DBG_LOW, "NOT Fixed"); */
369 } else if (err == READ_ERROR) {
373 LOG_PLUGIN(DBG_ERR, "[NMEA Parser] %dth sentense : Invalid Checksum\n", count);