register struct nmeaunit *up;
struct refclockproc *pp;
struct peer *peer;
- int month, day;
char *cp, *dp, *msg;
- int cmdtype;
- int cmdtypezdg = 0;
+ u_char sentence;
/* Use these variables to hold data until we decide its worth keeping */
char rd_lastcode[BMAX];
- l_fp rd_timestamp;
+ l_fp rd_timestamp, reftime;
int rd_lencode;
+ double rd_fudge;
+ struct calendar date;
/*
* Initialize pointers and read the timecode and timestamp
msg = cp + 3;
if (strncmp(msg, "RMC", 3) == 0)
- cmdtype = GPRMC;
+ sentence = NMEA_GPRMC;
else if (strncmp(msg, "GGA", 3) == 0)
- cmdtype = GPGGA;
+ sentence = NMEA_GPGGA;
else if (strncmp(msg, "GLL", 3) == 0)
- cmdtype = GPGLL;
- else if (strncmp(msg, "ZD", 2) == 0) {
- cmdtype = GPZDG_ZDA;
- if ('G' == msg[2])
- cmdtypezdg = 1;
- else if ('A' != msg[2])
- return;
- } else
+ sentence = NMEA_GPGLL;
- else if (strncmp(msg, "ZD", 2) == 0) {
- if ('G' == msg[2])
- sentence = NMEA_GPZDG;
- else if ('A' == msg[2])
- sentence = NMEA_GPZDA;
- else
- return;
- } else
++ else if (strncmp(msg, "ZDG", 3) == 0)
++ sentence = NMEA_GPZDG;
++ else if (strncmp(msg, "ZDA", 3) == 0)
++ sentence = NMEA_GPZDA;
++ else
return;
} else
return;
DPRINTF(1, ("nmea: timecode %d %s\n", pp->lencode, pp->a_lastcode));
/* Grab field depending on clock string type */
- switch (cmdtype) {
+ memset(&date, 0, sizeof(date));
+ switch (sentence) {
- case GPRMC:
+ case NMEA_GPRMC:
/*
* Test for synchronization. Check for quality byte.
*/
/*
* Convert date and check values.
*/
- if (GPRMC == cmdtype) {
+ if (NMEA_GPRMC == sentence) {
dp = field_parse(cp,9);
- day = dp[0] - '0';
- day = (day * 10) + dp[1] - '0';
- month = dp[2] - '0';
- month = (month * 10) + dp[3] - '0';
- pp->year = dp[4] - '0';
- pp->year = (pp->year * 10) + dp[5] - '0';
+ date.monthday = 10 * (dp[0] - '0') + (dp[1] - '0');
+ date.month = 10 * (dp[2] - '0') + (dp[3] - '0');
+ date.year = 10 * (dp[4] - '0') + (dp[5] - '0');
+ nmea_century_unfold(&date);
- } else if (GPZDG_ZDA == cmdtype) {
+ } else if (NMEA_GPZDA == sentence || NMEA_GPZDG == sentence) {
dp = field_parse(cp, 2);
- day = 10 * (dp[0] - '0') + (dp[1] - '0');
+ date.monthday = 10 * (dp[0] - '0') + (dp[1] - '0');
dp = field_parse(cp, 3);
- month = 10 * (dp[0] - '0') + (dp[1] - '0');
+ date.month = 10 * (dp[0] - '0') + (dp[1] - '0');
dp = field_parse(cp, 4);
- pp->year = /* 1000 * (dp[0] - '0') + 100 * (dp[1] - '0') + */ 10 * (dp[2] - '0') + (dp[3] - '0');
-
- } else {
- /* only time */
- time_t tt = time(NULL);
- struct tm * t = gmtime(&tt);
- day = t->tm_mday;
- month = t->tm_mon + 1;
- pp->year= t->tm_year + 1900;
- }
+ date.year = 1000 * (dp[0] - '0') + 100 * (dp[1] - '0')
+ + 10 * (dp[2] - '0') + (dp[3] - '0');
- if (month < 1 || month > 12 || day < 1) {
- refclock_report(peer, CEVNT_BADDATE);
- return;
- }
-
- /* pp->year will be 2 or 4 digits if read from GPS, 4 from gmtime */
- if (pp->year < 100) {
- if (pp->year < 9) /* year of our line of code is 2009 */
- pp->year += 2100;
- else
- pp->year += 2000;
- }
+ } else
+ nmea_day_unfold(&date);
- /* pp->year now 4 digits as ymd2yd requires */
- day = ymd2yd(pp->year, month, day);
- if (-1 == day) {
+ if (date.month < 1 || date.month > 12 ||
+ date.monthday < 1 || date.monthday > 31) {
refclock_report(peer, CEVNT_BADDATE);
return;
}
}
/*
- * Note if we're only using GPS timescale from now on.
+ * Get the reference time stamp from the calendar buffer.
+ * Process the new sample in the median filter and determine
+ * the timecode timestamp, but only if the PPS is not in
+ * control.
*/
- if (!up->gps_time && NMEA_GPZDG == sentence) {
- up->gps_time = 1;
- NLOG(NLOG_CLOCKINFO)
+ rd_fudge = pp->fudgetime2;
+ date.yearday = 0; /* make sure it's not used */
+ DTOLFP(pp->nsec * 1.0e-9, &reftime);
+ reftime.l_ui += caltontp(&date);
+
+ /* $GPZDG postprocessing first... */
- if (cmdtypezdg) {
++ if (NMEA_GPZDG == sentence) {
+ /*
+ * Note if we're only using GPS timescale from now on.
+ */
+ if (!up->gps_time) {
+ up->gps_time = 1;
+ NLOG(NLOG_CLOCKINFO)
msyslog(LOG_INFO, "%s using only $GPZDG",
refnumtoa(&peer->srcadr));
+ }
+ /*
+ * $GPZDG indicates the second after the *next* PPS
+ * pulse. So we remove 1 second from the reference
+ * time now.
+ */
+ reftime.l_ui--;
}
- /*
- * Process the new sample in the median filter and determine the
- * timecode timestamp, but only if the PPS is not in control.
- */
#ifdef HAVE_PPSAPI
up->tcount++;
- if (peer->flags & FLAG_PPS)
+ /*
+ * If we have PPS running, we try to associate the sentence with the last
+ * active edge of the PPS signal.
+ */
+ if (up->ppsapi_lit)
+ switch(refclock_ppsrelate(pp, &up->atom, &reftime,
+ &rd_timestamp, pp->fudgetime1,
+ &rd_fudge))
+ {
+ case PPS_RELATE_EDGE:
+ up->ppsapi_gate = 0;
+ break;
+ case PPS_RELATE_PHASE:
+ up->ppsapi_gate = 1;
+ break;
+ default:
+ break;
+ }
+ else
+ up->ppsapi_gate = 0;
+
+ if (up->ppsapi_gate && (peer->flags & FLAG_PPS))
return;
#endif /* HAVE_PPSAPI */
- if (!refclock_process_f(pp, pp->fudgetime2))
- refclock_report(peer, CEVNT_BADTIME);
+
+ refclock_process_offset(pp, reftime, rd_timestamp, rd_fudge);
}