int gps_unpack(char *buf, struct gps_data_t *gpsdata) /* unpack a gpsd response into a status structure, buf must be writeable. * gps_unpack() currently returns 0 in all cases, but should it ever need to * return an error status, it must be < 0. */ { libgps_debug_trace((DEBUG_CALLS, "gps_unpack(%s)\n", buf)); /* detect and process a JSON response */ if (buf[0] == '{') { const char *jp = buf, **next = &jp; while (next != NULL && *next != NULL && next[0][0] != '\0') { libgps_debug_trace((DEBUG_CALLS,"gps_unpack() segment parse '%s'\n", *next)); if (libgps_json_unpack(*next, gpsdata, next) == -1) break; #ifdef LIBGPS_DEBUG if (libgps_debuglevel >= 1) libgps_dump_state(gpsdata); #endif /* LIBGPS_DEBUG */ } } #ifndef USE_QT libgps_debug_trace((DEBUG_CALLS, "final flags: (0x%04x) %s\n", gpsdata->set,gps_maskdump(gpsdata->set))); #endif return 0; }
int main(int argc, char *argv[]) { struct gps_data_t collect; char buf[BUFSIZ]; int option; bool batchmode = false; int debug = 0; (void)signal(SIGSEGV, onsig); (void)signal(SIGBUS, onsig); while ((option = getopt(argc, argv, "bhsD:?")) != -1) { switch (option) { case 'b': batchmode = true; break; case 's': (void) printf ("Sizes: fix=%zd gpsdata=%zd rtcm2=%zd rtcm3=%zd ais=%zd compass=%zd raw=%zd devices=%zd policy=%zd version=%zd, noise=%zd\n", sizeof(struct gps_fix_t), sizeof(struct gps_data_t), sizeof(struct rtcm2_t), sizeof(struct rtcm3_t), sizeof(struct ais_t), sizeof(struct attitude_t), sizeof(struct rawdata_t), sizeof(collect.devices), sizeof(struct policy_t), sizeof(struct version_t), sizeof(struct gst_t)); exit(EXIT_SUCCESS); case 'D': debug = atoi(optarg); break; case '?': case 'h': default: (void)fputs("usage: test_libgps [-b] [-D lvl] [-s]\n", stderr); exit(EXIT_FAILURE); } } gps_enable_debug(debug, stdout); if (batchmode) { while (fgets(buf, sizeof(buf), stdin) != NULL) { if (buf[0] == '{' || isalpha(buf[0])) { gps_unpack(buf, &gpsdata); libgps_dump_state(&gpsdata); } } } else if (gps_open(NULL, 0, &collect) <= 0) { (void)fputs("Daemon is not running.\n", stdout); exit(EXIT_FAILURE); } else if (optind < argc) { (void)strlcpy(buf, argv[optind], BUFSIZ); (void)strlcat(buf, "\n", BUFSIZ); (void)gps_send(&collect, buf); (void)gps_read(&collect); libgps_dump_state(&collect); (void)gps_close(&collect); } else { int tty = isatty(0); if (tty) (void)fputs("This is the gpsd exerciser.\n", stdout); for (;;) { if (tty) (void)fputs("> ", stdout); if (fgets(buf, sizeof(buf), stdin) == NULL) { if (tty) putchar('\n'); break; } collect.set = 0; (void)gps_send(&collect, buf); (void)gps_read(&collect); libgps_dump_state(&collect); } (void)gps_close(&collect); } return 0; }
int main(int argc, char *argv[]) { struct gps_data_t collect; struct fixsource_t source; char buf[BUFSIZ]; int option; bool batchmode = false; bool forwardmode = false; char *fmsg = NULL; #ifdef CLIENTDEBUG_ENABLE int debug = 0; #endif (void)signal(SIGSEGV, onsig); (void)signal(SIGBUS, onsig); while ((option = getopt(argc, argv, "bf:hsD:?")) != -1) { switch (option) { case 'b': batchmode = true; break; case 'f': forwardmode = true; fmsg = optarg; break; case 's': (void) printf ("Sizes: fix=%zd gpsdata=%zd rtcm2=%zd rtcm3=%zd ais=%zd compass=%zd raw=%zd devices=%zd policy=%zd version=%zd, noise=%zd\n", sizeof(struct gps_fix_t), sizeof(struct gps_data_t), sizeof(struct rtcm2_t), sizeof(struct rtcm3_t), sizeof(struct ais_t), sizeof(struct attitude_t), sizeof(struct rawdata_t), sizeof(collect.devices), sizeof(struct policy_t), sizeof(struct version_t), sizeof(struct gst_t)); exit(EXIT_SUCCESS); #ifdef CLIENTDEBUG_ENABLE case 'D': debug = atoi(optarg); break; #endif case '?': case 'h': default: (void)fputs("usage: test_libgps [-b] [-f fwdmsg] [-D lvl] [-s] [server[:port:[device]]]\n", stderr); exit(EXIT_FAILURE); } } /* Grok the server, port, and device. */ if (optind < argc) { gpsd_source_spec(argv[optind], &source); } else gpsd_source_spec(NULL, &source); #ifdef CLIENTDEBUG_ENABLE gps_enable_debug(debug, stdout); #endif if (batchmode) { #ifdef SOCKET_EXPORT_ENABLE while (fgets(buf, sizeof(buf), stdin) != NULL) { if (buf[0] == '{' || isalpha(buf[0])) { gps_unpack(buf, &gpsdata); libgps_dump_state(&gpsdata); } } #endif } else if (gps_open(source.server, source.port, &collect) != 0) { (void)fprintf(stderr, "test_libgps: no gpsd running or network error: %d, %s\n", errno, gps_errstr(errno)); exit(EXIT_FAILURE); } else if (forwardmode) { (void)gps_send(&collect, fmsg); (void)gps_read(&collect); #ifdef SOCKET_EXPORT_ENABLE libgps_dump_state(&collect); #endif (void)gps_close(&collect); } else { int tty = isatty(0); if (tty) (void)fputs("This is the gpsd exerciser.\n", stdout); for (;;) { if (tty) (void)fputs("> ", stdout); if (fgets(buf, sizeof(buf), stdin) == NULL) { if (tty) putchar('\n'); break; } collect.set = 0; (void)gps_send(&collect, buf); (void)gps_read(&collect); #ifdef SOCKET_EXPORT_ENABLE libgps_dump_state(&collect); #endif } (void)gps_close(&collect); } return 0; }
/*@ -branchstate -usereleased -mustfreefresh -nullstate -usedef @*/ int gps_unpack(char *buf, struct gps_data_t *gpsdata) /* unpack a gpsd response into a status structure, buf must be writeable. * gps_unpack() currently returns 0 in all cases, but should it ever need to * return an error status, it must be < 0. */ { libgps_debug_trace((DEBUG_CALLS, "gps_unpack(%s)\n", buf)); /* detect and process a JSON response */ if (buf[0] == '{') { const char *jp = buf, **next = &jp; while (next != NULL && *next != NULL && next[0][0] != '\0') { libgps_debug_trace((DEBUG_CALLS,"gps_unpack() segment parse '%s'\n", *next)); if (libgps_json_unpack(*next, gpsdata, next) == -1) break; #ifdef LIBGPS_DEBUG if (libgps_debuglevel >= 1) libgps_dump_state(gpsdata); #endif /* LIBGPS_DEBUG */ } #ifdef OLDSTYLE_ENABLE if (PRIVATE(gpsdata) != NULL) PRIVATE(gpsdata)->newstyle = true; #endif /* OLDSTYLE_ENABLE */ } #ifdef OLDSTYLE_ENABLE else { /* * Get the decimal separator for the current application locale. * This looks thread-unsafe, but it's not. The key is that * character assignment is atomic. */ char *ns, *sp, *tp; static char decimal_point = '\0'; if (decimal_point == '\0') { struct lconv *locale_data = localeconv(); if (locale_data != NULL && locale_data->decimal_point[0] != '.') decimal_point = locale_data->decimal_point[0]; } for (ns = buf; ns; ns = strstr(ns + 1, "GPSD")) { if ( /*@i1@*/ strncmp(ns, "GPSD", 4) == 0) { bool eol = false; /* the following should execute each time we have a good next sp */ for (sp = ns + 5; *sp != '\0'; sp = tp + 1) { tp = sp + strcspn(sp, ",\r\n"); eol = *tp == '\r' || *tp == '\n'; if (*tp == '\0') tp--; else *tp = '\0'; /* * The daemon always emits the Anglo-American and SI * decimal point. Hack these into whatever the * application locale requires if it's not the same. * This has to happen *after* we grab the next * comma-delimited response, or we'll lose horribly * in locales where the decimal separator is comma. */ if (decimal_point != '\0') { char *cp; for (cp = sp; cp < tp; cp++) if (*cp == '.') *cp = decimal_point; } /* note, there's a bit of skip logic after the switch */ switch (*sp) { case 'F': /*@ -mustfreeonly */ if (sp[2] == '?') gpsdata->dev.path[0] = '\0'; else { /*@ -mayaliasunique @*/ (void)strlcpy(gpsdata->dev.path, sp + 2, sizeof(gpsdata->dev.path)); /*@ +mayaliasunique @*/ gpsdata->set |= DEVICE_SET; } /*@ +mustfreeonly */ break; case 'I': /*@ -mustfreeonly */ if (sp[2] == '?') gpsdata->dev.subtype[0] = '\0'; else { (void)strlcpy(gpsdata->dev.subtype, sp + 2, sizeof(gpsdata->dev.subtype)); gpsdata->set |= DEVICEID_SET; } /*@ +mustfreeonly */ break; case 'O': if (sp[2] == '?') { gpsdata->set = MODE_SET | STATUS_SET; gpsdata->status = STATUS_NO_FIX; gps_clear_fix(&gpsdata->fix); } else { struct gps_fix_t nf; char tag[MAXTAGLEN + 1], alt[20]; char eph[20], epv[20], track[20], speed[20], climb[20]; char epd[20], eps[20], epc[20], mode[2]; char timestr[20], ept[20], lat[20], lon[20]; int st = sscanf(sp + 2, "%8s %19s %19s %19s %19s %19s %19s %19s %19s %19s %19s %19s %19s %19s %1s", tag, timestr, ept, lat, lon, alt, eph, epv, track, speed, climb, epd, eps, epc, mode); if (st >= 14) { #define DEFAULT(val) (val[0] == '?') ? NAN : atof(val) /*@ +floatdouble @*/ nf.time = DEFAULT(timestr); nf.latitude = DEFAULT(lat); nf.longitude = DEFAULT(lon); nf.ept = DEFAULT(ept); nf.altitude = DEFAULT(alt); /* designed before we split eph into epx+epy */ nf.epx = nf.epy = DEFAULT(eph) / sqrt(2); nf.epv = DEFAULT(epv); nf.track = DEFAULT(track); nf.speed = DEFAULT(speed); nf.climb = DEFAULT(climb); nf.epd = DEFAULT(epd); nf.eps = DEFAULT(eps); nf.epc = DEFAULT(epc); /*@ -floatdouble @*/ #undef DEFAULT if (st >= 15) nf.mode = (mode[0] == '?') ? MODE_NOT_SEEN : atoi(mode); else nf.mode = (alt[0] == '?') ? MODE_2D : MODE_3D; if (alt[0] != '?') gpsdata->set |= ALTITUDE_SET | CLIMB_SET; if (isnan(nf.epx) == 0 && isnan(nf.epy) == 0) gpsdata->set |= HERR_SET; if (isnan(nf.epv) == 0) gpsdata->set |= VERR_SET; if (isnan(nf.track) == 0) gpsdata->set |= TRACK_SET | SPEED_SET; if (isnan(nf.eps) == 0) gpsdata->set |= SPEEDERR_SET; if (isnan(nf.epc) == 0) gpsdata->set |= CLIMBERR_SET; gpsdata->fix = nf; (void)strlcpy(gpsdata->tag, tag, MAXTAGLEN + 1); gpsdata->set |= TIME_SET | TIMERR_SET | LATLON_SET | MODE_SET; gpsdata->status = STATUS_FIX; gpsdata->set |= STATUS_SET; } } break; case 'X': if (sp[2] == '?') gpsdata->online = (timestamp_t)-1; else { (void)sscanf(sp, "X=%lf", &gpsdata->online); gpsdata->set |= ONLINE_SET; } break; case 'Y': if (sp[2] == '?') { gpsdata->satellites_visible = 0; } else { int j, i1, i2, i3, i5; int PRN[MAXCHANNELS]; int elevation[MAXCHANNELS], azimuth[MAXCHANNELS]; int used[MAXCHANNELS]; double ss[MAXCHANNELS], f4; char tag[MAXTAGLEN + 1], timestamp[21]; (void)sscanf(sp, "Y=%8s %20s %d ", tag, timestamp, &gpsdata->satellites_visible); (void)strlcpy(gpsdata->tag, tag, MAXTAGLEN); if (timestamp[0] != '?') { gpsdata->set |= TIME_SET; } for (j = 0; j < gpsdata->satellites_visible; j++) { PRN[j] = elevation[j] = azimuth[j] = used[j] = 0; ss[j] = 0.0; } for (j = 0, gpsdata->satellites_used = 0; j < gpsdata->satellites_visible; j++) { if ((sp != NULL) && ((sp = strchr(sp, ':')) != NULL)) { sp++; (void)sscanf(sp, "%d %d %d %lf %d", &i1, &i2, &i3, &f4, &i5); PRN[j] = i1; elevation[j] = i2; azimuth[j] = i3; ss[j] = f4; used[j] = i5; if (i5 == 1) gpsdata->satellites_used++; } } /*@ -compdef @*/ memcpy(gpsdata->PRN, PRN, sizeof(PRN)); memcpy(gpsdata->elevation, elevation, sizeof(elevation)); memcpy(gpsdata->azimuth, azimuth, sizeof(azimuth)); memcpy(gpsdata->ss, ss, sizeof(ss)); memcpy(gpsdata->used, used, sizeof(used)); /*@ +compdef @*/ } gpsdata->set |= SATELLITE_SET; break; } #ifdef LIBGPS_DEBUG if (libgps_debuglevel >= 1) libgps_dump_state(gpsdata); #endif /* LIBGPS_DEBUG */ /* * Skip to next GPSD when we see \r or \n; * we don't want to try interpreting stuff * in between that might be raw mode data. */ if (eol) break; } } } } #endif /* OLDSTYLE_ENABLE */ #ifndef USE_QT libgps_debug_trace((DEBUG_CALLS, "final flags: (0x%04x) %s\n", gpsdata->set,gps_maskdump(gpsdata->set))); #endif return 0; }