1 /* libgpsd_core.c -- direct access to GPSes on serial or USB devices.
3 * This file is Copyright (c) 2010 by the GPSD project
4 * BSD terms apply: see the file COPYING in the distribution root for details.
7 #include "gpsd_config.h"
9 #ifdef HAVE_SYS_IOCTL_H
10 #include <sys/ioctl.h>
11 #endif /* HAVE_SYS_IOCTL_H */
13 #ifdef HAVE_SYS_SOCKET_H
14 #include <sys/socket.h>
17 #endif /* HAVE_SYS_SOCKET_H */
19 #endif /* S_SPLINT_S */
26 #endif /* HAVE_NETDB_H */
27 #endif /* S_SPLINT_S */
34 #if defined(PPS_ENABLE) && defined(TIOCMIWAIT)
36 #include <pthread.h> /* pacifies OpenBSD's compiler */
40 int gpsd_switch_driver(struct gps_device_t *session, char *type_name)
42 const struct gps_type_t **dp;
43 bool identified = (session->device_type != NULL);
45 gpsd_report(LOG_PROG, "switch_driver(%s) called...\n", type_name);
46 if (identified && strcmp(session->device_type->type_name, type_name) == 0)
50 for (dp = gpsd_drivers; *dp; dp++)
51 if (strcmp((*dp)->type_name, type_name) == 0) {
52 gpsd_report(LOG_PROG, "selecting %s driver...\n",
54 gpsd_assert_sync(session);
55 /*@i@*/ session->device_type = *dp;
56 #ifdef ALLOW_RECONFIGURE
57 session->gpsdata.dev.mincycle = session->device_type->min_cycle;
58 #endif /* ALLOW_RECONFIGURE */
59 /* reconfiguration might be required */
60 if (identified && session->device_type->event_hook != NULL)
61 session->device_type->event_hook(session,
63 /* clients should be notified */
64 session->notify_clients = true;
67 gpsd_report(LOG_ERROR, "invalid GPS type \"%s\".\n", type_name);
73 void gpsd_init(struct gps_device_t *session, struct gps_context_t *context,
75 /* initialize GPS polling */
77 /*@ -mayaliasunique @*/
79 (void)strlcpy(session->gpsdata.dev.path, device,
80 sizeof(session->gpsdata.dev.path));
82 session->device_type = NULL; /* start by hunting packets */
83 session->observed = 0;
84 session->rtcmtime = 0;
85 session->is_serial = false; /* gpsd_open() sets this */
86 session->sourcetype = source_unknown; /* gpsd_open() sets this */
88 session->context = context;
90 /*@ +mayaliasunique @*/
92 gps_clear_fix(&session->gpsdata.fix);
93 gps_clear_fix(&session->newdata);
94 gps_clear_fix(&session->oldfix);
95 session->gpsdata.set = 0;
96 session->gpsdata.dop.hdop = NAN;
97 session->gpsdata.dop.vdop = NAN;
98 session->gpsdata.dop.pdop = NAN;
99 session->gpsdata.dop.tdop = NAN;
100 session->gpsdata.dop.gdop = NAN;
101 session->gpsdata.epe = NAN;
102 session->mag_var = NAN;
103 session->gpsdata.dev.cycle = session->gpsdata.dev.mincycle = 1;
105 /* tty-level initialization */
106 gpsd_tty_init(session);
107 /* necessary in case we start reading in the middle of a GPGSV sequence */
108 gpsd_zero_satellites(&session->gpsdata);
110 /* initialize things for the packet parser */
111 packet_reset(&session->packet);
114 void gpsd_deactivate(struct gps_device_t *session)
115 /* temporarily release the GPS device */
118 (void)ntpshm_free(session->context, session->shmindex);
119 session->shmindex = -1;
121 (void)ntpshm_free(session->context, session->shmTimeP);
122 session->shmTimeP = -1;
123 # endif /* PPS_ENABLE */
124 #endif /* NTPSHM_ENABLE */
125 #ifdef ALLOW_RECONFIGURE
126 if (!session->context->readonly
127 && session->device_type != NULL
128 && session->device_type->event_hook != NULL) {
129 session->device_type->event_hook(session, event_deactivate);
131 if (session->device_type != NULL) {
132 if (session->back_to_nmea
133 && session->device_type->mode_switcher != NULL)
134 session->device_type->mode_switcher(session, 0);
136 #endif /* ALLOW_RECONFIGURE */
137 gpsd_report(LOG_INF, "closing GPS=%s (%d)\n",
138 session->gpsdata.dev.path, session->gpsdata.gps_fd);
139 (void)gpsd_close(session);
142 #if defined(PPS_ENABLE) && defined(TIOCMIWAIT)
143 static /*@null@*/ void *gpsd_ppsmonitor(void *arg)
145 struct gps_device_t *session = (struct gps_device_t *)arg;
146 int cycle, duration, state = 0, laststate = -1, unchanged = 0;
148 struct timeval pulse[2] = { {0, 0}, {0, 0} };
150 #if defined(PPS_ON_CTS)
151 int pps_device = TIOCM_CTS;
152 #define pps_device_str "CTS"
154 int pps_device = TIOCM_CAR;
155 #define pps_device_str "DCD"
158 gpsd_report(LOG_PROG, "PPS Create Thread gpsd_ppsmonitor\n");
160 /* wait for status change on the device's carrier-detect line */
161 while (ioctl(session->gpsdata.gps_fd, TIOCMIWAIT, pps_device) == 0) {
165 (void)gettimeofday(&tv, NULL);
171 if (ioctl(session->gpsdata.gps_fd, TIOCMGET, &state) != 0)
175 state = (int)((state & pps_device) != 0);
177 #define timediff(x, y) (int)((x.tv_sec-y.tv_sec)*1000000+x.tv_usec-y.tv_usec)
178 cycle = timediff(tv, pulse[state]);
179 duration = timediff(tv, pulse[(int)(state == 0)]);
183 if (state == laststate) {
184 /* some pulses may be so short that state never changes */
185 if (999000 < cycle && 1001000 > cycle) {
189 "PPS pps-detect (%s) on %s invisible pulse\n",
190 pps_device_str, session->gpsdata.dev.path);
191 } else if (++unchanged == 10) {
193 gpsd_report(LOG_WARN,
194 "PPS TIOCMIWAIT returns unchanged state, ppsmonitor sleeps 10\n");
198 gpsd_report(LOG_RAW, "PPS pps-detect (%s) on %s changed to %d\n",
199 pps_device_str, session->gpsdata.dev.path, state);
205 // strange, try again
208 gpsd_report(LOG_INF, "PPS cycle: %d, duration: %d @ %lu.%06lu\n",
210 (unsigned long)tv.tv_sec, (unsigned long)tv.tv_usec);
213 if (3 < session->context->fixcnt) {
214 /* Garmin doc says PPS is valid after four good fixes. */
216 * The PPS pulse is normally a short pulse with a frequency of
217 * 1 Hz, and the UTC second is defined by the front edge. But we
218 * don't know the polarity of the pulse (different receivers
219 * emit different polarities). The duration variable is used to
220 * determine which way the pulse is going. The code assumes
221 * that the UTC second is changing when the signal has not
222 * been changing for at least 800ms, i.e. it assumes the duty
223 * cycle is at most 20%.
225 * Some GPS instead output a square wave that is 0.5 Hz and each
226 * edge denotes the start of a second.
228 * Some GPS, like the Globalsat MR-350P, output a 1uS pulse.
229 * The pulse is so short that TIOCMIWAIT sees a state change
230 * but by the time TIOCMGET is called the pulse is gone.
232 * A few stupid GPS, like the Furuno GPSClock, output a 1.0 Hz
233 * square wave where the leading edge is the start of a second
235 * 5Hz GPS (Garmin 18-5Hz) pulses at 5Hz. Set the pulse length to
236 * 40ms which gives a 160ms pulse before going high.
240 if (199000 > cycle) {
241 // too short to even be a 5Hz pulse
242 log = "Too short for 5Hz\n";
243 } else if (201000 > cycle) {
245 /* looks like 5hz PPS pulse */
246 if (100000 > duration) {
247 /* BUG: how does the code know to tell ntpd
248 * which 1/5 of a second to use?? */
250 log = "5Hz PPS pulse\n";
252 } else if (999000 > cycle) {
253 log = "Too long for 5Hz, too short for 1Hz\n";
254 } else if (1001000 > cycle) {
255 /* looks like PPS pulse or square wave */
258 log = "PPS invisible pulse\n";
259 } else if (499000 > duration) {
260 /* end of the short "half" of the cycle */
261 /* aka the trailing edge */
262 log = "PPS 1Hz trailing edge\n";
263 } else if (501000 > duration) {
264 /* looks like 1.0 Hz square wave, ignore trailing edge */
267 log = "PPS square\n";
270 /* end of the long "half" of the cycle */
271 /* aka the leading edge */
273 log = "PPS 1Hz leading edge\n";
275 } else if (1999000 > cycle) {
276 log = "Too long for 1Hz, too short for 2Hz\n";
277 } else if (2001000 > cycle) {
278 /* looks like 0.5 Hz square wave */
279 if (999000 > duration) {
280 log = "PPS 0.5 Hz square too short duration\n";
281 } else if (1001000 > duration) {
283 log = "PPS 0.5 Hz square wave\n";
285 log = "PPS 0.5 Hz square too long duration\n";
288 log = "Too long for 0.5Hz\n";
291 /* not a good fix, but a test for an otherwise good PPS
293 log = "PPS no fix.\n";
297 gpsd_report(LOG_RAW, "%s\n", log);
300 (void)ntpshm_pps(session, &tv);
302 gpsd_report(LOG_INF, "PPS pulse rejected\n");
309 #endif /* PPS_ENABLE */
312 int gpsd_activate(struct gps_device_t *session)
313 /* acquire a connection to the GPS device */
315 /* special case: source may be a URI to a remote GNSS or DGPS service */
316 if (netgnss_uri_check(session->gpsdata.dev.path)) {
317 session->gpsdata.gps_fd = netgnss_uri_open(session->context,
318 session->gpsdata.dev.path);
319 session->sourcetype = source_tcp;
320 gpsd_report(LOG_SPIN,
321 "netgnss_uri_open(%s) returns socket on fd %d\n",
322 session->gpsdata.dev.path, session->gpsdata.gps_fd);
323 /* otherwise, could be an TCP data feed */
324 } else if (strncmp(session->gpsdata.dev.path, "tcp://", 6) == 0) {
325 char server[GPS_PATH_MAX], *port;
327 (void)strlcpy(server, session->gpsdata.dev.path + 6, sizeof(server));
328 session->gpsdata.gps_fd = -1;
329 port = strchr(server, ':');
331 gpsd_report(LOG_ERROR, "Missing colon in TCP feed spec.\n");
335 gpsd_report(LOG_INF, "opening TCP feed at %s, port %s.\n", server,
337 if ((dsock = netlib_connectsock(AF_UNSPEC, server, port, "tcp")) < 0) {
338 gpsd_report(LOG_ERROR, "TCP device open error %s.\n",
339 netlib_errstr(dsock));
342 session->gpsdata.gps_fd = dsock;
343 session->sourcetype = source_tcp;
344 } else if (strncmp(session->gpsdata.dev.path, "udp://", 6) == 0) {
345 char server[GPS_PATH_MAX], *port;
347 (void)strlcpy(server, session->gpsdata.dev.path + 6, sizeof(server));
348 session->gpsdata.gps_fd = -1;
349 port = strchr(server, ':');
351 gpsd_report(LOG_ERROR, "Missing colon in UDP feed spec.\n");
355 gpsd_report(LOG_INF, "opening UDP feed at %s, port %s.\n", server,
357 if ((dsock = netlib_connectsock(AF_UNSPEC, server, port, "udp")) < 0) {
358 gpsd_report(LOG_ERROR, "UDP device open error %s.\n",
359 netlib_errstr(dsock));
362 session->gpsdata.gps_fd = dsock;
363 session->sourcetype = source_udp;
365 /* otherwise, ordinary serial device */
367 session->gpsdata.gps_fd = gpsd_open(session);
369 if (session->gpsdata.gps_fd < 0)
372 #ifdef NON_NMEA_ENABLE
373 const struct gps_type_t **dp;
375 /*@ -mustfreeonly @*/
376 for (dp = gpsd_drivers; *dp; dp++) {
377 (void)tcflush(session->gpsdata.gps_fd, TCIOFLUSH); /* toss stale data */
378 if ((*dp)->probe_detect != NULL
379 && (*dp)->probe_detect(session) != 0) {
380 gpsd_report(LOG_PROG, "probe found %s driver...\n",
382 session->device_type = *dp;
383 gpsd_assert_sync(session);
387 /*@ +mustfreeonly @*/
388 gpsd_report(LOG_PROG, "no probe matched...\n");
390 #endif /* NON_NMEA_ENABLE */
391 session->gpsdata.online = timestamp();
393 session->driver.sirf.satcounter = 0;
394 #endif /* SIRF_ENABLE */
395 packet_init(&session->packet);
397 "gpsd_activate(): opened GPS (fd %d)\n",
398 session->gpsdata.gps_fd);
399 // session->gpsdata.online = 0;
400 session->gpsdata.fix.mode = MODE_NOT_SEEN;
401 session->gpsdata.status = STATUS_NO_FIX;
402 session->gpsdata.fix.track = NAN;
403 session->gpsdata.separation = NAN;
404 session->mag_var = NAN;
405 session->releasetime = 0;
406 session->getcount = 0;
408 /* clear the private data union */
409 memset(&session->driver, '\0', sizeof(session->driver));
411 * We might know the device's type, but we shoudn't assume it has
412 * retained its settings. A revert hook might well have undone
413 * them on the previous close. Fire a reactivate event so drivers
414 * can do something about this if they choose.
416 if (session->device_type != NULL
417 && session->device_type->event_hook != NULL)
418 session->device_type->event_hook(session, event_reactivate);
421 session->opentime = timestamp();
422 return session->gpsdata.gps_fd;
427 void ntpd_link_activate(struct gps_device_t *session)
429 #if defined(PPS_ENABLE) && defined(TIOCMIWAIT)
431 #endif /* defined(PPS_ENABLE) && defined(TIOCMIWAIT) */
434 /* If we are talking to ntpd, allocate a shared-memory segment for "NMEA" time data */
435 if (session->context->enable_ntpshm)
436 session->shmindex = ntpshm_alloc(session->context);
438 if (0 > session->shmindex) {
439 gpsd_report(LOG_INF, "NTPD ntpshm_alloc() failed\n");
440 #if defined(PPS_ENABLE) && defined(TIOCMIWAIT)
441 } else if (session->context->shmTimePPS) {
442 /* We also have the 1pps capability, allocate a shared-memory segment
443 * for the 1pps time data and launch a thread to capture the 1pps
446 if ((session->shmTimeP = ntpshm_alloc(session->context)) >= 0) {
448 (void)pthread_create(&pt, NULL, gpsd_ppsmonitor, (void *)session);
451 gpsd_report(LOG_INF, "NTPD ntpshm_alloc(1) failed\n");
454 #endif /* defined(PPS_ENABLE) && defined(TIOCMIWAIT) */
456 #endif /* NTPSHM_ENABLE */
459 char /*@observer@*/ *gpsd_id( /*@in@ */ struct gps_device_t *session)
460 /* full ID of the device for reports, including subtype */
462 static char buf[128];
463 if ((session == NULL) || (session->device_type == NULL) ||
464 (session->device_type->type_name == NULL))
466 (void)strlcpy(buf, session->device_type->type_name, sizeof(buf));
467 if (session->subtype[0] != '\0') {
468 (void)strlcat(buf, " ", sizeof(buf));
469 (void)strlcat(buf, session->subtype, sizeof(buf));
474 static void gpsd_error_model(struct gps_device_t *session,
475 struct gps_fix_t *fix, struct gps_fix_t *oldfix)
476 /* compute errors and derived quantities */
479 * Now we compute derived quantities. This is where the tricky error-
480 * modeling stuff goes. Presently we don't know how to derive
483 * Some drivers set the position-error fields. Only the Zodiacs
484 * report speed error. Nobody reports track error or climb error.
486 * The UERE constants are our assumption about the base error of
487 * GPS fixes in different directions.
489 #define H_UERE_NO_DGPS 15.0 /* meters, 95% confidence */
490 #define H_UERE_WITH_DGPS 3.75 /* meters, 95% confidence */
491 #define V_UERE_NO_DGPS 23.0 /* meters, 95% confidence */
492 #define V_UERE_WITH_DGPS 5.75 /* meters, 95% confidence */
493 #define P_UERE_NO_DGPS 19.0 /* meters, 95% confidence */
494 #define P_UERE_WITH_DGPS 4.75 /* meters, 95% confidence */
495 double h_uere, v_uere, p_uere;
501 (session->gpsdata.status ==
502 STATUS_DGPS_FIX ? H_UERE_WITH_DGPS : H_UERE_NO_DGPS);
504 (session->gpsdata.status ==
505 STATUS_DGPS_FIX ? V_UERE_WITH_DGPS : V_UERE_NO_DGPS);
507 (session->gpsdata.status ==
508 STATUS_DGPS_FIX ? P_UERE_WITH_DGPS : P_UERE_NO_DGPS);
511 * OK, this is not an error computation, but we're at the right
512 * place in the architecture for it. Compute speed over ground
513 * and climb/sink in the simplest possible way.
515 if (fix->mode >= MODE_2D && oldfix->mode >= MODE_2D
516 && isnan(fix->speed) != 0) {
517 if (fix->time == oldfix->time)
521 earth_distance(fix->latitude, fix->longitude,
522 oldfix->latitude, oldfix->longitude)
523 / (fix->time - oldfix->time);
525 if (fix->mode >= MODE_3D && oldfix->mode >= MODE_3D
526 && isnan(fix->climb) != 0) {
527 if (fix->time == oldfix->time)
529 else if (isnan(fix->altitude) == 0 && isnan(oldfix->altitude) == 0) {
531 (fix->altitude - oldfix->altitude) / (fix->time -
537 * Field reports match the theoretical prediction that
538 * expected time error should be half the resolution of
539 * the GPS clock, so we put the bound of the error
540 * in as a constant pending getting it from each driver.
542 if (isnan(fix->time) == 0 && isnan(fix->ept) != 0)
544 /* Other error computations depend on having a valid fix */
545 gpsd_report(LOG_DATA, "modeling errors: mode=%d, masks=%s\n",
546 fix->mode, gpsd_maskdump(session->gpsdata.set));
547 if (fix->mode >= MODE_2D) {
548 if (isnan(fix->epx) != 0 && finite(session->gpsdata.dop.hdop) != 0)
549 fix->epx = session->gpsdata.dop.xdop * h_uere;
551 if (isnan(fix->epy) != 0 && finite(session->gpsdata.dop.hdop) != 0)
552 fix->epy = session->gpsdata.dop.ydop * h_uere;
554 if ((fix->mode >= MODE_3D)
555 && isnan(fix->epv) != 0 && finite(session->gpsdata.dop.vdop) != 0)
556 fix->epv = session->gpsdata.dop.vdop * v_uere;
558 if (isnan(session->gpsdata.epe) != 0
559 && finite(session->gpsdata.dop.pdop) != 0)
560 session->gpsdata.epe = session->gpsdata.dop.pdop * p_uere;
562 session->gpsdata.epe = NAN;
565 * If we have a current fix and an old fix, and the packet handler
566 * didn't set the speed error and climb error members itself,
567 * try to compute them now.
569 if (isnan(fix->eps) != 0) {
570 if (oldfix->mode > MODE_NO_FIX && fix->mode > MODE_NO_FIX
571 && isnan(oldfix->epx) == 0 && isnan(oldfix->epy) == 0
572 && isnan(oldfix->time) == 0 && isnan(oldfix->time) == 0
573 && fix->time > oldfix->time) {
574 double t = fix->time - oldfix->time;
576 EMIX(oldfix->epx, oldfix->epy) + EMIX(fix->epx, fix->epy);
581 if ((fix->mode >= MODE_3D)
582 && isnan(fix->epc) != 0 && fix->time > oldfix->time) {
583 if (oldfix->mode > MODE_3D && fix->mode > MODE_3D) {
584 double t = fix->time - oldfix->time;
585 double e = oldfix->epv + fix->epv;
586 /* if vertical uncertainties are zero this will be too */
590 * We compute a track error estimate solely from the
591 * position of this fix and the last one. The maximum
592 * track error, as seen from the position of last fix, is
593 * the angle subtended by the two most extreme possible
594 * error positions of the current fix; the expected track
595 * error is half that. Let the position of the old fix be
596 * A and of the new fix B. We model the view from A as
597 * two right triangles ABC and ABD with BC and BD both
598 * having the length of the new fix's estimated error.
599 * adj = len(AB), opp = len(BC) = len(BD), hyp = len(AC) =
600 * len(AD). This leads to spurious uncertainties
601 * near 180 when we're moving slowly; to avoid reporting
602 * garbage, throw back NaN if the distance from the previous
603 * fix is less than the error estimate.
606 if (oldfix->mode >= MODE_2D) {
608 earth_distance(oldfix->latitude, oldfix->longitude,
609 fix->latitude, fix->longitude);
610 if (isnan(adj) == 0 && adj > EMIX(fix->epx, fix->epy)) {
611 double opp = EMIX(fix->epx, fix->epy);
612 double hyp = sqrt(adj * adj + opp * opp);
613 fix->epd = RAD_2_DEG * 2 * asin(opp / hyp);
619 /* save old fix for later error computations */
620 /*@ -mayaliasunique @*/
621 if (fix->mode >= MODE_2D)
622 (void)memcpy(oldfix, fix, sizeof(struct gps_fix_t));
623 /*@ +mayaliasunique @*/
626 gps_mask_t gpsd_poll(struct gps_device_t *session)
627 /* update the stuff in the scoreboard structure */
630 bool first_sync = false;
632 gps_clear_fix(&session->newdata);
635 if (session->packet.outbuflen == 0)
636 session->d_xmit_time = timestamp();
637 #endif /* TIMING_ENABLE */
639 if (session->packet.type >= COMMENT_PACKET) {
641 session->observed |= PACKET_TYPEMASK(session->packet.type);
645 /* can we get a full packet from the device? */
646 if (session->device_type) {
647 newlen = session->device_type->get_packet(session);
649 "%s is known to be %s\n",
650 session->gpsdata.dev.path,
651 session->device_type->type_name);
653 const struct gps_type_t **dp;
655 newlen = generic_get(session);
657 "packet sniff on %s finds type %d\n",
658 session->gpsdata.dev.path, session->packet.type);
659 if (session->packet.type == COMMENT_PACKET) {
660 gpsd_report (LOG_PROG, "comment, sync lock deferred\n");
661 } else if (session->packet.type > COMMENT_PACKET) {
662 first_sync = (session->device_type == NULL);
663 for (dp = gpsd_drivers; *dp; dp++)
664 if (session->packet.type == (*dp)->packet_type) {
665 (void)gpsd_switch_driver(session, (*dp)->type_name);
668 } else if (session->getcount++ > 1 && !gpsd_next_hunt_setting(session))
672 /* update the scoreboard structure from the GPS */
673 gpsd_report(LOG_RAW + 2, "%s sent %zd new characters\n",
674 session->gpsdata.dev.path, newlen);
675 if (newlen < 0) { /* read error */
676 gpsd_report(LOG_INF, "GPS on %s returned error %zd (%lf sec since data)\n",
677 session->gpsdata.dev.path, newlen,
678 timestamp() - session->gpsdata.online);
679 session->gpsdata.online = 0;
681 } else if (newlen == 0) { /* zero length read, possible EOF */
682 gpsd_report(LOG_INF, "GPS on %s is offline (%lf sec since data)\n",
683 session->gpsdata.dev.path,
684 timestamp() - session->gpsdata.online);
685 session->gpsdata.online = 0;
687 } else if (session->packet.outbuflen == 0) { /* got new data, but no packet */
688 gpsd_report(LOG_RAW + 3, "New data on %s, not yet a packet\n",
689 session->gpsdata.dev.path);
691 } else { /* we have recognized a packet */
692 gps_mask_t received = PACKET_IS, dopmask = 0;
693 session->gpsdata.online = timestamp();
695 gpsd_report(LOG_RAW + 3, "Accepted packet on %s.\n",
696 session->gpsdata.dev.path);
699 session->d_recv_time = timestamp();
700 #endif /* TIMING_ENABLE */
702 /* track the packet count since achieving sync on the device */
706 "%s identified as type %s (%f sec @ %dbps)\n",
707 session->gpsdata.dev.path,
708 session->device_type->type_name,
709 timestamp() - session->opentime,
710 gpsd_get_speed(&session->ttyset));
712 /* fire the identified hook */
713 if (session->device_type != NULL
714 && session->device_type->event_hook != NULL)
715 session->device_type->event_hook(session, event_identified);
716 session->packet.counter = 0;
718 session->packet.counter++;
720 /* fire the configure hook */
721 if (session->device_type != NULL
722 && session->device_type->event_hook != NULL)
723 session->device_type->event_hook(session, event_configure);
726 * If this is the first time we've achieved sync on this
727 * device, or the driver type has changed for any other
728 * reason, that's a significant event that the caller needs to
731 if (first_sync || session->notify_clients) {
732 session->notify_clients = false;
733 received |= DRIVER_IS;
736 /* Get data from current packet into the fix structure */
737 if (session->packet.type != COMMENT_PACKET)
738 if (session->device_type != NULL
739 && session->device_type->parse_packet != NULL)
740 received |= session->device_type->parse_packet(session);
744 * Only update the NTP time if we've seen the leap-seconds data.
745 * Else we may be providing GPS time.
747 if (session->context->enable_ntpshm == 0) {
748 //gpsd_report(LOG_PROG, "NTP: off\n");
749 } else if ((received & TIME_IS) == 0) {
750 //gpsd_report(LOG_PROG, "NTP: No time this packet\n");
751 } else if (isnan(session->newdata.time)) {
752 //gpsd_report(LOG_PROG, "NTP: bad new time\n");
753 } else if (session->newdata.time == session->last_fixtime) {
754 //gpsd_report(LOG_PROG, "NTP: Not a new time\n");
755 } else if (session->newdata.mode == MODE_NO_FIX) {
756 //gpsd_report(LOG_PROG, "NTP: No fix\n");
759 //gpsd_report(LOG_PROG, "NTP: Got one\n");
760 /* assume zero when there's no offset method */
761 if (session->device_type == NULL
762 || session->device_type->ntp_offset == NULL)
765 offset = session->device_type->ntp_offset(session);
766 (void)ntpshm_put(session, session->newdata.time, offset);
767 session->last_fixtime = session->newdata.time;
769 #endif /* NTPSHM_ENABLE */
772 * Compute fix-quality data from the satellite positions.
773 * These will not overwrite any DOPs reported from the packet
776 if ((received & SATELLITE_IS) != 0
777 && session->gpsdata.satellites_visible > 0) {
778 dopmask = fill_dop(&session->gpsdata, &session->gpsdata.dop);
779 session->gpsdata.epe = NAN;
781 session->gpsdata.set = ONLINE_IS | dopmask | received;
783 /* copy/merge device data into staging buffers */
784 /*@-nullderef -nullpass@*/
785 if ((session->gpsdata.set & CLEAR_IS) != 0)
786 gps_clear_fix(&session->gpsdata.fix);
787 /* don't downgrade mode if holding previous fix */
788 if (session->gpsdata.fix.mode > session->newdata.mode)
789 session->gpsdata.set &= ~MODE_IS;
790 //gpsd_report(LOG_PROG,
791 // "transfer mask on %s: %02x\n", session->gpsdata.tag, session->gpsdata.set);
792 gps_merge_fix(&session->gpsdata.fix,
793 session->gpsdata.set, &session->newdata);
794 gpsd_error_model(session, &session->gpsdata.fix, &session->oldfix);
795 /*@+nullderef -nullpass@*/
798 * Count good fixes. We used to check
799 * session->gpsdata.status > STATUS_NO_FIX
800 * here, but that wasn't quite right. That tells us whether
801 * we think we have a valid fix for the current cycle, but remains
802 * true while following non-fix packets are received. What we
803 * really want to know is whether the last packet received was a
804 * fix packet AND held a valid fix. We must ignore non-fix packets
805 * AND packets which have fix data but are flagged as invalid. Some
806 * devices output fix packets on a regular basis, even when unable
807 * to derive a good fix. Such packets should set STATUS_NO_FIX.
809 if ((session->gpsdata.set & LATLON_IS) != 0
810 && session->gpsdata.status > STATUS_NO_FIX)
811 session->context->fixcnt++;
814 session->d_decode_time = timestamp();
815 #endif /* TIMING_ENABLE */
818 * Sanity check. This catches a surprising number of port and
819 * driver errors, including 32-vs.-64-bit problems.
821 /*@+relaxtypes +longunsignedintegral@*/
822 if ((session->gpsdata.set & TIME_IS) != 0) {
823 if (session->newdata.time > time(NULL) + (60 * 60 * 24 * 365))
824 gpsd_report(LOG_ERROR,
825 "date more than a year in the future!\n");
826 else if (session->newdata.time < 0)
827 gpsd_report(LOG_ERROR, "date is negative!\n");
829 /*@-relaxtypes -longunsignedintegral@*/
831 return session->gpsdata.set;
835 void gpsd_wrap(struct gps_device_t *session)
836 /* end-of-session wrapup */
838 if (session->gpsdata.gps_fd != -1)
839 gpsd_deactivate(session);
842 void gpsd_zero_satellites( /*@out@*/ struct gps_data_t *out)
844 (void)memset(out->PRN, 0, sizeof(out->PRN));
845 (void)memset(out->elevation, 0, sizeof(out->elevation));
846 (void)memset(out->azimuth, 0, sizeof(out->azimuth));
847 (void)memset(out->ss, 0, sizeof(out->ss));
848 out->satellites_visible = 0;
849 clear_dop(&out->dop);