static gps_mask_t decode_itk_subframe(struct gps_device_t *session, unsigned char *buf, size_t len) { unsigned short flags, prn, sf; unsigned int i; uint32_t words[10]; if (len != 64) { gpsd_report(LOG_PROG, "ITALK: bad SUBFRAME (len %zu, should be 64)\n", len); return 0; } flags = (ushort) getleu16(buf, 7 + 4); prn = (ushort) getleu16(buf, 7 + 6); sf = (ushort) getleu16(buf, 7 + 8); gpsd_report(LOG_PROG, "iTalk 50B SUBFRAME prn %u sf %u - decode %s %s\n", prn, sf, flags & SUBFRAME_WORD_FLAG_MASK ? "error" : "ok", flags & SUBFRAME_GPS_PREAMBLE_INVERTED ? "(inverted)" : ""); if (flags & SUBFRAME_WORD_FLAG_MASK) return 0; // don't try decode an erroneous packet /* * Timo says "SUBRAME message contains decoded navigation message subframe * words with parity checking done but parity bits still present." */ for (i = 0; i < 10; i++) words[i] = (uint32_t)(getleu32(buf, 7 + 14 + 4 * i) >> 6) & 0xffffff; return gpsd_interpret_subframe(session, prn, words); }
/*@-mustfreefresh@*/ static void init_hook(struct gps_device_t *session) /* for chrony SOCK interface, which allows nSec timekeeping */ { /* open the chrony socket */ char chrony_path[GPS_PATH_MAX]; session->chronyfd = -1; if ( 0 == getuid() ) { /* this case will fire on command-line devices; * they're opened before priv-dropping. Matters because * only root can use /var/run. */ (void)snprintf(chrony_path, sizeof (chrony_path), "/var/run/chrony.%s.sock", basename(session->gpsdata.dev.path)); } else { (void)snprintf(chrony_path, sizeof (chrony_path), "/tmp/chrony.%s.sock", basename(session->gpsdata.dev.path)); } if (access(chrony_path, F_OK) != 0) { gpsd_report(&session->context->errout, LOG_PROG, "PPS chrony socket %s doesn't exist\n", chrony_path); } else { session->chronyfd = netlib_localsocket(chrony_path, SOCK_DGRAM); if (session->chronyfd < 0) gpsd_report(&session->context->errout, LOG_PROG, "PPS connect chrony socket failed: %s, error: %d, errno: %d/%s\n", chrony_path, session->chronyfd, errno, strerror(errno)); else gpsd_report(&session->context->errout, LOG_RAW, "PPS using chrony socket: %s\n", chrony_path); } }
void gpsd_time_init(struct gps_context_t *context, time_t starttime) /* initialize the GPS context's time fields */ { /* * Provides a start time for getting the century. Do this, just * in case one of our embedded deployments is still in place in * the year 2.1K. Still likely to fail if we bring up the daemon * just before a century mark, but that case is probably doomed * anyhow because of 2-digit years. */ context->leap_seconds = LEAPSECOND_NOW; context->century = CENTURY_BASE; context->start_time = starttime; context->rollovers = (int)((context->start_time-GPS_EPOCH) / GPS_ROLLOVER); if (context->start_time < GPS_EPOCH) gpsd_report(LOG_ERROR, "system time looks bogus, dates may not be reliable.\n"); else { struct tm *now = localtime(&context->start_time); char scr[128]; /* * This is going to break our regression-test suite once a century. * I think we can live with that consequence. */ now->tm_year += 1900; context->century = now->tm_year - (now->tm_year % 100); (void)unix_to_iso8601((timestamp_t)context->start_time, scr, sizeof(scr)); gpsd_report(LOG_INF, "startup at %s (%d)\n", scr, (int)context->start_time); } }
void ntpshm_link_activate(struct gps_device_t *session) /* set up ntpshm storage for a session */ { /* allocate a shared-memory segment for "NMEA" time data */ session->shmIndex = ntpshm_alloc(session->context); if (0 > session->shmIndex) { gpsd_report(&session->context->errout, LOG_INF, "NTPD ntpshm_alloc() failed\n"); #if defined(PPS_ENABLE) } else if (session->sourcetype == source_usb || session->sourcetype == source_rs232) { /* We also have the 1pps capability, allocate a shared-memory segment * for the 1pps time data and launch a thread to capture the 1pps * transitions */ if ((session->shmIndexPPS = ntpshm_alloc(session->context)) < 0) { gpsd_report(&session->context->errout, LOG_INF, "NTPD ntpshm_alloc(1) failed\n"); } else { init_hook(session); session->thread_report_hook = report_hook; session->thread_wrap_hook = wrap_hook; pps_thread_activate(session); } #endif /* PPS_ENABLE */ } }
static int ntrip_stream_get_req(const struct ntrip_stream_t *stream, const int debug) { int dsock; char buf[BUFSIZ]; dsock = netlib_connectsock(AF_UNSPEC, stream->url, stream->port, "tcp"); if (BAD_SOCKET(dsock)) { gpsd_report(debug, LOG_ERROR, "ntrip stream connect error %d\n", dsock); return -1; } gpsd_report(debug, LOG_SPIN, "netlib_connectsock() returns socket on fd %d\n", dsock); (void)snprintf(buf, sizeof(buf), "GET /%s HTTP/1.1\r\n" "User-Agent: NTRIP gpsd/%s\r\n" "Host: %s\r\n" "Accept: rtk/rtcm, dgps/rtcm\r\n" "%s" "Connection: close\r\n" "\r\n", stream->mountpoint, VERSION, stream->url, stream->authStr); if (write(dsock, buf, strlen(buf)) != (ssize_t) strlen(buf)) { gpsd_report(debug, LOG_ERROR, "ntrip stream write error %d on fd %d during get request\n", errno, dsock); (void)close(dsock); return -1; } return dsock; }
void dgpsip_report(struct gps_context_t *context, struct gps_device_t *gps, struct gps_device_t *dgpsip) /* may be time to ship a usage report to the DGPSIP server */ { /* * 10 is an arbitrary number, the point is to have gotten several good * fixes before reporting usage to our DGPSIP server. */ if (context->fixcnt > 10 && !dgpsip->dgpsip.reported) { dgpsip->dgpsip.reported = true; if (dgpsip->gpsdata.gps_fd > -1) { char buf[BUFSIZ]; (void)snprintf(buf, sizeof(buf), "R %0.8f %0.8f %0.2f\r\n", gps->gpsdata.fix.latitude, gps->gpsdata.fix.longitude, gps->gpsdata.fix.altitude); if (write(dgpsip->gpsdata.gps_fd, buf, strlen(buf)) == (ssize_t) strlen(buf)) gpsd_report(LOG_IO, "=> dgps %s\n", buf); else gpsd_report(LOG_IO, "write to dgps FAILED\n"); } } }
void ntrip_report(struct gps_context_t *context, struct gps_device_t *gps, struct gps_device_t *caster) /* may be time to ship a usage report to the Ntrip caster */ { static int count; /* * 10 is an arbitrary number, the point is to have gotten several good * fixes before reporting usage to our Ntrip caster. * * count % 5 is as arbitrary a number as the fixcnt. But some delay * was needed here */ count ++; if (caster->ntrip.stream.nmea != 0 && context->fixcnt > 10 && (count % 5)==0) { if (caster->gpsdata.gps_fd > -1) { char buf[BUFSIZ]; gpsd_position_fix_dump(gps, buf, sizeof(buf)); if (write(caster->gpsdata.gps_fd, buf, strlen(buf)) == (ssize_t) strlen(buf)) { gpsd_report(context->debug, LOG_IO, "=> dgps %s\n", buf); } else { gpsd_report(context->debug, LOG_IO, "ntrip report write failed\n"); } } } }
static gps_mask_t decode_itk_utcionomodel(struct gps_device_t *session, unsigned char *buf, size_t len) { int leap; unsigned short flags; if (len != 64) { gpsd_report(LOG_PROG, "ITALK: bad UTC_IONO_MODEL (len %zu, should be 64)\n", len); return 0; } flags = (ushort) getleu16(buf, 7); if (0 == (flags & UTC_IONO_MODEL_UTCVALID)) return 0; leap = (int)getleu16(buf, 7 + 24); if (session->context->leap_seconds < leap) session->context->leap_seconds = leap; session->newdata.time = gpsd_gpstime_resolve(session, (unsigned short) getleu16(buf, 7 + 36), (unsigned int)getleu32(buf, 7 + 38) / 1000.0); gpsd_report(LOG_DATA, "UTC_IONO_MODEL: time=%.2f mask={TIME}\n", session->newdata.time); return TIME_SET | PPSTIME_IS; }
static int ntrip_stream_req_probe(const struct ntrip_stream_t *stream, const int debug) { int dsock; ssize_t r; char buf[BUFSIZ]; dsock = netlib_connectsock(AF_UNSPEC, stream->url, stream->port, "tcp"); if (dsock < 0) { gpsd_report(debug, LOG_ERROR, "ntrip stream connect error %d in req probe\n", dsock); return -1; } gpsd_report(debug, LOG_SPIN, "ntrip stream for req probe connected on fd %d\n", dsock); (void)snprintf(buf, sizeof(buf), "GET / HTTP/1.1\r\n" "User-Agent: NTRIP gpsd/%s\r\n" "Host: %s\r\n" "Connection: close\r\n" "\r\n", VERSION, stream->url); r = write(dsock, buf, strlen(buf)); if (r != (ssize_t)strlen(buf)) { gpsd_report(debug, LOG_ERROR, "ntrip stream write error %d on fd %d during probe request %zd\n", errno, dsock, r); (void)close(dsock); return -1; } /* coverity[leaked_handle] This is an intentional allocation */ return dsock; }
int ntpshm_pps(struct gps_device_t *session, struct timeval *tv) { struct shmTime *shmTime = NULL, *shmTimeP = NULL; time_t seconds; double offset; long l_offset; if (session->shmindex < 0 || session->shmTimeP < 0 || (shmTime = session->context->shmTime[session->shmindex]) == NULL || (shmTimeP = session->context->shmTime[session->shmTimeP]) == NULL) return 0; /* check if received time messages are within locking range */ #ifdef S_SPLINT_S /* avoids an internal error in splint 3.1.1 */ l_offset = 0; #else l_offset = shmTime->receiveTimeStampSec - shmTime->clockTimeStampSec; #endif /*@ -ignorequals @*/ l_offset *= 1000000; l_offset += shmTime->receiveTimeStampUSec - shmTime->clockTimeStampUSec; /*@ +ignorequals @*/ if (labs( l_offset ) > PUT_MAX_OFFSET) { gpsd_report(LOG_RAW, "ntpshm_pps: not in locking range: %ld\n" , (long)l_offset); return -1; } /*@ -ignorequals @*/ if (tv->tv_usec < PPS_MAX_OFFSET) { seconds = (time_t)tv->tv_sec; offset = (double)tv->tv_usec / 1000000.0; } else { if (tv->tv_usec > (1000000 - PPS_MAX_OFFSET)) { seconds = (time_t)(tv->tv_sec + 1); offset = 1 - ((double)tv->tv_usec / 1000000.0); } else { shmTimeP->precision = -1; /* lost lock */ gpsd_report(LOG_INF, "ntpshm_pps: lost PPS lock\n"); return -1; } } shmTimeP->count++; shmTimeP->clockTimeStampSec = seconds; shmTimeP->clockTimeStampUSec = 0; shmTimeP->receiveTimeStampSec = (time_t)tv->tv_sec; shmTimeP->receiveTimeStampUSec = tv->tv_usec; shmTimeP->precision = offset != 0 ? (int)(ceil(log(offset) / M_LN2)) : -20; shmTimeP->count++; shmTimeP->valid = 1; gpsd_report(LOG_RAW, "ntpshm_pps: clock: %lu @ %lu.%06lu, precision %d\n" , (unsigned long)seconds, (unsigned long)tv->tv_sec , (unsigned long)tv->tv_usec, shmTimeP->precision); return 1; }
/*@ -branchstate @*/ int ntrip_open(struct gps_context_t *context, char *caster) /* open a connection to a Ntrip broadcaster */ { char *amp, *colon, *slash; char *auth = NULL; char *port = NULL; char *stream = NULL; int ret; /*@ -boolops @*/ if ((amp = strchr(caster, '@')) != NULL) { if (((colon = strchr(caster, ':')) != NULL) && colon < amp) { auth = caster; *amp = '\0'; caster = amp + 1; } else { gpsd_report(LOG_ERROR, "can't extract user-ID and password from %s\n", caster); return -1; } } /*@ +boolops @*/ if ((slash = strchr(caster, '/')) != NULL) { *slash = '\0'; stream = slash + 1; } else { /* todo: add autoconnect like in dgpsip.c */ gpsd_report(LOG_ERROR, "can't extract Ntrip stream from %s\n", caster); return -1; } if ((colon = strchr(caster, ':')) != NULL) { port = colon + 1; *colon = '\0'; } if (!port) { port = "rtcm-sc104"; if (!getservbyname(port, "tcp")) port = DEFAULT_RTCM_PORT; } if (ntrip_stream_probe(caster, port, stream, &ntrip_stream)) { gpsd_report(LOG_ERROR, "unable to probe for data about stream %s:%s/%s\n", caster, port, stream); return -1; } ret = ntrip_stream_open(caster, port, auth, context, &ntrip_stream); if (ret >= 0) gpsd_report(LOG_PROG, "connection to Ntrip broadcaster %s established.\n", caster); else gpsd_report(LOG_ERROR, "can't connect to Ntrip stream %s:%s/%s.\n", caster, port, stream); return ret; }
static void onsig(int sig) { if (sig == SIGALRM) { gpsd_report(LOG_ERROR, "packet recognition timed out.\n"); exit(1); } else { gpsd_report(LOG_ERROR, "killed by signal %d\n", sig); exit(0); } }
static void evermore_configurator(struct gps_device_t *session, unsigned int seq) { gpsd_report(LOG_PROG, "evermore_configurator(%d)\n", seq); (void) evermore_nmea_config(session, 1); /* configure NMEA messages for gpsd (GPGSV every 5s) */ if (seq == 0) { if (session->packet.type == NMEA_PACKET) { gpsd_report(LOG_WARN, "NMEA_PACKET packet\n"); } (void) evermore_mode(session, 1); /* switch GPS to binary mode */ session->back_to_nmea = true; } }
static gps_mask_t decode_itk_prnstatus(struct gps_device_t *session, unsigned char *buf, size_t len) { gps_mask_t mask; if (len < 62) { gpsd_report(&session->context->errout, LOG_PROG, "ITALK: runt PRN_STATUS (len=%zu)\n", len); mask = 0; } else { unsigned int i, nsv, nchan, st; session->gpsdata.skyview_time = gpsd_gpstime_resolve(session, (unsigned short)getleu16(buf, 7 + 4), (unsigned int)getleu32(buf, 7 + 6) / 1000.0), gpsd_zero_satellites(&session->gpsdata); nsv = 0; nchan = (unsigned int)getleu16(buf, 7 + 50); if (nchan > MAX_NR_VISIBLE_PRNS) nchan = MAX_NR_VISIBLE_PRNS; for (i = st = 0; i < nchan; i++) { unsigned int off = 7 + 52 + 10 * i; unsigned short flags; bool used; flags = (unsigned short) getleu16(buf, off); used = flags & PRN_FLAG_USE_IN_NAV; session->gpsdata.skyview[i].ss = (float)(getleu16(buf, off + 2) & 0xff); session->gpsdata.skyview[i].PRN = (int)getleu16(buf, off + 4) & 0xff; session->gpsdata.skyview[i].elevation = (int)getles16(buf, off + 6) & 0xff; session->gpsdata.skyview[i].azimuth = (int)getles16(buf, off + 8) & 0xff; session->gpsdata.skyview[i].used = used; if (session->gpsdata.skyview[i].PRN > 0) { st++; if (used) session->sats_used[nsv++] = session->gpsdata.skyview[i].PRN; } } session->gpsdata.satellites_visible = (int)st; session->gpsdata.satellites_used = (int)nsv; mask = USED_IS | SATELLITE_SET;; gpsd_report(&session->context->errout, LOG_DATA, "PRN_STATUS: time=%.2f visible=%d used=%d mask={USED|SATELLITE}\n", session->newdata.time, session->gpsdata.satellites_visible, session->gpsdata.satellites_used); } return mask; }
static int ntrip_stream_get_parse(const struct ntrip_stream_t *stream, const int dsock, const int debug) { /*@-nullpass@*/ char buf[BUFSIZ]; int opts; memset(buf, 0, sizeof(buf)); while (read(dsock, buf, sizeof(buf) - 1) == -1) { if (errno == EINTR) continue; gpsd_report(debug, LOG_ERROR, "ntrip stream read error %d on fd %d during get rsp\n", errno, dsock); goto close; } /* parse 401 Unauthorized */ /* coverity[string_null] - guaranteed terminated by the memset above */ if (strstr(buf, NTRIP_UNAUTH)!=NULL) { gpsd_report(debug, LOG_ERROR, "not authorized for Ntrip stream %s/%s\n", stream->url, stream->mountpoint); goto close; } /* parse SOURCETABLE */ if (strstr(buf, NTRIP_SOURCETABLE)!=NULL) { gpsd_report(debug, LOG_ERROR, "Broadcaster doesn't recognize Ntrip stream %s:%s/%s\n", stream->url, stream->port, stream->mountpoint); goto close; } /* parse ICY 200 OK */ if (strstr(buf, NTRIP_ICY)==NULL) { gpsd_report(debug, LOG_ERROR, "Unknown reply %s from Ntrip service %s:%s/%s\n", buf, stream->url, stream->port, stream->mountpoint); goto close; } opts = fcntl(dsock, F_GETFL); if (opts >= 0) (void)fcntl(dsock, F_SETFL, opts | O_NONBLOCK); return dsock; close: (void)close(dsock); return -1; /*@+nullpass@*/ }
void gpsd_close(struct gps_device_t *session) { if (session->gpsdata.gps_fd != -1) { (void)tcdrain(session->gpsdata.gps_fd); if (isatty(session->gpsdata.gps_fd) != 0) { /* force hangup on close on systems that don't do HUPCL properly */ /*@ ignore @*/ (void)cfsetispeed(&session->ttyset, (speed_t) B0); (void)cfsetospeed(&session->ttyset, (speed_t) B0); /*@ end @*/ (void)tcsetattr(session->gpsdata.gps_fd, TCSANOW, &session->ttyset); } /* this is the clean way to do it */ session->ttyset_old.c_cflag |= HUPCL; /* keep the most recent baud rate */ /*@ ignore @*/ (void)cfsetispeed(&session->ttyset_old, (speed_t) session->gpsdata.dev.baudrate); (void)cfsetospeed(&session->ttyset_old, (speed_t) session->gpsdata.dev.baudrate); /*@ end @*/ (void)tcsetattr(session->gpsdata.gps_fd, TCSANOW, &session->ttyset_old); gpsd_report(LOG_SPIN, "close(%d) in gpsd_close(%s)\n", session->gpsdata.gps_fd, session->gpsdata.dev.path); (void)close(session->gpsdata.gps_fd); session->gpsdata.gps_fd = -1; } }
timestamp_t gpsd_utc_resolve(/*@in@*/struct gps_device_t *session) /* resolve a UTC date, checking for rollovers */ { /* * We'd like to *correct* for rollover the way we do for GPS week. * In theory, comparing extracted UTC against present time should * allow us to compute the device's epoch assumption. In practice, * this will be hairy and risky. */ timestamp_t t; t = (timestamp_t)mkgmtime(&session->driver.nmea.date) + session->driver.nmea.subseconds; session->context->valid &=~ GPS_TIME_VALID; /* * If the system clock is zero or has a small-integer value, * no further sanity-checking is possible. */ if (session->context->start_time < GPS_EPOCH) return t; /* * If the GPS is reporting a time from before the daemon started, we've * had a rollover event while the daemon was running. */ if (session->newdata.time < (timestamp_t)session->context->start_time) { char scr[128]; (void)unix_to_iso8601(session->newdata.time, scr, sizeof(scr)); gpsd_report(LOG_WARN, "GPS week rollover makes time %s (%f) invalid\n", scr, session->newdata.time); } return t; }
/*@ -branchstate */ int netgnss_uri_open(struct gps_device_t *dev, char *netgnss_service) /* open a connection to a DGNSS service */ { #ifdef NTRIP_ENABLE if (strncmp(netgnss_service, NETGNSS_NTRIP, strlen(NETGNSS_NTRIP)) == 0) { dev->ntrip.conn_state = ntrip_conn_init; return ntrip_open(dev, netgnss_service + strlen(NETGNSS_NTRIP)); } #endif if (strncmp(netgnss_service, NETGNSS_DGPSIP, strlen(NETGNSS_DGPSIP)) == 0) return dgpsip_open(dev, netgnss_service + strlen(NETGNSS_DGPSIP)); if (strncmp(netgnss_service, NETGNSS_UDP, strlen(NETGNSS_UDP)) == 0) return udp_open(dev, netgnss_service + strlen(NETGNSS_UDP)); #ifndef REQUIRE_DGNSS_PROTO return dgpsip_open(dev, netgnss_service); #else gpsd_report(LOG_ERROR, "Unknown or unspecified DGNSS protocol for service %s\n", netgnss_service); return -1; #endif }
/*@ -temptrans -mustfreefresh @*/ static /*@null@*/ char *ntrip_field_iterate( /*@null@ */ char *start, /*@null@*/ char *prev, const char *eol, const int debug) { char *s, *t, *u; if (start) s = start; else { if (!prev) return NULL; s = prev + strlen(prev) + 1; if (s >= eol) return NULL; } /* ignore any quoted ; chars as they are part of the field content */ t = s; while ((u = strstr(t, NTRIP_QSC))) t = u + strlen(NTRIP_QSC); if ((t = strstr(t, ";"))) *t = '\0'; gpsd_report(debug, LOG_RAW, "Next Ntrip source table field %s\n", s); return s; }
/* offset is actual_ts - clock_ts */ static void chrony_send(struct gps_device_t *session, struct timedrift_t *td) { struct sock_sample sample; /* chrony expects tv-sec since Jan 1970 */ sample.pulse = 0; sample.leap = session->context->leap_notify; sample.magic = SOCK_MAGIC; /*@-type@*//* splint is confused about struct timespec */ TSTOTV(&sample.tv, &td->clock); /*@-compdef@*/ sample.offset = timespec_diff_ns(td->real, td->clock) / 1e9; /*@+compdef@*/ #ifdef __COVERITY__ sample._pad = 0; #endif /* __COVERITY__ */ /*@+type@*/ /*@-type@*/ /* splint is confused about struct timespec */ gpsd_report(&session->context->errout, LOG_RAW, "PPS chrony_send %lu.%09lu @ %lu.%09lu Offset: %0.9f\n", (unsigned long)td->real.tv_sec, (unsigned long)td->real.tv_nsec, (unsigned long)td->clock.tv_sec, (unsigned long)td->clock.tv_nsec, sample.offset); /*@+type@*/ (void)send(session->chronyfd, &sample, sizeof (sample), 0); }
ssize_t gpsd_serial_write(struct gps_device_t * session, const char *buf, const size_t len) { ssize_t status; int error = 0; bool ok; /* if (session == NULL || session->context == NULL || session->context->readonly) return 0; */ status = write(session->gpsdata.gps_fd, buf, len); ok = (status == (ssize_t) len); session->gpsdata.bytes_send += status; if(!ok) error = errno; (void)tcdrain(session->gpsdata.gps_fd); /* extra guard prevents expensive hexdump calls */ if (session->context->debug >= LOG_IO) { char scratchbuf[MAX_PACKET_LENGTH*2+1]; gpsd_report(session->context->debug, LOG_IO, "=> GPS: %s%s (%d, %d)\n", gpsd_packetdump(scratchbuf, sizeof(scratchbuf), (char *)buf, len), ok ? "" : " FAILED", status, error); } return status; }
static bool evermore_nmea_config(struct gps_device_t *session, int mode) /* mode = 0 : EverMore default */ /* mode = 1 : gpsd best */ /* mode = 2 : EverMore search, activate PEMT101 message */ { unsigned char tmp8; /*@ +charint */ unsigned char evrm_nmeaout_config[] = { 0x8e, /* 0: msg ID, NMEA Message Control */ 0xff, /* 1: NMEA sentence bitmask, GGA(0), GLL(1), GSA(2), GSV(3), ... */ 0x01, /* 2: nmea checksum no(0), yes(1) */ 1, /* 3: GPGGA, interval 0-255s */ 0, /* 4: GPGLL, interval 0-255s */ 1, /* 5: GPGSA, interval 0-255s */ 1, /* 6: GPGSV, interval 0-255s */ 1, /* 7: GPRMC, interval 0-255s */ 0, /* 8: GPVTG, interval 0-255s */ 0, /* 9: PEMT,101, interval 0-255s */ 0, 0, 0, 0, 0, 0, /* 10-15: reserved */ }; /*@ -charint */ gpsd_report(LOG_PROG, "evermore_nmea_config(%d)\n", mode); /*@i1@*/tmp8 = (mode == 1) ? 5 : 1; /* NMEA GPGSV, gpsd */ evrm_nmeaout_config[6] = tmp8; /* GPGSV, 1s or 5s */ /*@i1@*/tmp8 = (mode == 2) ? 1 : 0; /* NMEA PEMT101 */ evrm_nmeaout_config[9] = tmp8; /* PEMT101, 1s or 0s */ return evermore_write(session, evrm_nmeaout_config, sizeof(evrm_nmeaout_config)); }
gps_mask_t generic_parse_input(struct gps_device_t *session) { const struct gps_type_t **dp; if (session->packet.type == COMMENT_PACKET) { gpsd_set_century(session); return 0; #ifdef NMEA_ENABLE } else if (session->packet.type == NMEA_PACKET) { gps_mask_t st = 0; char *sentence = (char *)session->packet.outbuffer; if (sentence[strlen(sentence)-1] != '\n') gpsd_report(LOG_IO, "<= GPS: %s\n", sentence); else gpsd_report(LOG_IO, "<= GPS: %s", sentence); if ((st=nmea_parse(sentence, session)) == 0) { gpsd_report(LOG_WARN, "unknown sentence: \"%s\"\n", sentence); } for (dp = gpsd_drivers; *dp; dp++) { char *trigger = (*dp)->trigger; if (trigger!=NULL && strncmp(sentence,trigger,strlen(trigger))==0) { gpsd_report(LOG_PROG, "found trigger string %s.\n", trigger); if (*dp != session->device_type) { (void)gpsd_switch_driver(session, (*dp)->type_name); if (session->device_type != NULL && session->device_type->event_hook != NULL) session->device_type->event_hook(session, event_triggermatch); st |= DEVICEID_SET; } } } return st; #endif /* NMEA_ENABLE */ } else { for (dp = gpsd_drivers; *dp; dp++) { if (session->packet.type == (*dp)->packet_type) { (void)gpsd_switch_driver(session, (*dp)->type_name); return (*dp)->parse_packet(session); } } return 0; } }
static /*@null@*/ struct shmTime *getShmTime(int unit) { int shmid=shmget ((key_t)(NTPD_BASE+unit), sizeof (struct shmTime), IPC_CREAT|0644); if (shmid == -1) { gpsd_report(LOG_ERROR, "shmget failed\n"); return NULL; } else { struct shmTime *p=(struct shmTime *)shmat (shmid, 0, 0); /*@ -mustfreefresh */ if ((int)(long)p == -1) { gpsd_report(LOG_ERROR, "shmat failed\n"); return NULL; } gpsd_report(LOG_PROG, "shmat(%d,0,0) succeeded\n"); return p; /*@ +mustfreefresh */ } }
static bool tnt_send(struct gps_device_t *session, const char *fmt, ...) /* printf(3)-like TNT command generator */ { char buf[BUFSIZ]; va_list ap; ssize_t sent; va_start(ap, fmt); (void)vsnprintf(buf, sizeof(buf) - 5, fmt, ap); va_end(ap); sent = tnt_control_send(session, buf, strlen(buf)); if (sent == (ssize_t) strlen(buf)) { gpsd_report(LOG_IO, "=> GPS: %s\n", buf); return true; } else { gpsd_report(LOG_WARN, "=> GPS: %s FAILED\n", buf); return false; } }
void pps_thread_activate(struct gps_device_t *session) /* activate a thread to watch the device's PPS transitions */ { int retval; pthread_t pt; #if defined(HAVE_SYS_TIMEPPS_H) /* some operations in init_kernel_pps() require root privs */ (void)init_kernel_pps( session ); if ( 0 <= session->kernelpps_handle ) { gpsd_report(session->context->debug, LOG_WARN, "KPPS kernel PPS will be used\n"); } #endif /*@-compdef -nullpass@*/ retval = pthread_create(&pt, NULL, gpsd_ppsmonitor, (void *)session); /*@+compdef +nullpass@*/ gpsd_report(session->context->debug, LOG_PROG, "PPS thread %s\n", (retval==0) ? "launched" : "FAILED"); }
static gps_mask_t decode_itk_pseudo(struct gps_device_t *session, unsigned char *buf, size_t len) { unsigned short flags, n, i; union long_double l_d; n = (ushort) getleu16(buf, 7 + 4); if ((n < 1) || (n > MAXCHANNELS)){ gpsd_report(LOG_INF, "ITALK: bad PSEUDO channel count\n"); return 0; } if (len != (size_t)((n+1)*36)) { gpsd_report(LOG_PROG, "ITALK: bad PSEUDO len %zu\n", len); } gpsd_report(LOG_PROG, "iTalk PSEUDO [%u]\n", n); flags = (unsigned short)getleu16(buf, 7 + 6); if ((flags & 0x3) != 0x3) return 0; // bail if measurement time not valid. session->newdata.time = gpsd_gpstime_resolve(session, (unsigned short int) getleu16(buf, 7 + 8), (unsigned int)getleu32(buf, 7 + 38) / 1000.0); /*@-type@*/ for (i = 0; i < n; i++){ session->gpsdata.PRN[i] = getleu16(buf, 7 + 26 + (i*36)) & 0xff; session->gpsdata.ss[i] = getleu16(buf, 7 + 26 + (i*36 + 2)) & 0x3f; session->gpsdata.raw.satstat[i] = getleu32(buf, 7 + 26 + (i*36 + 4)); session->gpsdata.raw.pseudorange[i] = getled(buf, 7 + 26 + (i*36 + 8)); session->gpsdata.raw.doppler[i] = getled(buf, 7 + 26 + (i*36 + 16)); session->gpsdata.raw.carrierphase[i] = getleu16(buf, 7 + 26 + (i*36 + 28)); session->gpsdata.raw.mtime[i] = session->newdata.time; session->gpsdata.raw.codephase[i] = NAN; session->gpsdata.raw.deltarange[i] = NAN; } /*@+type@*/ return RAW_IS; }
void gpsd_time_init(struct gps_context_t *context, time_t starttime) /* initialize the GPS context's time fields */ { /* * gpsd can't work with 'right' timezones (leapseconds inserted in * the timezone offset). Avoid this and all manner of other local * time issues by telling the system we want times returned in UTC. */ /*@-observertrans@*/ (void)putenv("TZ=UTC"); /*@+observertrans@*/ /* * Provides a start time for getting the century. Do this, just * in case one of our embedded deployments is still in place in * the year 2.1K. Still likely to fail if we bring up the daemon * just before a century mark, but that case is probably doomed * anyhow because of 2-digit years. */ context->leap_seconds = LEAPSECOND_NOW; context->century = CENTURY_BASE; context->start_time = starttime; context->rollovers = (int)((context->start_time-GPS_EPOCH) / GPS_ROLLOVER); if (context->start_time < GPS_EPOCH) gpsd_report(LOG_ERROR, "system time looks bogus, dates may not be reliable.\n"); else { /* we've forced the UTC timezone, so this is actually UTC */ struct tm *now = localtime(&context->start_time); char scr[128]; /* * This is going to break our regression-test suite once a century. * I think we can live with that consequence. */ now->tm_year += 1900; context->century = now->tm_year - (now->tm_year % 100); (void)unix_to_iso8601((timestamp_t)context->start_time, scr, sizeof(scr)); gpsd_report(LOG_INF, "startup at %s (%d)\n", scr, (int)context->start_time); } }
/* Note: you can start gpsd as non-root, and have it work with ntpd. * However, it will then only use the ntpshm segments 2 and 3. * * Ntpd always runs as root (to be able to control the system clock). * Its logics for the creation of ntpshm segments are: * * Segments 0 and 1: permissions 0600, i.e. other programs can only * read and write as root. * * Segments 2 and 3: permissions 0666, i.e. other programs can read * and write as any user. I.e.: if ntpd has been * configured to use these segments, any * unpriviliged user is allowed to provide data * for synchronisation. * * As gpsd can be started as both root and non-root, this behaviour is * mimicked by: * * Started as root: do as ntpd when attaching (creating) the segments. * (In contrast to ntpd, which only attaches (creates) configured * segments, gpsd creates all segments.) * * Started as non-root: only attach (create) segments 2 and 3 with * permissions 0666. As the permissions are for any user, the creator * does not matter. * * For each GPS module gpsd controls, it will use the attached ntpshm * segments in pairs (for coarse clock and pps source, respectively) * starting from the first found segments. I.e. started as root, one * GPS will deliver data on segments 0 and 1, and as non-root data * will be delivered on segments 2 and 3. * * to debug, try looking at the live segments this way * * ipcs -m * * results should look like this: * ------ Shared Memory Segments -------- * key shmid owner perms bytes nattch status * 0x4e545030 0 root 700 96 2 * 0x4e545031 32769 root 700 96 2 * 0x4e545032 163842 root 666 96 1 * 0x4e545033 196611 root 666 96 1 * * For a bit more data try this: * cat /proc/sysvipc/shm * * If gpsd can not open the segments be sure you are not running SELinux * or apparmor. * * if you see the shared segments (keys 1314148400 -- 1314148403), and * no gpsd or ntpd is running then try removing them like this: * * ipcrm -M 0x4e545030 * ipcrm -M 0x4e545031 * ipcrm -M 0x4e545032 * ipcrm -M 0x4e545033 */ static /*@null@*/ volatile struct shmTime *getShmTime(struct gps_context_t *context, int unit) { int shmid; unsigned int perms; volatile struct shmTime *p; // set the SHM perms the way ntpd does if (unit < 2) { // we are root, be careful perms = 0600; } else { // we are not root, try to work anyway perms = 0666; } /* * Note: this call requires root under BSD, and possibly on * well-secured Linux systems. This is why ntpshm_context_init() has to be * called before privilege-dropping. */ shmid = shmget((key_t) (NTPD_BASE + unit), sizeof(struct shmTime), (int)(IPC_CREAT | perms)); if (shmid == -1) { gpsd_report(&context->errout, LOG_ERROR, "NTPD shmget(%ld, %zd, %o) fail: %s\n", (long int)(NTPD_BASE + unit), sizeof(struct shmTime), (int)perms, strerror(errno)); return NULL; } p = (struct shmTime *)shmat(shmid, 0, 0); /*@ -mustfreefresh */ if ((int)(long)p == -1) { gpsd_report(&context->errout, LOG_ERROR, "NTPD shmat failed: %s\n", strerror(errno)); return NULL; } gpsd_report(&context->errout, LOG_PROG, "NTPD shmat(%d,0,0) succeeded, segment %d\n", shmid, unit); return p; /*@ +mustfreefresh */ }
bool gpsd_set_raw(struct gps_device_t * session) { (void)cfmakeraw(&session->ttyset); if (tcsetattr(session->gpsdata.gps_fd, TCIOFLUSH, &session->ttyset) == -1) { gpsd_report(LOG_ERROR, "error changing port attributes: %s\n", strerror(errno)); return false; } return true; }