pud: only check gpsd status; no clear of info on bad fix or invalid signal
[olsrd.git] / lib / pud / src / gpsdclient.c
1 /*
2  * The olsr.org Optimized Link-State Routing daemon (olsrd)
3  *
4  * (c) by the OLSR project
5  *
6  * See our Git repository to find out who worked on this file
7  * and thus is a copyright holder on it.
8  *
9  * All rights reserved.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  *
15  * * Redistributions of source code must retain the above copyright
16  *   notice, this list of conditions and the following disclaimer.
17  * * Redistributions in binary form must reproduce the above copyright
18  *   notice, this list of conditions and the following disclaimer in
19  *   the documentation and/or other materials provided with the
20  *   distribution.
21  * * Neither the name of olsr.org, olsrd nor the names of its
22  *   contributors may be used to endorse or promote products derived
23  *   from this software without specific prior written permission.
24  *
25  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
26  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
27  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
28  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
29  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
30  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
31  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
32  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
33  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
35  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36  * POSSIBILITY OF SUCH DAMAGE.
37  *
38  * Visit http://www.olsr.org for more information.
39  *
40  * If you find this software useful feel free to make a donation
41  * to the project. For more information see the website or contact
42  * the copyright holders.
43  *
44  */
45
46 #include "gpsdclient.h"
47
48 #include "configuration.h"
49
50 #include <nmealib/nmath.h>
51 #include <nmealib/sentence.h>
52 #include <errno.h>
53 #include <gps.h>
54 #include <math.h>
55 #include <string.h>
56 #include <syslog.h>
57
58 #if GPSD_API_MAJOR_VERSION < 6
59   #if GPSD_API_MINOR_VERSION < 1
60     #define GPSD_WHEEZY
61   #else
62     #define GPSD_JESSIE
63   #endif
64 #else
65   #define GPSD_NEW
66 #endif
67
68 /*
69  * Loggers
70  */
71
72 /* log gpsd log messages*/
73 static void gpsdLog(const char *s) {
74   syslog(LOG_INFO, "gpsd log: %s", s);
75 }
76
77 /* log gpsd errors */
78 static void gpsdError(const char *s) {
79   syslog(LOG_ERR, "gpsd error: %s", s);
80 }
81
82 /* standard parsing of a GPS data source spec */
83 void gpsdParseSourceSpec(char *arg, GpsDaemon *gpsDaemon) {
84   if (!arg //
85       || !gpsDaemon) {
86     return;
87   }
88
89   gpsDaemon->source.server = (char *) (unsigned long) DEFAULT_GPSD_HOST;
90   gpsDaemon->source.port = (char *) (unsigned long) DEFAULT_GPSD_PORT;
91   gpsDaemon->source.device = NULL;
92
93   if (*arg) {
94     char *colon1;
95     const char *skipto;
96     char *rbrk;
97
98     strncpy(gpsDaemon->source.spec, arg, PATH_MAX);
99     gpsDaemon->source.spec[PATH_MAX - 1] = '\0';
100
101     skipto = gpsDaemon->source.spec;
102     if ((*skipto == '[') //
103         && ((rbrk = strchr(skipto, ']')) != NULL )) {
104       skipto = rbrk;
105     }
106     colon1 = strchr(skipto, ':');
107
108     if (colon1 != NULL) {
109       char *colon2;
110
111       *colon1 = '\0';
112       if (colon1 != gpsDaemon->source.spec) {
113         gpsDaemon->source.server = gpsDaemon->source.spec;
114       }
115
116       gpsDaemon->source.port = colon1 + 1;
117       colon2 = strchr(gpsDaemon->source.port, ':');
118       if (colon2 != NULL) {
119         *colon2 = '\0';
120         gpsDaemon->source.device = colon2 + 1;
121       }
122     } else if (strchr(gpsDaemon->source.spec, '/') != NULL) {
123       gpsDaemon->source.device = gpsDaemon->source.spec;
124     } else {
125       gpsDaemon->source.server = gpsDaemon->source.spec;
126     }
127   }
128
129   if (*gpsDaemon->source.server == '[') {
130     char *rbrk = strchr(gpsDaemon->source.server, ']');
131     ++gpsDaemon->source.server;
132     if (rbrk != NULL) {
133       *rbrk = '\0';
134     }
135   }
136 }
137
138 bool gpsdConnect(GpsDaemon *gpsd, struct gps_data_t *gpsData, struct GpsdConnectionState *connectionTracking) {
139   bool disconnectFirst;
140
141   if (!gpsd //
142       || !gpsData //
143       || !connectionTracking) {
144     return false;
145   }
146
147   disconnectFirst = connectionTracking->connected;
148
149   if (disconnectFirst) {
150     gpsdDisconnect(gpsData, connectionTracking);
151   }
152
153   gpsData->gps_fd = -1;
154   if (gps_open(gpsd->source.server, gpsd->source.port, gpsData)) {
155     if (!connectionTracking->connectionFailureReported) {
156       syslog(LOG_WARNING, "%sonnecting to gpsd on %s:%s failed, starting retries", disconnectFirst ? "Rec" : "C", gpsd->source.server, gpsd->source.port);
157       connectionTracking->connectionFailureReported = true;
158     }
159     connectionTracking->retryCount++;
160     return false;
161   }
162
163   if (connectionTracking->connectionFailureReported) {
164     syslog(LOG_WARNING, "%sonnecting to gpsd on %s:%s successful after %llu retr%s", disconnectFirst ? "Rec" : "C", gpsd->source.server, gpsd->source.port,
165         connectionTracking->retryCount, connectionTracking->retryCount == 1 ? "y" : "ies");
166     connectionTracking->connectionFailureReported = false;
167   }
168   connectionTracking->retryCount = 0;
169
170   if (gpsd->source.device) {
171     gpsd->gpsdStreamFlags |= WATCH_DEVICE;
172   }
173
174   /* instruct gpsd which data to receive */
175   gps_stream(gpsData, gpsd->gpsdStreamFlags, gpsd->source.device);
176
177   return true;
178 }
179
180 void gpsdDisconnect(struct gps_data_t *gpsdata, struct GpsdConnectionState *connectionTracking) {
181   if (!gpsdata //
182       || !connectionTracking) {
183     return;
184   }
185
186   if (gpsdata->gps_fd >= 0) {
187     gps_close(gpsdata);
188     gpsdata->gps_fd = -1;
189     syslog(LOG_INFO, "Closed gpsd connection");
190   }
191
192   memset(connectionTracking, 0, sizeof(*connectionTracking));
193 }
194
195 /**
196  * Convert true heading to magnetic.  Taken from the Aviation
197  * Formulary v1.43.  Valid to within two degrees within the
198  * continiental USA except for the following airports: MO49 MO86 MO50
199  * 3K6 02K and KOOA.  AK correct to better than one degree.  Western
200  * Europe correct to within 0.2 deg.
201  *
202  * If you're not in one of these areas, I apologize, I don't have the
203  * math to compute your varation.  This is obviously extremely
204  * floating-point heavy, so embedded people, beware of using.
205  *
206  * Note that there are issues with using magnetic heading.  This code
207  * does not account for the possibility of travelling into or out of
208  * an area of valid calculation beyond forcing the magnetic conversion
209  * off.  A better way to communicate this to the user is probably
210  * desirable (in case the don't notice the subtle change from "(mag)"
211  * to "(true)" on their display).
212  */
213 float true2magnetic(double lat, double lon, double heading) {
214   /* Western Europe */
215   if ((lat > 36.0) && (lat < 68.0) && (lon > -10.0) && (lon < 28.0)) {
216     heading = (10.4768771667158 - (0.507385322418858 * lon) + (0.00753170031703826 * pow(lon, 2)) - (1.40596203924748e-05 * pow(lon, 3))
217         - (0.535560699962353 * lat) + (0.0154348808069955 * lat * lon) - (8.07756425110592e-05 * lat * pow(lon, 2)) + (0.00976887198864442 * pow(lat, 2))
218         - (0.000259163929798334 * lon * pow(lat, 2)) - (3.69056939266123e-05 * pow(lat, 3)) + heading);
219   }
220   /* USA */
221   else if ((lat > 24.0) && (lat < 50.0) && (lon > 66.0) && (lon < 125.0)) {
222     lon = 0.0 - lon;
223     heading = ((-65.6811) + (0.99 * lat) + (0.0128899 * pow(lat, 2)) - (0.0000905928 * pow(lat, 3)) + (2.87622 * lon) - (0.0116268 * lat * lon)
224         - (0.00000603925 * lon * pow(lat, 2)) - (0.0389806 * pow(lon, 2)) - (0.0000403488 * lat * pow(lon, 2)) + (0.000168556 * pow(lon, 3)) + heading);
225   }
226   /* AK */
227   else if ((lat > 54.0) && (lon > 130.0) && (lon < 172.0)) {
228     lon = 0.0 - lon;
229     heading = (618.854 + (2.76049 * lat) - (0.556206 * pow(lat, 2)) + (0.00251582 * pow(lat, 3)) - (12.7974 * lon) + (0.408161 * lat * lon)
230         + (0.000434097 * lon * pow(lat, 2)) - (0.00602173 * pow(lon, 2)) - (0.00144712 * lat * pow(lon, 2)) + (0.000222521 * pow(lon, 3)) + heading);
231   } else {
232     /* We don't know how to compute magnetic heading for this
233      * location. */
234     heading = NAN;
235   }
236
237   /* No negative headings. */
238   if (isnan(heading) == 0 && heading < 0.0) {
239     heading += 360.0;
240   }
241
242   return (float) (heading);
243 }
244
245 void nmeaInfoFromGpsd(struct gps_data_t *gpsdata, NmeaInfo *info, struct GpsdConnectionState *connectionTracking) {
246   if (!gpsdata //
247       || !info //
248       || !connectionTracking) {
249     return;
250   }
251
252   if (gpsdata->set & VERSION_SET) {
253     if (!connectionTracking->version) {
254       size_t releaseLength = strlen(gpsdata->version.release);
255       size_t revLength = strlen(gpsdata->version.rev);
256       size_t remoteLength = strlen(gpsdata->version.remote);
257       syslog(LOG_INFO, "Connected to gpsd%s%s%s%s%s%s on %s, protocol %d.%d", //
258           !releaseLength ? "" : " ", //
259           !releaseLength ? "" : gpsdata->version.release, //
260           !releaseLength ? "" : " ", //
261           !revLength ? "" : "(", //
262           !revLength ? "" : gpsdata->version.rev, //
263           !revLength ? "" : ")", //
264           !remoteLength ? "localhost" : gpsdata->version.remote, //
265           gpsdata->version.proto_major, //
266           gpsdata->version.proto_minor);
267
268       connectionTracking->version = true;
269     }
270
271     gpsdata->set &= ~VERSION_SET;
272   }
273
274   if (gpsdata->set & LOGMESSAGE_SET) {
275     gpsdLog(gpsdata->error);
276     gpsdata->set &= ~LOGMESSAGE_SET;
277   }
278
279   if (gpsdata->set & ERROR_SET) {
280     gpsdError(gpsdata->error);
281     gpsdata->set &= ~ERROR_SET;
282   }
283
284   if (gpsdata->set & (DEVICELIST_SET | DEVICE_SET | DEVICEID_SET)) {
285     int i = 0;
286     while (i < MAXUSERDEVS) {
287       struct devconfig_t *dev = &gpsdata->devices.list[i];
288       if (dev->flags //
289           && !connectionTracking->devSeen[i]) {
290         size_t subtypeLength = strlen(dev->subtype);
291         syslog(LOG_INFO, "Using %s device%s%s on %s in %s mode at %u baud (%u%c%u), refresh time %.3f (min. %.3f)", //
292             dev->driver, //
293             !subtypeLength ? "" : " ", //
294             !subtypeLength ? "" : dev->subtype, //
295             dev->path, //
296             dev->driver_mode ? "native" : "compatibility", //
297             dev->baudrate, //
298             8, //
299             dev->parity, //
300             dev->stopbits, //
301             dev->cycle, //
302             dev->mincycle);
303
304         connectionTracking->devSeen[i] = true;
305         connectionTracking->dev[i] = *dev;
306       } else if (connectionTracking->devSeen[i]) {
307         size_t subtypeLength;
308
309         dev = &connectionTracking->dev[i];
310         subtypeLength = strlen(dev->subtype);
311         syslog(LOG_INFO, "No longer using %s device%s%s on %s", //
312             dev->driver, //
313             !subtypeLength ? "" : " ", //
314             !subtypeLength ? "" : dev->subtype, //
315             dev->path);
316
317         connectionTracking->devSeen[i] = false;
318         memset(&connectionTracking->dev[i], 0, sizeof(connectionTracking->dev[i]));
319       }
320
321       i++;
322     }
323
324     gpsdata->set &= ~(DEVICELIST_SET | DEVICE_SET | DEVICEID_SET);
325   }
326
327   /* ignored */
328   gpsdata->set &= ~( //
329           ONLINE_SET // unreliable
330           | TIMERR_SET //
331           | CLIMB_SET //
332           | DOP_SET // using dop from fix
333           | ATTITUDE_SET //
334           | SPEEDERR_SET //
335           | TRACKERR_SET //
336           | CLIMBERR_SET //
337           | RTCM2_SET //
338           | RTCM3_SET //
339           | AIS_SET //
340           | PACKET_SET //
341           | SUBFRAME_SET //
342           | GST_SET //
343           | POLICY_SET //
344 #ifdef GPSD_JESSIE
345           | TIMEDRIFT_SET //
346           | EOF_SET //
347 #endif
348 #ifdef GPSD_NEW
349           | TOFF_SET //
350           | PPS_SET //
351           | NAVDATA_SET //
352 #endif
353           );
354
355   gpsdata->set &= ~STATUS_SET; /* always valid */
356   if (gpsdata->status == STATUS_NO_FIX) {
357     nmeaInfoClear(info);
358     nmeaTimeSet(&info->utc, &info->present, NULL);
359     return;
360   }
361
362   if (!gpsdata->set) {
363     return;
364   }
365
366   info->smask = NMEALIB_SENTENCE_MASK;
367   nmeaInfoSetPresent(&info->present, NMEALIB_PRESENT_SMASK);
368
369   /* date & time */
370   if (!isNaN(gpsdata->fix.time)) {
371     double seconds;
372     double fraction = modf(fabs(gpsdata->fix.time), &seconds);
373     long sec = lrint(seconds);
374     struct tm *time = gmtime(&sec);
375     if (time) {
376       info->utc.year = (unsigned int) time->tm_year + 1900;
377       info->utc.mon = (unsigned int) time->tm_mon + 1;
378       info->utc.day = (unsigned int) time->tm_mday;
379       info->utc.hour = (unsigned int) time->tm_hour;
380       info->utc.min = (unsigned int) time->tm_min;
381       info->utc.sec = (unsigned int) time->tm_sec;
382       info->utc.hsec = (unsigned int) lrint(fraction * 100);
383
384       nmeaInfoSetPresent(&info->present, NMEALIB_PRESENT_UTCDATE | NMEALIB_PRESENT_UTCTIME);
385     }
386   }
387   gpsdata->set &= ~TIME_SET;
388
389   /* sig & fix */
390   if (!gpsdata->online) {
391     gpsdata->fix.mode = MODE_NO_FIX;
392   }
393
394   switch (gpsdata->fix.mode) {
395     case MODE_3D:
396       info->fix = NMEALIB_FIX_3D;
397       info->sig = NMEALIB_SIG_FIX;
398       break;
399
400     case MODE_2D:
401       info->fix = NMEALIB_FIX_2D;
402       info->sig = NMEALIB_SIG_FIX;
403       break;
404
405     case MODE_NOT_SEEN:
406     case MODE_NO_FIX:
407     default:
408       info->fix = NMEALIB_FIX_BAD;
409       info->sig = NMEALIB_SIG_INVALID;
410       break;
411   }
412   nmeaInfoSetPresent(&info->present, NMEALIB_PRESENT_FIX | NMEALIB_PRESENT_SIG);
413   gpsdata->set &= ~MODE_SET;
414
415   /* hdop */
416   if (!isNaN(gpsdata->fix.epx) //
417       && !isNaN(gpsdata->fix.epy)) {
418     info->hdop = nmeaMathPdopCalculate(gpsdata->fix.epx, gpsdata->fix.epy);
419     nmeaInfoSetPresent(&info->present, NMEALIB_PRESENT_HDOP);
420   }
421   gpsdata->set &= ~HERR_SET;
422
423   /* vdop */
424   if (!isNaN(gpsdata->fix.epv)) {
425     info->vdop = gpsdata->fix.epv;
426     nmeaInfoSetPresent(&info->present, NMEALIB_PRESENT_VDOP);
427   }
428   gpsdata->set &= ~VERR_SET;
429
430   /* pdop */
431   if (nmeaInfoIsPresentAll(info->present, NMEALIB_PRESENT_HDOP | NMEALIB_PRESENT_VDOP)) {
432     info->pdop = nmeaMathPdopCalculate(info->hdop, info->vdop);
433     nmeaInfoSetPresent(&info->present, NMEALIB_PRESENT_PDOP);
434   }
435
436   /* lat */
437   if ((gpsdata->fix.mode >= MODE_2D) //
438       && !isNaN(gpsdata->fix.latitude)) {
439     info->latitude = nmeaMathDegreeToNdeg(gpsdata->fix.latitude);
440     nmeaInfoSetPresent(&info->present, NMEALIB_PRESENT_LAT);
441   }
442
443   /* lon */
444   if ((gpsdata->fix.mode >= MODE_2D) //
445       && !isNaN(gpsdata->fix.longitude)) {
446     info->longitude = nmeaMathDegreeToNdeg(gpsdata->fix.longitude);
447     nmeaInfoSetPresent(&info->present, NMEALIB_PRESENT_LON);
448   }
449
450   /* lat & lon */
451   gpsdata->set &= ~LATLON_SET;
452
453   /* elv */
454   if ((gpsdata->fix.mode >= MODE_3D) //
455       && !isNaN(gpsdata->fix.altitude)) {
456     info->elevation = gpsdata->fix.altitude;
457     info->height = gpsdata->separation;
458     nmeaInfoSetPresent(&info->present, NMEALIB_PRESENT_ELV | NMEALIB_PRESENT_HEIGHT);
459   }
460   gpsdata->set &= ~ALTITUDE_SET;
461
462   /* speed */
463   if ((gpsdata->fix.mode >= MODE_2D) //
464       && !isNaN(gpsdata->fix.speed)) {
465     info->speed = gpsdata->fix.speed * MPS_TO_KPH;
466     nmeaInfoSetPresent(&info->present, NMEALIB_PRESENT_SPEED);
467   }
468   gpsdata->set &= ~SPEED_SET;
469
470   /* track & mtrack */
471   if ((gpsdata->fix.mode >= MODE_2D) //
472       && !isNaN(gpsdata->fix.track)) {
473     double magheading;
474
475     info->track = gpsdata->fix.track;
476     nmeaInfoSetPresent(&info->present, NMEALIB_PRESENT_TRACK);
477
478     magheading = true2magnetic(gpsdata->fix.latitude, gpsdata->fix.longitude, gpsdata->fix.track);
479     if (!isNaN(magheading)) {
480       info->mtrack = magheading;
481       nmeaInfoSetPresent(&info->present, NMEALIB_PRESENT_MTRACK);
482     }
483   }
484   gpsdata->set &= ~TRACK_SET;
485
486   /* magvar: not available */
487
488   /* satellites */
489
490   info->satellites.inUseCount = 0;
491   memset(&info->satellites.inUse, 0, sizeof(info->satellites.inUse));
492   info->satellites.inViewCount = 0;
493   memset(&info->satellites.inView, 0, sizeof(info->satellites.inView));
494
495   if (gpsdata->satellites_visible > 0) {
496     int iGpsd;
497
498 #ifndef GPSD_NEW
499     bool usedFlags[MAXCHANNELS];
500
501     memset(usedFlags, 0, sizeof(usedFlags));
502
503     /* build a bitmap of which satellites are used */
504     for (iGpsd = 0; iGpsd < MAXCHANNELS; iGpsd++) {
505       size_t iGpsdUsed;
506       for (iGpsdUsed = 0; iGpsdUsed < (size_t) gpsdata->satellites_used; iGpsdUsed++) {
507         if (gpsdata->used[iGpsdUsed] == gpsdata->PRN[iGpsd]) {
508           usedFlags[iGpsd] = true;
509           iGpsdUsed = (size_t) gpsdata->satellites_used;
510         }
511       }
512     }
513 #endif
514
515     for (iGpsd = 0; //
516         (iGpsd < gpsdata->satellites_visible) && (iGpsd < MAXCHANNELS) && (iGpsd < (int) NMEALIB_MAX_SATELLITES); //
517         iGpsd++) {
518       NmeaSatellite *infoSatellite = &info->satellites.inView[iGpsd];
519       unsigned int prn;
520       int elevation;
521       unsigned int azimuth;
522       unsigned int snr;
523       bool inUse;
524
525 #ifndef GPSD_NEW
526       prn = (unsigned int) gpsdata->PRN[iGpsd];
527       elevation = gpsdata->elevation[iGpsd];
528       azimuth = (unsigned int) gpsdata->azimuth[iGpsd];
529       snr = (unsigned int) lrint(gpsdata->ss[iGpsd]);
530       inUse = usedFlags[iGpsd];
531 #else
532       struct satellite_t *gpsdSatellite = &gpsdata->skyview[iGpsd];
533
534       prn = (unsigned int) gpsdSatellite->PRN;
535       elevation = gpsdSatellite->elevation;
536       azimuth = (unsigned int) gpsdSatellite->azimuth;
537       snr = (unsigned int) lrint(gpsdSatellite->ss);
538       inUse = gpsdSatellite->used;
539 #endif
540
541       infoSatellite->prn = prn;
542       infoSatellite->elevation = elevation;
543       infoSatellite->azimuth = azimuth;
544       infoSatellite->snr = snr;
545       info->satellites.inViewCount++;
546
547       if (inUse) {
548         info->satellites.inUse[iGpsd] = prn;
549         info->satellites.inUseCount++;
550       }
551     }
552   }
553   nmeaInfoSetPresent(&info->present, //
554       NMEALIB_PRESENT_SATINUSECOUNT //
555       | NMEALIB_PRESENT_SATINUSE //
556       | NMEALIB_PRESENT_SATINVIEWCOUNT //
557       | NMEALIB_PRESENT_SATINVIEW);
558   gpsdata->set &= ~SATELLITE_SET;
559
560   nmeaInfoSanitise(info);
561
562   if (gpsdata->set) {
563     syslog(LOG_WARNING, "Unhandled bits in gpsdata->set: %llx", (long long unsigned int) gpsdata->set);
564   }
565 }
566
567 void readFromGpsd(GpsDaemon *gpsd, struct gps_data_t *gpsdata, struct GpsdConnectionState *connectionTracking, NmeaInfo *nmeaInfo) {
568   int gpsReadCode;
569
570   if (!gpsd //
571       || !gpsdata //
572       || !connectionTracking //
573       || !nmeaInfo) {
574     return;
575   }
576
577   errno = 0;
578   if (!connectionTracking->connected) {
579     gpsReadCode = -1;
580   } else {
581     gpsReadCode = gps_read(gpsdata);
582   }
583
584   if (gpsReadCode > 0) {
585     /* data received from gpsd */
586     nmeaInfoFromGpsd(gpsdata, nmeaInfo, connectionTracking);
587   } else if (gpsReadCode < 0) {
588     /* failed to receive data from gpsd */
589
590     if (connectionTracking->connected) {
591       if (errno) {
592         syslog(LOG_WARNING, "Disconnected from gpsd: %s", strerror(errno));
593       } else {
594         syslog(LOG_WARNING, "Disconnected from gpsd");
595       }
596
597       gpsdDisconnect(gpsdata, connectionTracking);
598       nmeaInfoClear(nmeaInfo);
599     }
600
601     connectionTracking->connected = gpsdConnect(gpsd, gpsdata, connectionTracking);
602     nmeaTimeSet(&nmeaInfo->utc, &nmeaInfo->present, NULL);
603   } else {
604     /* no data received from gpsd */
605   }
606 }