libgps.c
来自「gpsd, a popular GPS daemon.」· C语言 代码 · 共 712 行 · 第 1/2 页
C
712 行
/* $Id: libgps.c 4377 2007-06-02 14:52:38Z esr $ *//* libgps.c -- client interface library for the gpsd daemon */#include <sys/time.h>#include <stdio.h>#include <unistd.h>#include <stdlib.h>#include <string.h>#include <errno.h>#include <stdarg.h>#ifndef S_SPLINT_S#include <pthread.h> /* pacifies OpenBSD's compiler */#endif#include <math.h>#include "gpsd_config.h"#include "gpsd.h"#ifdef HAVE_SETLOCALE#include <locale.h>#endif#ifdef S_SPLINT_Sextern char *strtok_r(char *, const char *, char **);#endif /* S_SPLINT_S *//* convert double degrees to a static string and return a pointer to it * * deg_str_type: * deg_dd : return DD.dddddd * deg_ddmm : return DD MM.mmmm' * deg_ddmmss : return DD MM' SS.sss" * *//*@observer@*/char *deg_to_str( enum deg_str_type type, double f) { static char str[40]; int dsec, sec, deg, min; long frac_deg; double fdsec, fsec, fdeg, fmin; if ( f < 0 || f > 360 ) { (void)strlcpy( str, "nan", 40); return str; } fmin = modf( f, &fdeg); deg = (int)fdeg; frac_deg = (long)(fmin * 1000000); if ( deg_dd == type ) { /* DD.dddddd */ (void)snprintf(str, sizeof(str), "%3d.%06ld", deg,frac_deg); return str; } fsec = modf( fmin * 60, &fmin); min = (int)fmin; sec = (int)(fsec * 10000.0); if ( deg_ddmm == type ) { /* DD MM.mmmm */ (void)snprintf(str,sizeof(str), "%3d %02d.%04d'", deg,min,sec); return str; } /* else DD MM SS.sss */ fdsec = modf( fsec * 60, &fsec); sec = (int)fsec; dsec = (int)(fdsec * 1000.0); (void)snprintf(str,sizeof(str), "%3d %02d' %02d.%03d\"", deg,min,sec,dsec); return str;}/* * check the environment to determine proper GPS units * * clients should only call this if no user preference is specified on * the command line or via X resources. * * return imperial - Use miles/feet * nautical - Use knots/feet * metric - Use km/meters * unspecified - use compiled default * * In order check these environment vars: * GPSD_UNITS one of: * imperial = miles/feet * nautical = knots/feet * metric = km/meters * LC_MEASUREMENT * en_US = miles/feet * C = miles/feet * POSIX = miles/feet * [other] = km/meters * LANG * en_US = miles/feet * C = miles/feet * POSIX = miles/feet * [other] = km/meters * * if none found then return compiled in default */enum unit gpsd_units(void){ char *envu = NULL;#ifdef HAVE_SETLOCALE (void)setlocale(LC_NUMERIC, "C");#endif if ((envu = getenv("GPSD_UNITS")) != NULL && *envu != '\0') { if (0 == strcasecmp(envu, "imperial")) { return imperial; } if (0 == strcasecmp(envu, "nautical")) { return nautical; } if (0 == strcasecmp(envu, "metric")) { return metric; } /* unrecognized, ignore it */ } if (((envu = getenv("LC_MEASUREMENT")) != NULL && *envu != '\0') || ((envu = getenv("LANG")) != NULL && *envu != '\0')) { if (strcasecmp(envu, "en_US")==0 || strcasecmp(envu, "C")==0 || strcasecmp(envu, "POSIX")==0) { return imperial; } /* Other, must be metric */ return metric; } /* TODO: allow a compile time default here */ return unspecified;}struct gps_data_t *gps_open(const char *host, const char *port)/* open a connection to a gpsd daemon */{ struct gps_data_t *gpsdata = (struct gps_data_t *)calloc(sizeof(struct gps_data_t), 1); /*@ -branchstate @*/ if (!gpsdata) return NULL; if (!host) host = "127.0.0.1"; if (!port) port = DEFAULT_GPSD_PORT; if ((gpsdata->gps_fd = netlib_connectsock(host, port, "tcp")) < 0) { errno = gpsdata->gps_fd; (void)free(gpsdata); return NULL; } gpsdata->status = STATUS_NO_FIX; gps_clear_fix(&gpsdata->fix); return gpsdata; /*@ +branchstate @*/}int gps_close(struct gps_data_t *gpsdata)/* close a gpsd connection */{ int retval = close(gpsdata->gps_fd); if (gpsdata->gps_id) { (void)free(gpsdata->gps_id); gpsdata->gps_id = NULL; } gpsdata->gps_device[0] = '\0'; if (gpsdata->devicelist) { int i; for (i = 0; i < gpsdata->ndevices; i++) /*@i1@*/(void)free(gpsdata->devicelist[i]); (void)free(gpsdata->devicelist); gpsdata->devicelist = NULL; gpsdata->ndevices = -1; } /*@i@*/(void)free(gpsdata); return retval;}void gps_set_raw_hook(struct gps_data_t *gpsdata, void (*hook)(struct gps_data_t *, char *, size_t len, int level)){ gpsdata->raw_hook = hook;}/*@ -branchstate -usereleased @*/static void gps_unpack(char *buf, struct gps_data_t *gpsdata)/* unpack a daemon response into a status structure */{ char *ns, *sp, *tp; int i; for (ns = buf; ns; ns = strstr(ns+1, "GPSD")) { if (/*@i1@*/strncmp(ns, "GPSD", 4) == 0) { /* 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"); if (*tp == '\0') tp--; else *tp = '\0'; switch (*sp) { case 'A': if (sp[2] == '?') { gpsdata->fix.altitude = NAN; } else { (void)sscanf(sp, "A=%lf", &gpsdata->fix.altitude); gpsdata->set |= ALTITUDE_SET; } break; case 'B': if (sp[2] == '?') { gpsdata->baudrate = gpsdata->stopbits = 0; } else (void)sscanf(sp, "B=%u %*d %*s %u", &gpsdata->baudrate, &gpsdata->stopbits); break; case 'C': if (sp[2] == '?') gpsdata->mincycle = gpsdata->cycle = 0; else { if (sscanf(sp, "C=%lf %lf", &gpsdata->cycle, &gpsdata->mincycle) < 2) gpsdata->mincycle = gpsdata->cycle; } break; case 'D': if (sp[2] == '?') gpsdata->fix.time = NAN; else { gpsdata->fix.time = iso8601_to_unix(sp+2); gpsdata->set |= TIME_SET; } break; case 'E': gpsdata->epe = gpsdata->fix.eph = gpsdata->fix.epv = NAN; /* epe should always be present if eph or epv is */ if (sp[2] != '?') { char epe[20], eph[20], epv[20]; (void)sscanf(sp, "E=%s %s %s", epe, eph, epv);#define DEFAULT(val) (val[0] == '?') ? NAN : atof(val) /*@ +floatdouble @*/ gpsdata->epe = DEFAULT(epe); gpsdata->fix.eph = DEFAULT(eph); gpsdata->fix.epv = DEFAULT(epv); /*@ -floatdouble @*/#undef DEFAULT } break; case 'F': /*@ -mustfreeonly */ if (sp[2] == '?') gpsdata->gps_device[0] = '\0'; else { /*@ -mayaliasunique @*/ strncpy(gpsdata->gps_device, sp+2, PATH_MAX); /*@ +mayaliasunique @*/ gpsdata->set |= DEVICE_SET; } /*@ +mustfreeonly */ break; case 'I': /*@ -mustfreeonly */ if (gpsdata->gps_id) free(gpsdata->gps_id); if (sp[2] == '?') gpsdata->gps_id = NULL; else { gpsdata->gps_id = strdup(sp+2); gpsdata->set |= DEVICEID_SET; } /*@ +mustfreeonly */ break; case 'K': if (gpsdata->devicelist) { for (i = 0; i < gpsdata->ndevices; i++) /*@i1@*/(void)free(gpsdata->devicelist[i]); (void)free(gpsdata->devicelist); gpsdata->devicelist = NULL; gpsdata->ndevices = -1; gpsdata->set |= DEVICELIST_SET; } if (sp[2] != '?') { /*@ -nullderef @*/ gpsdata->ndevices = (int)strtol(sp+2, &sp, 10); gpsdata->devicelist = (char **)calloc( (size_t)gpsdata->ndevices, sizeof(char **)); /*@ -nullstate -mustfreefresh @*/ gpsdata->devicelist[i=0] = strdup(strtok_r(sp+1, " \r\n", &ns)); while ((sp = strtok_r(NULL, " \r\n", &ns))) gpsdata->devicelist[++i] = strdup(sp); /*@ +nullstate +mustfreefresh @*/ /*@ +nullderef @*/ gpsdata->set |= DEVICELIST_SET; } break; case 'M': if (sp[2] == '?') { gpsdata->fix.mode = MODE_NOT_SEEN; } else { gpsdata->fix.mode = atoi(sp+2); gpsdata->set |= MODE_SET; } break; case 'N': if (sp[2] == '?') gpsdata->driver_mode = 0; else gpsdata->driver_mode = (unsigned)atoi(sp+2); 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); nf.eph = DEFAULT(eph); 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.eph)==0) gpsdata->set |= HERR_SET; if (isnan(nf.epv)==0) gpsdata->set |= VERR_SET;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?