/* * pcf_poll - called by the transmit procedure */ static void pcf_poll( int unit, struct peer *peer ) { struct refclockproc *pp; char buf[LENPCF]; struct tm tm, *tp; time_t t; pp = peer->procptr; buf[0] = 0; if (read(pp->io.fd, buf, sizeof(buf)) < sizeof(buf) || buf[0] != 9) { refclock_report(peer, CEVNT_FAULT); return; } ZERO(tm); tm.tm_mday = buf[11] * 10 + buf[10]; tm.tm_mon = buf[13] * 10 + buf[12] - 1; tm.tm_year = buf[15] * 10 + buf[14]; tm.tm_hour = buf[7] * 10 + buf[6]; tm.tm_min = buf[5] * 10 + buf[4]; tm.tm_sec = buf[3] * 10 + buf[2]; tm.tm_isdst = (buf[8] & 1) ? 1 : (buf[8] & 2) ? 0 : -1; /* * Y2K convert the 2-digit year */ if (tm.tm_year < 99) tm.tm_year += 100; t = mktime(&tm); if (t == (time_t) -1) { refclock_report(peer, CEVNT_BADTIME); return; } #if defined(__GLIBC__) && defined(_BSD_SOURCE) if ((tm.tm_isdst > 0 && tm.tm_gmtoff != 7200) || (tm.tm_isdst == 0 && tm.tm_gmtoff != 3600) || tm.tm_isdst < 0) { #ifdef DEBUG if (debug) printf ("local time zone not set to CET/CEST\n"); #endif refclock_report(peer, CEVNT_BADTIME); return; } #endif pp->lencode = strftime(pp->a_lastcode, BMAX, "%Y %m %d %H %M %S", &tm); #if defined(_REENTRANT) || defined(_THREAD_SAFE) tp = gmtime_r(&t, &tm); #else tp = gmtime(&t); #endif if (!tp) { refclock_report(peer, CEVNT_FAULT); return; } get_systime(&pp->lastrec); pp->polls++; pp->year = tp->tm_year + 1900; pp->day = tp->tm_yday + 1; pp->hour = tp->tm_hour; pp->minute = tp->tm_min; pp->second = tp->tm_sec; pp->nsec = buf[16] * 31250000; if (buf[17] & 1) pp->nsec += 500000000; #ifdef DEBUG if (debug) printf ("pcf%d: time is %04d/%02d/%02d %02d:%02d:%02d UTC\n", unit, pp->year, tp->tm_mon + 1, tp->tm_mday, pp->hour, pp->minute, pp->second); #endif if (!refclock_process(pp)) { refclock_report(peer, CEVNT_BADTIME); return; } record_clock_stats(&peer->srcadr, pp->a_lastcode); if ((buf[1] & 1) && !(pp->sloppyclockflag & CLK_FLAG2)) pp->leap = LEAP_NOTINSYNC; else pp->leap = LEAP_NOWARNING; pp->lastref = pp->lastrec; refclock_receive(peer); }
/* * tpro_poll - called by the transmit procedure */ static void tpro_poll( int unit, struct peer *peer ) { register struct tprounit *up; struct refclockproc *pp; struct tproval *tp; /* * This is the main routine. It snatches the time from the TPRO * board and tacks on a local timestamp. */ pp = peer->procptr; up = pp->unitptr; tp = &up->tprodata; if (read(pp->io.fd, (char *)tp, sizeof(struct tproval)) < 0) { refclock_report(peer, CEVNT_FAULT); return; } get_systime(&pp->lastrec); pp->polls++; /* * We get down to business, check the timecode format and decode * its contents. If the timecode has invalid length or is not in * proper format, we declare bad format and exit. Note: we * can't use the sec/usec conversion produced by the driver, * since the year may be suspect. All format error checking is * done by the snprintf() and sscanf() routines. * * Note that the refclockproc usec member has now become nsec. * We could either multiply the read-in usec value by 1000 or * we could pad the written string appropriately and read the * resulting value in already scaled. */ snprintf(pp->a_lastcode, sizeof(pp->a_lastcode), "%1x%1x%1x %1x%1x:%1x%1x:%1x%1x.%1x%1x%1x%1x%1x%1x %1x", tp->day100, tp->day10, tp->day1, tp->hour10, tp->hour1, tp->min10, tp->min1, tp->sec10, tp->sec1, tp->ms100, tp->ms10, tp->ms1, tp->usec100, tp->usec10, tp->usec1, tp->status); pp->lencode = strlen(pp->a_lastcode); #ifdef DEBUG if (debug) printf("tpro: time %s timecode %d %s\n", ulfptoa(&pp->lastrec, 6), pp->lencode, pp->a_lastcode); #endif if (sscanf(pp->a_lastcode, "%3d %2d:%2d:%2d.%6ld", &pp->day, &pp->hour, &pp->minute, &pp->second, &pp->nsec) != 5) { refclock_report(peer, CEVNT_BADTIME); return; } pp->nsec *= 1000; /* Convert usec to nsec */ if (!tp->status & 0x3) pp->leap = LEAP_NOTINSYNC; else pp->leap = LEAP_NOWARNING; if (!refclock_process(pp)) { refclock_report(peer, CEVNT_BADTIME); return; } if (pp->coderecv == pp->codeproc) { refclock_report(peer, CEVNT_TIMEOUT); return; } pp->lastref = pp->lastrec; record_clock_stats(&peer->srcadr, pp->a_lastcode); refclock_receive(peer); }
/* * hopfpci_poll - called by the transmit procedure */ static void hopfpci_poll( int unit, struct peer *peer ) { struct refclockproc *pp; HOPFTIME m_time; pp = peer->procptr; #ifndef SYS_WINNT if (ioctl(fd, HOPF_CLOCK_GET_UTC, &m_time) < 0) msyslog(LOG_ERR, "HOPF_P(%d): HOPF_CLOCK_GET_UTC: %m\n", unit); #else GetHopfSystemTime(&m_time); #endif pp->polls++; pp->day = ymd2yd(m_time.wYear,m_time.wMonth,m_time.wDay); pp->hour = m_time.wHour; pp->minute = m_time.wMinute; pp->second = m_time.wSecond; pp->nsec = m_time.wMilliseconds * 1000000; if (m_time.wStatus & LEWAPWAR) pp->leap = LEAP_ADDSECOND; else pp->leap = LEAP_NOWARNING; snprintf(pp->a_lastcode, sizeof(pp->a_lastcode), "ST: %02X T: %02d:%02d:%02d.%03ld D: %02d.%02d.%04d", m_time.wStatus, pp->hour, pp->minute, pp->second, pp->nsec / 1000000, m_time.wDay, m_time.wMonth, m_time.wYear); pp->lencode = (u_short)strlen(pp->a_lastcode); get_systime(&pp->lastrec); /* * If clock has no valid status then report error and exit */ if ((m_time.wStatus & HOPF_OPMODE) == HOPF_INVALID) { /* time ok? */ refclock_report(peer, CEVNT_BADTIME); pp->leap = LEAP_NOTINSYNC; return; } /* * Test if time is running on internal quarz * if CLK_FLAG1 is set, sychronize even if no radio operation */ if ((m_time.wStatus & HOPF_OPMODE) == HOPF_INTERNAL){ if ((pp->sloppyclockflag & CLK_FLAG1) == 0) { refclock_report(peer, CEVNT_BADTIME); pp->leap = LEAP_NOTINSYNC; return; } } if (!refclock_process(pp)) { refclock_report(peer, CEVNT_BADTIME); return; } pp->lastref = pp->lastrec; refclock_receive(peer); record_clock_stats(&peer->srcadr, pp->a_lastcode); return; }
/* * chronolog_receive - receive data from the serial interface */ static void chronolog_receive( struct recvbuf *rbufp ) { struct chronolog_unit *up; struct refclockproc *pp; struct peer *peer; l_fp trtmp; /* arrival timestamp */ int hours; /* hour-of-day */ int minutes; /* minutes-past-the-hour */ int seconds; /* seconds */ int temp; /* int temp */ int got_good; /* got a good time flag */ /* * Initialize pointers and read the timecode and timestamp */ peer = rbufp->recv_peer; pp = peer->procptr; up = pp->unitptr; temp = refclock_gtlin(rbufp, pp->a_lastcode, BMAX, &trtmp); if (temp == 0) { if (up->tcswitch == 0) { up->tcswitch = 1; up->laststamp = trtmp; } else up->tcswitch = 0; return; } pp->lencode = temp; pp->lastrec = up->laststamp; up->laststamp = trtmp; up->tcswitch = 1; #ifdef DEBUG if (debug) printf("chronolog: timecode %d %s\n", pp->lencode, pp->a_lastcode); #endif /* * We get down to business. Check the timecode format and decode * its contents. This code uses the first character to see whether * we're looking at a date or a time. We store data data across * calls since it is transmitted a few seconds ahead of the * timestamp. */ got_good=0; if (sscanf(pp->a_lastcode, "Y %d/%d/%d", &up->year,&up->month,&up->day)) { /* * Y2K convert the 2-digit year */ up->year = up->year >= 69 ? up->year : up->year + 100; return; } if (sscanf(pp->a_lastcode,"Z %02d:%02d:%02d", &hours,&minutes,&seconds) == 3) { #ifdef GET_LOCALTIME struct tm local; struct tm *gmtp; time_t unixtime; int adjyear; int adjmon; /* * Convert to GMT for sites that distribute localtime. This * means we have to do Y2K conversion on the 2-digit year; * otherwise, we get the time wrong. */ memset(&local, 0, sizeof(local)); local.tm_year = up->year; local.tm_mon = up->month-1; local.tm_mday = up->day; local.tm_hour = hours; local.tm_min = minutes; local.tm_sec = seconds; local.tm_isdst = -1; unixtime = mktime (&local); if ((gmtp = gmtime (&unixtime)) == NULL) { refclock_report (peer, CEVNT_FAULT); return; } adjyear = gmtp->tm_year+1900; adjmon = gmtp->tm_mon+1; pp->day = ymd2yd (adjyear, adjmon, gmtp->tm_mday); pp->hour = gmtp->tm_hour; pp->minute = gmtp->tm_min; pp->second = gmtp->tm_sec; #ifdef DEBUG if (debug) printf ("time is %04d/%02d/%02d %02d:%02d:%02d UTC\n", adjyear,adjmon,gmtp->tm_mday,pp->hour,pp->minute, pp->second); #endif #else /* * For more rational sites distributing UTC */ pp->day = ymd2yd(year+1900,month,day); pp->hour = hours; pp->minute = minutes; pp->second = seconds; #endif got_good=1; } if (!got_good) return; /* * Process the new sample in the median filter and determine the * timecode timestamp. */ if (!refclock_process(pp)) { refclock_report(peer, CEVNT_BADTIME); return; } pp->lastref = pp->lastrec; refclock_receive(peer); record_clock_stats(&peer->srcadr, pp->a_lastcode); up->lasthour = (u_char)pp->hour; }
/* * arc_receive - receive data from the serial interface */ static void arc_receive( struct recvbuf *rbufp ) { register struct arcunit *up; struct refclockproc *pp; struct peer *peer; char c; int i, n, wday, month, flags, status; int arc_last_offset; static int quality_average = 0; static int quality_sum = 0; static int quality_polls = 0; /* * Initialize pointers and read the timecode and timestamp */ peer = (struct peer *)rbufp->recv_srcclock; pp = peer->procptr; up = (struct arcunit *)pp->unitptr; /* If the command buffer is empty, and we are resyncing, insert a g\r quality request into it to poll for signal quality again. */ if((up->resyncing) && (space_left(up) == CMDQUEUELEN)) { #ifdef DEBUG if(debug > 1) { printf("arc: inserting signal-quality poll.\n"); } #endif send_slow(up, pp->io.fd, "g\r"); } /* The `arc_last_offset' is the offset in lastcode[] of the last byte received, and which we assume actually received the input timestamp. (When we get round to using tty_clk and it is available, we assume that we will receive the whole timecode with the trailing \r, and that that \r will be timestamped. But this assumption also works if receive the characters one-by-one.) */ arc_last_offset = pp->lencode+rbufp->recv_length - 1; /* We catch a timestamp iff: * The command code is `o' for a timestamp. * If ARCRON_MULTIPLE_SAMPLES is undefined then we must have exactly char in the buffer (the command code) so that we only sample the first character of the timecode as our `on-time' character. * The first character in the buffer is not the echoed `\r' from the `o` command (so if we are to timestamp an `\r' it must not be first in the receive buffer with lencode==1. (Even if we had other characters following it, we probably would have a premature timestamp on the '\r'.) * We have received at least one character (I cannot imagine how it could be otherwise, but anyway...). */ c = rbufp->recv_buffer[0]; if((pp->a_lastcode[0] == 'o') && #ifndef ARCRON_MULTIPLE_SAMPLES (pp->lencode == 1) && #endif ((pp->lencode != 1) || (c != '\r')) && (arc_last_offset >= 1)) { /* Note that the timestamp should be corrected if >1 char rcvd. */ l_fp timestamp; timestamp = rbufp->recv_time; #ifdef DEBUG if(debug) { /* Show \r as `R', other non-printing char as `?'. */ printf("arc: stamp -->%c<-- (%d chars rcvd)\n", ((c == '\r') ? 'R' : (isgraph((int)c) ? c : '?')), rbufp->recv_length); } #endif /* Now correct timestamp by offset of last byte received---we subtract from the receive time the delay implied by the extra characters received. Reject the input if the resulting code is too long, but allow for the trailing \r, normally not used but a good handle for tty_clk or somesuch kernel timestamper. */ if(arc_last_offset > LENARC) { #ifdef DEBUG if(debug) { printf("arc: input code too long (%d cf %d); rejected.\n", arc_last_offset, LENARC); } #endif pp->lencode = 0; refclock_report(peer, CEVNT_BADREPLY); return; } L_SUBUF(×tamp, charoffsets[arc_last_offset]); #ifdef DEBUG if(debug > 1) { printf( "arc: %s%d char(s) rcvd, the last for lastcode[%d]; -%sms offset applied.\n", ((rbufp->recv_length > 1) ? "*** " : ""), rbufp->recv_length, arc_last_offset, mfptoms((unsigned long)0, charoffsets[arc_last_offset], 1)); } #endif #ifdef ARCRON_MULTIPLE_SAMPLES /* If taking multiple samples, capture the current adjusted sample iff: * No timestamp has yet been captured (it is zero), OR * This adjusted timestamp is earlier than the one already captured, on the grounds that this one suffered less delay in being delivered to us and is more accurate. */ if(L_ISZERO(&(up->lastrec)) || L_ISGEQ(&(up->lastrec), ×tamp)) #endif { #ifdef DEBUG if(debug > 1) { printf("arc: system timestamp captured.\n"); #ifdef ARCRON_MULTIPLE_SAMPLES if(!L_ISZERO(&(up->lastrec))) { l_fp diff; diff = up->lastrec; L_SUB(&diff, ×tamp); printf("arc: adjusted timestamp by -%sms.\n", mfptoms(diff.l_i, diff.l_f, 3)); } #endif } #endif up->lastrec = timestamp; } } /* Just in case we still have lots of rubbish in the buffer... */ /* ...and to avoid the same timestamp being reused by mistake, */ /* eg on receipt of the \r coming in on its own after the */ /* timecode. */ if(pp->lencode >= LENARC) { #ifdef DEBUG if(debug && (rbufp->recv_buffer[0] != '\r')) { printf("arc: rubbish in pp->a_lastcode[].\n"); } #endif pp->lencode = 0; return; } /* Append input to code buffer, avoiding overflow. */ for(i = 0; i < rbufp->recv_length; i++) { if(pp->lencode >= LENARC) { break; } /* Avoid overflow... */ c = rbufp->recv_buffer[i]; /* Drop trailing '\r's and drop `h' command echo totally. */ if(c != '\r' && c != 'h') { pp->a_lastcode[pp->lencode++] = c; } /* If we've just put an `o' in the lastcode[0], clear the timestamp in anticipation of a timecode arriving soon. We would expect to get to process this before any of the timecode arrives. */ if((c == 'o') && (pp->lencode == 1)) { L_CLR(&(up->lastrec)); #ifdef DEBUG if(debug > 1) { printf("arc: clearing timestamp.\n"); } #endif } } if (pp->lencode == 0) return; /* Handle a quality message. */ if(pp->a_lastcode[0] == 'g') { int r, q; if(pp->lencode < 3) { return; } /* Need more data... */ r = (pp->a_lastcode[1] & 0x7f); /* Strip parity. */ q = (pp->a_lastcode[2] & 0x7f); /* Strip parity. */ if(((q & 0x70) != 0x30) || ((q & 0xf) > MAX_CLOCK_QUALITY) || ((r & 0x70) != 0x30)) { /* Badly formatted response. */ #ifdef DEBUG if(debug) { printf("arc: bad `g' response %2x %2x.\n", r, q); } #endif return; } if(r == '3') { /* Only use quality value whilst sync in progress. */ if (up->quality_stamp < current_time) { struct calendar cal; l_fp new_stamp; get_systime (&new_stamp); caljulian (new_stamp.l_ui, &cal); up->quality_stamp = current_time + 60 - cal.second + 5; quality_sum = 0; quality_polls = 0; } quality_sum += (q & 0xf); quality_polls++; quality_average = (quality_sum / quality_polls); #ifdef DEBUG if(debug) { printf("arc: signal quality %d (%d).\n", quality_average, (q & 0xf)); } #endif } else if( /* (r == '2') && */ up->resyncing) { up->quality = quality_average; #ifdef DEBUG if(debug) { printf("arc: sync finished, signal quality %d: %s\n", up->quality, quality_action(up->quality)); } #endif msyslog(LOG_NOTICE, "ARCRON: sync finished, signal quality %d: %s", up->quality, quality_action(up->quality)); up->resyncing = 0; /* Resync is over. */ quality_average = 0; quality_sum = 0; quality_polls = 0; #ifdef ARCRON_KEEN /* Clock quality dubious; resync earlier than usual. */ if((up->quality == QUALITY_UNKNOWN) || (up->quality < MIN_CLOCK_QUALITY_OK)) { up->next_resync = current_time + RETRY_RESYNC_TIME; } #endif } pp->lencode = 0; return; } /* Stop now if this is not a timecode message. */ if(pp->a_lastcode[0] != 'o') { pp->lencode = 0; refclock_report(peer, CEVNT_BADREPLY); return; } /* If we don't have enough data, wait for more... */ if(pp->lencode < LENARC) { return; } /* WE HAVE NOW COLLECTED ONE TIMESTAMP (phew)... */ #ifdef DEBUG if(debug > 1) { printf("arc: NOW HAVE TIMESTAMP...\n"); } #endif /* But check that we actually captured a system timestamp on it. */ if(L_ISZERO(&(up->lastrec))) { #ifdef DEBUG if(debug) { printf("arc: FAILED TO GET SYSTEM TIMESTAMP\n"); } #endif pp->lencode = 0; refclock_report(peer, CEVNT_BADREPLY); return; } /* Append a mark of the clock's received signal quality for the benefit of Derek Mulcahy's Tcl/Tk utility (we map the `unknown' quality value to `6' for his s/w) and terminate the string for sure. This should not go off the buffer end. */ pp->a_lastcode[pp->lencode] = ((up->quality == QUALITY_UNKNOWN) ? '6' : ('0' + up->quality)); pp->a_lastcode[pp->lencode + 1] = '\0'; /* Terminate for printf(). */ #ifdef PRE_NTP420 /* We don't use the micro-/milli- second part... */ pp->usec = 0; pp->msec = 0; #else /* We don't use the nano-second part... */ pp->nsec = 0; #endif /* Validate format and numbers. */ if (pp->a_lastcode[0] != 'o' || !get2(pp->a_lastcode + 1, &pp->hour) || !get2(pp->a_lastcode + 3, &pp->minute) || !get2(pp->a_lastcode + 5, &pp->second) || !get1(pp->a_lastcode + 7, &wday) || !get2(pp->a_lastcode + 8, &pp->day) || !get2(pp->a_lastcode + 10, &month) || !get2(pp->a_lastcode + 12, &pp->year)) { #ifdef DEBUG /* Would expect to have caught major problems already... */ if(debug) { printf("arc: badly formatted data.\n"); } #endif pp->lencode = 0; refclock_report(peer, CEVNT_BADREPLY); return; } flags = pp->a_lastcode[14]; status = pp->a_lastcode[15]; #ifdef DEBUG if(debug) { printf("arc: status 0x%.2x flags 0x%.2x\n", flags, status); } #endif n = 9; /* Validate received values at least enough to prevent internal array-bounds problems, etc. */ if((pp->hour < 0) || (pp->hour > 23) || (pp->minute < 0) || (pp->minute > 59) || (pp->second < 0) || (pp->second > 60) /*Allow for leap seconds.*/ || (wday < 1) || (wday > 7) || (pp->day < 1) || (pp->day > 31) || (month < 1) || (month > 12) || (pp->year < 0) || (pp->year > 99)) { /* Data out of range. */ pp->lencode = 0; refclock_report(peer, CEVNT_BADREPLY); return; } if(peer->MODE == 0) { /* compatiblity to original version */ int bst = flags; /* Check that BST/UTC bits are the complement of one another. */ if(!(bst & 2) == !(bst & 4)) { pp->lencode = 0; refclock_report(peer, CEVNT_BADREPLY); return; } } if(status & 0x8) { msyslog(LOG_NOTICE, "ARCRON: battery low"); } /* Year-2000 alert! */ /* Attempt to wrap 2-digit date into sensible window. */ if(pp->year < YEAR_PIVOT) { pp->year += 100; } /* Y2KFixes */ pp->year += 1900; /* use full four-digit year */ /* Y2KFixes */ /* Attempt to do the right thing by screaming that the code will soon break when we get to the end of its useful life. What a hero I am... PLEASE FIX LEAP-YEAR AND WRAP CODE IN 209X! */ if(pp->year >= YEAR_PIVOT+2000-2 ) { /* Y2KFixes */ /*This should get attention B^> */ msyslog(LOG_NOTICE, "ARCRON: fix me! EITHER YOUR DATE IS BADLY WRONG or else I will break soon!"); } #ifdef DEBUG if(debug) { printf("arc: n=%d %02d:%02d:%02d %02d/%02d/%04d %1d %1d\n", n, pp->hour, pp->minute, pp->second, pp->day, month, pp->year, flags, status); } #endif /* The status value tested for is not strictly supported by the clock spec since the value of bit 2 (0x4) is claimed to be undefined for MSF, yet does seem to indicate if the last resync was successful or not. */ pp->leap = LEAP_NOWARNING; status &= 0x7; if(status == 0x3) { if(status != up->status) { msyslog(LOG_NOTICE, "ARCRON: signal acquired"); } } else { if(status != up->status) { msyslog(LOG_NOTICE, "ARCRON: signal lost"); pp->leap = LEAP_NOTINSYNC; /* MSF clock is free-running. */ up->status = status; pp->lencode = 0; refclock_report(peer, CEVNT_FAULT); return; } } up->status = status; if (peer->MODE == 0) { /* compatiblity to original version */ int bst = flags; pp->day += moff[month - 1]; if(isleap_4(pp->year) && month > 2) { pp->day++; }/* Y2KFixes */ /* Convert to UTC if required */ if(bst & 2) { pp->hour--; if (pp->hour < 0) { pp->hour = 23; pp->day--; /* If we try to wrap round the year * (BST on 1st Jan), reject.*/ if(pp->day < 0) { pp->lencode = 0; refclock_report(peer, CEVNT_BADTIME); return; } } } } if(peer->MODE > 0) { if(pp->sloppyclockflag & CLK_FLAG1) { struct tm local; struct tm *gmtp; time_t unixtime; /* * Convert to GMT for sites that distribute localtime. * This means we have to do Y2K conversion on the * 2-digit year; otherwise, we get the time wrong. */ memset(&local, 0, sizeof(local)); local.tm_year = pp->year-1900; local.tm_mon = month-1; local.tm_mday = pp->day; local.tm_hour = pp->hour; local.tm_min = pp->minute; local.tm_sec = pp->second; switch (peer->MODE) { case 1: local.tm_isdst = (flags & 2); break; case 2: local.tm_isdst = (flags & 2); break; case 3: switch (flags & 3) { case 0: /* It is unclear exactly when the Arcron changes from DST->ST and ST->DST. Testing has shown this to be irregular. For the time being, let the OS decide. */ local.tm_isdst = 0; #ifdef DEBUG if (debug) printf ("arc: DST = 00 (0)\n"); #endif break; case 1: /* dst->st time */ local.tm_isdst = -1; #ifdef DEBUG if (debug) printf ("arc: DST = 01 (1)\n"); #endif break; case 2: /* st->dst time */ local.tm_isdst = -1; #ifdef DEBUG if (debug) printf ("arc: DST = 10 (2)\n"); #endif break; case 3: /* dst time */ local.tm_isdst = 1; #ifdef DEBUG if (debug) printf ("arc: DST = 11 (3)\n"); #endif break; } break; default: msyslog(LOG_NOTICE, "ARCRON: Invalid mode %d", peer->MODE); return; break; } unixtime = mktime (&local); if ((gmtp = gmtime (&unixtime)) == NULL) { pp->lencode = 0; refclock_report (peer, CEVNT_FAULT); return; } pp->year = gmtp->tm_year+1900; month = gmtp->tm_mon+1; pp->day = ymd2yd(pp->year,month,gmtp->tm_mday); /* pp->day = gmtp->tm_yday; */ pp->hour = gmtp->tm_hour; pp->minute = gmtp->tm_min; pp->second = gmtp->tm_sec; #ifdef DEBUG if (debug) { printf ("arc: time is %04d/%02d/%02d %02d:%02d:%02d UTC\n", pp->year,month,gmtp->tm_mday,pp->hour,pp->minute, pp->second); } #endif } else { /* * For more rational sites distributing UTC */ pp->day = ymd2yd(pp->year,month,pp->day); } } if (peer->MODE == 0) { /* compatiblity to original version */ /* If clock signal quality is * unknown, revert to default PRECISION...*/ if(up->quality == QUALITY_UNKNOWN) { peer->precision = PRECISION; } else { /* ...else improve precision if flag3 is set... */ peer->precision = ((pp->sloppyclockflag & CLK_FLAG3) ? HIGHPRECISION : PRECISION); } } else { if ((status == 0x3) && (pp->sloppyclockflag & CLK_FLAG2)) { peer->precision = ((pp->sloppyclockflag & CLK_FLAG3) ? HIGHPRECISION : PRECISION); } else if (up->quality == QUALITY_UNKNOWN) { peer->precision = PRECISION; } else { peer->precision = ((pp->sloppyclockflag & CLK_FLAG3) ? HIGHPRECISION : PRECISION); } } /* Notice and log any change (eg from initial defaults) for flags. */ if(up->saved_flags != pp->sloppyclockflag) { #ifdef DEBUG msyslog(LOG_NOTICE, "ARCRON: flags enabled: %s%s%s%s", ((pp->sloppyclockflag & CLK_FLAG1) ? "1" : "."), ((pp->sloppyclockflag & CLK_FLAG2) ? "2" : "."), ((pp->sloppyclockflag & CLK_FLAG3) ? "3" : "."), ((pp->sloppyclockflag & CLK_FLAG4) ? "4" : ".")); /* Note effects of flags changing... */ if(debug) { printf("arc: PRECISION = %d.\n", peer->precision); } #endif up->saved_flags = pp->sloppyclockflag; } /* Note time of last believable timestamp. */ pp->lastrec = up->lastrec; #ifdef ARCRON_LEAPSECOND_KEEN /* Find out if a leap-second might just have happened... (ie is this the first hour of the first day of Jan or Jul?) */ if((pp->hour == 0) && (pp->day == 1) && ((month == 1) || (month == 7))) { if(possible_leap >= 0) { /* A leap may have happened, and no resync has started yet...*/ possible_leap = 1; } } else { /* Definitely not leap-second territory... */ possible_leap = 0; } #endif if (!refclock_process(pp)) { pp->lencode = 0; refclock_report(peer, CEVNT_BADTIME); return; } record_clock_stats(&peer->srcadr, pp->a_lastcode); refclock_receive(peer); }
/* * as2201__receive - receive data from the serial interface */ static void as2201_receive( struct recvbuf *rbufp ) { register struct as2201unit *up; struct refclockproc *pp; struct peer *peer; l_fp trtmp; size_t octets; /* * Initialize pointers and read the timecode and timestamp. */ peer = rbufp->recv_peer; pp = peer->procptr; up = pp->unitptr; pp->lencode = refclock_gtlin(rbufp, pp->a_lastcode, BMAX, &trtmp); #ifdef DEBUG if (debug) printf("gps: timecode %d %d %s\n", up->linect, pp->lencode, pp->a_lastcode); #endif if (pp->lencode == 0) return; /* * If linect is greater than zero, we must be in the middle of a * statistics operation, so simply tack the received data at the * end of the statistics string. If not, we could either have * just received the timecode itself or a decimal number * indicating the number of following lines of the statistics * reply. In the former case, write the accumulated statistics * data to the clockstats file and continue onward to process * the timecode; in the later case, save the number of lines and * quietly return. */ if (pp->sloppyclockflag & CLK_FLAG2) pp->lastrec = trtmp; if (up->linect > 0) { up->linect--; if ((int)(up->lastptr - up->stats + pp->lencode) > SMAX - 2) return; *up->lastptr++ = ' '; memcpy(up->lastptr, pp->a_lastcode, 1 + pp->lencode); up->lastptr += pp->lencode; return; } else { if (pp->lencode == 1) { up->linect = atoi(pp->a_lastcode); return; } else { record_clock_stats(&peer->srcadr, up->stats); #ifdef DEBUG if (debug) printf("gps: stat %s\n", up->stats); #endif } } up->lastptr = up->stats; *up->lastptr = '\0'; /* * We get down to business, check the timecode format and decode * its contents. If the timecode has invalid length or is not in * proper format, we declare bad format and exit. */ if (pp->lencode < LENTOC) { refclock_report(peer, CEVNT_BADREPLY); return; } /* * Timecode format: "yy:ddd:hh:mm:ss.mmm" */ if (sscanf(pp->a_lastcode, "%2d:%3d:%2d:%2d:%2d.%3ld", &pp->year, &pp->day, &pp->hour, &pp->minute, &pp->second, &pp->nsec) != 6) { refclock_report(peer, CEVNT_BADREPLY); return; } pp->nsec *= 1000000; /* * Test for synchronization (this is a temporary crock). */ if (pp->a_lastcode[2] != ':') pp->leap = LEAP_NOTINSYNC; else pp->leap = LEAP_NOWARNING; /* * Process the new sample in the median filter and determine the * timecode timestamp. */ if (!refclock_process(pp)) { refclock_report(peer, CEVNT_BADTIME); return; } /* * If CLK_FLAG4 is set, initialize the statistics buffer and * send the next command. If not, simply write the timecode to * the clockstats file. */ if ((int)(up->lastptr - up->stats + pp->lencode) > SMAX - 2) return; memcpy(up->lastptr, pp->a_lastcode, pp->lencode); up->lastptr += pp->lencode; if (pp->sloppyclockflag & CLK_FLAG4) { octets = strlen(stat_command[up->index]); if ((int)(up->lastptr - up->stats + 1 + octets) > SMAX - 2) return; *up->lastptr++ = ' '; memcpy(up->lastptr, stat_command[up->index], octets); up->lastptr += octets - 1; *up->lastptr = '\0'; (void)write(pp->io.fd, stat_command[up->index], strlen(stat_command[up->index])); up->index++; if (*stat_command[up->index] == '\0') up->index = 0; } }
/* * ulink_receive - receive data from the serial interface */ static void ulink_receive( struct recvbuf *rbufp ) { struct ulinkunit *up; struct refclockproc *pp; struct peer *peer; l_fp trtmp; /* arrival timestamp */ int quality; /* quality indicator */ int temp; /* int temp */ char syncchar; /* synchronization indicator */ char leapchar; /* leap indicator */ char modechar; /* model 320 mode flag */ char siglchar; /* model difference between 33x/325 */ char char_quality[2]; /* temp quality flag */ /* * Initialize pointers and read the timecode and timestamp */ peer = (struct peer *)rbufp->recv_srcclock; pp = peer->procptr; up = (struct ulinkunit *)pp->unitptr; temp = refclock_gtlin(rbufp, pp->a_lastcode, BMAX, &trtmp); /* * Note we get a buffer and timestamp for both a <cr> and <lf>, * but only the <cr> timestamp is retained. */ if (temp == 0) { if (up->tcswitch == 0) { up->tcswitch = 1; up->laststamp = trtmp; } else up->tcswitch = 0; return; } pp->lencode = temp; pp->lastrec = up->laststamp; up->laststamp = trtmp; up->tcswitch = 1; #ifdef DEBUG if (debug) printf("ulink: timecode %d %s\n", pp->lencode, pp->a_lastcode); #endif /* * We get down to business, check the timecode format and decode * its contents. If the timecode has invalid length or is not in * proper format, we declare bad format and exit. */ syncchar = leapchar = modechar = siglchar = ' '; switch (pp->lencode ) { case LEN33X: /* * First we check if the format is 33x or 325: * <CR><LF>S9+D 00 YYYY+DDDUTCS HH:MM:SSL+5 (33x) * <CR><LF>R5_1C00LYYYY+DDDUTCS HH:MM:SSL+5 (325) * simply by comparing if the signal level is 'S' or 'R' */ if (sscanf(pp->a_lastcode, "%c%*31c", &siglchar) == 1) { if(siglchar == SIGLCHAR325) { /* * decode for a Model 325 decoder. * Timecode format from January 23, 2004 datasheet is: * * <CR><LF>R5_1C00LYYYY+DDDUTCS HH:MM:SSL+5 * * R WWVB decodersignal readability R1 - R5 * 5 R1 is unreadable, R5 is best * space a space (0x20) * 1 Data bit 0, 1, M (pos mark), or ? (unknown). * C Reception from either (C)olorado or (H)awaii * 00 Hours since last good WWVB frame sync. Will * be 00-99 * space Space char (0x20) or (0xa5) if locked to wwvb * YYYY Current year, 2000-2099 * + Leap year indicator. '+' if a leap year, * a space (0x20) if not. * DDD Day of year, 000 - 365. * UTC Timezone (always 'UTC'). * S Daylight savings indicator * S - standard time (STD) in effect * O - during STD to DST day 0000-2400 * D - daylight savings time (DST) in effect * I - during DST to STD day 0000-2400 * space Space character (0x20) * HH Hours 00-23 * : This is the REAL in sync indicator (: = insync) * MM Minutes 00-59 * : : = in sync ? = NOT in sync * SS Seconds 00-59 * L Leap second flag. Changes from space (0x20) * to 'I' or 'D' during month preceding leap * second adjustment. (I)nsert or (D)elete * +5 UT1 correction (sign + digit )) */ if (sscanf(pp->a_lastcode, "%*2c %*2c%2c%*c%4d%*c%3d%*4c %2d%c%2d:%2d%c%*2c", char_quality, &pp->year, &pp->day, &pp->hour, &syncchar, &pp->minute, &pp->second, &leapchar) == 8) { if (char_quality[0] == '0') { quality = 0; } else if (char_quality[0] == '0') { quality = (char_quality[1] & 0x0f); } else { quality = 99; } if (leapchar == 'I' ) leapchar = '+'; if (leapchar == 'D' ) leapchar = '-'; /* #ifdef DEBUG if (debug) { printf("ulink: char_quality %c %c\n", char_quality[0], char_quality[1]); printf("ulink: quality %d\n", quality); printf("ulink: syncchar %x\n", syncchar); printf("ulink: leapchar %x\n", leapchar); } #endif */ } } if(siglchar == SIGLCHAR33x) { /* * We got a Model 33X decoder. * Timecode format from January 29, 2001 datasheet is: * <CR><LF>S9+D 00 YYYY+DDDUTCS HH:MM:SSL+5 * S WWVB decoder sync indicator. S for in-sync(?) * or N for noisy signal. * 9+ RF signal level in S-units, 0-9 followed by * a space (0x20). The space turns to '+' if the * level is over 9. * D Data bit 0, 1, 2 (position mark), or * 3 (unknown). * space Space character (0x20) * 00 Hours since last good WWVB frame sync. Will * be 00-23 hrs, or '1d' to '7d'. Will be 'Lk' * if currently in sync. * space Space character (0x20) * YYYY Current year, 1990-2089 * + Leap year indicator. '+' if a leap year, * a space (0x20) if not. * DDD Day of year, 001 - 366. * UTC Timezone (always 'UTC'). * S Daylight savings indicator * S - standard time (STD) in effect * O - during STD to DST day 0000-2400 * D - daylight savings time (DST) in effect * I - during DST to STD day 0000-2400 * space Space character (0x20) * HH Hours 00-23 * : This is the REAL in sync indicator (: = insync) * MM Minutes 00-59 * : : = in sync ? = NOT in sync * SS Seconds 00-59 * L Leap second flag. Changes from space (0x20) * to '+' or '-' during month preceding leap * second adjustment. * +5 UT1 correction (sign + digit )) */ if (sscanf(pp->a_lastcode, "%*4c %2c %4d%*c%3d%*4c %2d%c%2d:%2d%c%*2c", char_quality, &pp->year, &pp->day, &pp->hour, &syncchar, &pp->minute, &pp->second, &leapchar) == 8) { if (char_quality[0] == 'L') { quality = 0; } else if (char_quality[0] == '0') { quality = (char_quality[1] & 0x0f); } else { quality = 99; } /* #ifdef DEBUG if (debug) { printf("ulink: char_quality %c %c\n", char_quality[0], char_quality[1]); printf("ulink: quality %d\n", quality); printf("ulink: syncchar %x\n", syncchar); printf("ulink: leapchar %x\n", leapchar); } #endif */ } } break; } case LEN320: /* * Model 320 Decoder * The timecode format is: * * <cr><lf>SQRYYYYDDD+HH:MM:SS.mmLT<cr> * * where: * * S = 'S' -- sync'd in last hour, * '0'-'9' - hours x 10 since last update, * '?' -- not in sync * Q = Number of correlating time-frames, from 0 to 5 * R = 'R' -- reception in progress, * 'N' -- Noisy reception, * ' ' -- standby mode * YYYY = year from 1990 to 2089 * DDD = current day from 1 to 366 * + = '+' if current year is a leap year, else ' ' * HH = UTC hour 0 to 23 * MM = Minutes of current hour from 0 to 59 * SS = Seconds of current minute from 0 to 59 * mm = 10's milliseconds of the current second from 00 to 99 * L = Leap second pending at end of month * 'I' = insert, 'D'= delete * T = DST <-> STD transition indicators * */ if (sscanf(pp->a_lastcode, "%c%1d%c%4d%3d%*c%2d:%2d:%2d.%2ld%c", &syncchar, &quality, &modechar, &pp->year, &pp->day, &pp->hour, &pp->minute, &pp->second, &pp->nsec, &leapchar) == 10) { pp->nsec *= 10000000; /* M320 returns 10's of msecs */ if (leapchar == 'I' ) leapchar = '+'; if (leapchar == 'D' ) leapchar = '-'; if (syncchar != '?' ) syncchar = ':'; break; } default: refclock_report(peer, CEVNT_BADREPLY); return; } /* * Decode quality indicator * For the 325 & 33x series, the lower the number the "better" * the time is. I used the dispersion as the measure of time * quality. The quality indicator in the 320 is the number of * correlating time frames (the more the better) */ /* * The spec sheet for the 325 & 33x series states the clock will * maintain +/-0.002 seconds accuracy when locked to WWVB. This * is indicated by 'Lk' in the quality portion of the incoming * string. When not in lock, a drift of +/-0.015 seconds should * be allowed for. * With the quality indicator decoding scheme above, the 'Lk' * condition will produce a quality value of 0. If the quality * indicator starts with '0' then the second character is the * number of hours since we were last locked. If the first * character is anything other than 'L' or '0' then we have been * out of lock for more than 9 hours so we assume the worst and * force a quality value that selects the 'default' maximum * dispersion. The dispersion values below are what came with the * driver. They're not unreasonable so they've not been changed. */ if (pp->lencode == LEN33X) { switch (quality) { case 0 : pp->disp=.002; break; case 1 : pp->disp=.02; break; case 2 : pp->disp=.04; break; case 3 : pp->disp=.08; break; default: pp->disp=MAXDISPERSE; break; } } else { switch (quality) { case 5 : pp->disp=.002; break; case 4 : pp->disp=.02; break; case 3 : pp->disp=.04; break; case 2 : pp->disp=.08; break; case 1 : pp->disp=.16; break; default: pp->disp=MAXDISPERSE; break; } } /* * Decode synchronization, and leap characters. If * unsynchronized, set the leap bits accordingly and exit. * Otherwise, set the leap bits according to the leap character. */ if (syncchar != ':') pp->leap = LEAP_NOTINSYNC; else if (leapchar == '+') pp->leap = LEAP_ADDSECOND; else if (leapchar == '-') pp->leap = LEAP_DELSECOND; else pp->leap = LEAP_NOWARNING; /* * Process the new sample in the median filter and determine the * timecode timestamp. */ if (!refclock_process(pp)) { refclock_report(peer, CEVNT_BADTIME); } }
/* * hpgps_receive - receive data from the serial interface */ static void hpgps_receive( struct recvbuf *rbufp ) { register struct hpgpsunit *up; struct refclockproc *pp; struct peer *peer; l_fp trtmp; char tcodechar1; /* identifies timecode format */ char tcodechar2; /* identifies timecode format */ char timequal; /* time figure of merit: 0-9 */ char freqqual; /* frequency figure of merit: 0-3 */ char leapchar; /* leapsecond: + or 0 or - */ char servchar; /* request for service: 0 = no, 1 = yes */ char syncchar; /* time info is invalid: 0 = no, 1 = yes */ short expectedsm; /* expected timecode byte checksum */ short tcodechksm; /* computed timecode byte checksum */ int i,m,n; int month, day, lastday; char *tcp; /* timecode pointer (skips over the prompt) */ char prompt[BMAX]; /* prompt in response from receiver */ /* * Initialize pointers and read the receiver response */ peer = (struct peer *)rbufp->recv_srcclock; pp = peer->procptr; up = (struct hpgpsunit *)pp->unitptr; *pp->a_lastcode = '\0'; pp->lencode = refclock_gtlin(rbufp, pp->a_lastcode, BMAX, &trtmp); #ifdef DEBUG if (debug) printf("hpgps: lencode: %d timecode:%s\n", pp->lencode, pp->a_lastcode); #endif /* * If there's no characters in the reply, we can quit now */ if (pp->lencode == 0) return; /* * If linecnt is greater than zero, we are getting information only, * such as the receiver identification string or the receiver status * screen, so put the receiver response at the end of the status * screen buffer. When we have the last line, write the buffer to * the clockstats file and return without further processing. * * If linecnt is zero, we are expecting either the timezone * or a timecode. At this point, also write the response * to the clockstats file, and go on to process the prompt (if any), * timezone, or timecode and timestamp. */ if (up->linecnt-- > 0) { if ((int)(pp->lencode + 2) <= (SMAX - (up->lastptr - up->statscrn))) { *up->lastptr++ = '\n'; (void)strcpy(up->lastptr, pp->a_lastcode); up->lastptr += pp->lencode; } if (up->linecnt == 0) record_clock_stats(&peer->srcadr, up->statscrn); return; } record_clock_stats(&peer->srcadr, pp->a_lastcode); pp->lastrec = trtmp; up->lastptr = up->statscrn; *up->lastptr = '\0'; up->pollcnt = 2; /* * We get down to business: get a prompt if one is there, issue * a clear status command if it contains an error indication. * Next, check for either the timezone reply or the timecode reply * and decode it. If we don't recognize the reply, or don't get the * proper number of decoded fields, or get an out of range timezone, * or if the timecode checksum is bad, then we declare bad format * and exit. * * Timezone format (including nominal prompt): * scpi > -H,-M<cr><lf> * * Timecode format (including nominal prompt): * scpi > T2yyyymmddhhmmssMFLRVcc<cr><lf> * */ (void)strcpy(prompt,pp->a_lastcode); tcp = strrchr(pp->a_lastcode,'>'); if (tcp == NULL) tcp = pp->a_lastcode; else tcp++; prompt[tcp - pp->a_lastcode] = '\0'; while ((*tcp == ' ') || (*tcp == '\t')) tcp++; /* * deal with an error indication in the prompt here */ if (strrchr(prompt,'E') > strrchr(prompt,'s')){ #ifdef DEBUG if (debug) printf("hpgps: error indicated in prompt: %s\n", prompt); #endif if (write(pp->io.fd, "*CLS\r\r", 6) != 6) refclock_report(peer, CEVNT_FAULT); } /* * make sure we got a timezone or timecode format and * then process accordingly */ m = sscanf(tcp,"%c%c", &tcodechar1, &tcodechar2); if (m != 2){ #ifdef DEBUG if (debug) printf("hpgps: no format indicator\n"); #endif refclock_report(peer, CEVNT_BADREPLY); return; } switch (tcodechar1) { case '+': case '-': m = sscanf(tcp,"%d,%d", &up->tzhour, &up->tzminute); if (m != MTZONE) { #ifdef DEBUG if (debug) printf("hpgps: only %d fields recognized in timezone\n", m); #endif refclock_report(peer, CEVNT_BADREPLY); return; } if ((up->tzhour < -12) || (up->tzhour > 13) || (up->tzminute < -59) || (up->tzminute > 59)){ #ifdef DEBUG if (debug) printf("hpgps: timezone %d, %d out of range\n", up->tzhour, up->tzminute); #endif refclock_report(peer, CEVNT_BADREPLY); return; } return; case 'T': break; default: #ifdef DEBUG if (debug) printf("hpgps: unrecognized reply format %c%c\n", tcodechar1, tcodechar2); #endif refclock_report(peer, CEVNT_BADREPLY); return; } /* end of tcodechar1 switch */ switch (tcodechar2) { case '2': m = sscanf(tcp,"%*c%*c%4d%2d%2d%2d%2d%2d%c%c%c%c%c%2hx", &pp->year, &month, &day, &pp->hour, &pp->minute, &pp->second, &timequal, &freqqual, &leapchar, &servchar, &syncchar, &expectedsm); n = NTCODET2; if (m != MTCODET2){ #ifdef DEBUG if (debug) printf("hpgps: only %d fields recognized in timecode\n", m); #endif refclock_report(peer, CEVNT_BADREPLY); return; } break; default: #ifdef DEBUG if (debug) printf("hpgps: unrecognized timecode format %c%c\n", tcodechar1, tcodechar2); #endif refclock_report(peer, CEVNT_BADREPLY); return; } /* end of tcodechar2 format switch */ /* * Compute and verify the checksum. * Characters are summed starting at tcodechar1, ending at just * before the expected checksum. Bail out if incorrect. */ tcodechksm = 0; while (n-- > 0) tcodechksm += *tcp++; tcodechksm &= 0x00ff; if (tcodechksm != expectedsm) { #ifdef DEBUG if (debug) printf("hpgps: checksum %2hX doesn't match %2hX expected\n", tcodechksm, expectedsm); #endif refclock_report(peer, CEVNT_BADREPLY); return; } /* * Compute the day of year from the yyyymmdd format. */ if (month < 1 || month > 12 || day < 1) { refclock_report(peer, CEVNT_BADTIME); return; } if ( ! isleap_4(pp->year) ) { /* Y2KFixes */ /* not a leap year */ if (day > day1tab[month - 1]) { refclock_report(peer, CEVNT_BADTIME); return; } for (i = 0; i < month - 1; i++) day += day1tab[i]; lastday = 365; } else { /* a leap year */ if (day > day2tab[month - 1]) { refclock_report(peer, CEVNT_BADTIME); return; } for (i = 0; i < month - 1; i++) day += day2tab[i]; lastday = 366; } /* * Deal with the timezone offset here. The receiver timecode is in * local time = UTC + :PTIME:TZONE, so SUBTRACT the timezone values. * For example, Pacific Standard Time is -8 hours , 0 minutes. * Deal with the underflows and overflows. */ pp->minute -= up->tzminute; pp->hour -= up->tzhour; if (pp->minute < 0) { pp->minute += 60; pp->hour--; } if (pp->minute > 59) { pp->minute -= 60; pp->hour++; } if (pp->hour < 0) { pp->hour += 24; day--; if (day < 1) { pp->year--; if ( isleap_4(pp->year) ) /* Y2KFixes */ day = 366; else day = 365; } } if (pp->hour > 23) { pp->hour -= 24; day++; if (day > lastday) { pp->year++; day = 1; } } pp->day = day; /* * Decode the MFLRV indicators. * NEED TO FIGURE OUT how to deal with the request for service, * time quality, and frequency quality indicators some day. */ if (syncchar != '0') { pp->leap = LEAP_NOTINSYNC; } else { pp->leap = LEAP_NOWARNING; switch (leapchar) { case '0': break; /* See http://bugs.ntp.org/1090 * Ignore leap announcements unless June or December. * Better would be to use :GPSTime? to find the month, * but that seems too likely to introduce other bugs. */ case '+': if ((month==6) || (month==12)) pp->leap = LEAP_ADDSECOND; break; case '-': if ((month==6) || (month==12)) pp->leap = LEAP_DELSECOND; break; default: #ifdef DEBUG if (debug) printf("hpgps: unrecognized leap indicator: %c\n", leapchar); #endif refclock_report(peer, CEVNT_BADTIME); return; } /* end of leapchar switch */ } /* * Process the new sample in the median filter and determine the * reference clock offset and dispersion. We use lastrec as both * the reference time and receive time in order to avoid being * cute, like setting the reference time later than the receive * time, which may cause a paranoid protocol module to chuck out * the data. */ if (!refclock_process(pp)) { refclock_report(peer, CEVNT_BADTIME); return; } pp->lastref = pp->lastrec; refclock_receive(peer); /* * If CLK_FLAG4 is set, ask for the status screen response. */ if (pp->sloppyclockflag & CLK_FLAG4){ up->linecnt = 22; if (write(pp->io.fd, ":SYSTEM:PRINT?\r", 15) != 15) refclock_report(peer, CEVNT_FAULT); } }
/* psc_poll: read, decode, and record device time */ static void psc_poll( int unit, struct peer *peer ) { struct refclockproc *pp = peer->procptr; struct psc_unit *up; unsigned tlo, thi; unsigned char status; up = (struct psc_unit *) pp->unitptr; tlo = regp[unit]->low_time; /* latch and read first 4 bytes */ thi = regp[unit]->high_time; /* read 4 higher order bytes */ status = regp[unit]->device_status; /* read device status byte */ if (!(status & PSC_SYNC_OK)) { refclock_report(peer, CEVNT_BADTIME); if (!up->msg_flag[unit]) { /* write once to system log */ msyslog(LOG_WARNING, "SYNCHRONIZATION LOST on unit %1d, status %02x\n", unit, status); up->msg_flag[unit] = 1; } return; } get_systime(&pp->lastrec); pp->polls++; tlo = SWAP(tlo); /* little to big endian swap on */ thi = SWAP(thi); /* copy of data */ /* convert the BCD time to broken down time used by refclockproc */ pp->day = BCD2INT3((thi & 0x0FFF0000) >> 16); pp->hour = BCD2INT2((thi & 0x0000FF00) >> 8); pp->minute = BCD2INT2(thi & 0x000000FF); pp->second = BCD2INT2(tlo >> 24); /* ntp_process() in ntp_refclock.c appears to use usec as fraction of second in microseconds if usec is nonzero. */ pp->nsec = 1000000*BCD2INT3((tlo & 0x00FFF000) >> 12) + BCD2INT3(tlo & 0x00000FFF); snprintf(pp->a_lastcode, sizeof(pp->a_lastcode), "%3.3d %2.2d:%2.2d:%2.2d.%09ld %02x %08x %08x", pp->day, pp->hour, pp->minute, pp->second, pp->nsec, status, thi, tlo); pp->lencode = strlen(pp->a_lastcode); /* compute the timecode timestamp */ if (!refclock_process(pp)) { refclock_report(peer, CEVNT_BADTIME); return; } /* simulate the NTP receive and packet procedures */ refclock_receive(peer); /* write clock statistics to file */ record_clock_stats(&peer->srcadr, pp->a_lastcode); /* With the first timecode beginning the day, check for a GPS leap second notification. */ if (pp->hour < up->last_hour) { check_leap_sec(pp, unit); up->msg_flag[0] = up->msg_flag[1] = 0; /* reset flags */ } up->last_hour = pp->hour; }
static void neoclock4x_receive(struct recvbuf *rbufp) { struct neoclock4x_unit *up; struct refclockproc *pp; struct peer *peer; unsigned long calc_utc; int day; int month; /* ddd conversion */ int c; int dsec; unsigned char calc_chksum; int recv_chksum; peer = rbufp->recv_peer; pp = peer->procptr; up = pp->unitptr; /* wait till poll interval is reached */ if(0 == up->recvnow) return; /* reset poll interval flag */ up->recvnow = 0; /* read last received timecode */ pp->lencode = refclock_gtlin(rbufp, pp->a_lastcode, BMAX, &pp->lastrec); pp->leap = LEAP_NOWARNING; if(NEOCLOCK4X_TIMECODELEN != pp->lencode) { NLOG(NLOG_CLOCKEVENT) msyslog(LOG_WARNING, "NeoClock4X(%d): received data has invalid length, expected %d bytes, received %d bytes: %s", up->unit, NEOCLOCK4X_TIMECODELEN, pp->lencode, pp->a_lastcode); refclock_report(peer, CEVNT_BADREPLY); return; } neol_hexatoi_len(&pp->a_lastcode[NEOCLOCK4X_OFFSET_CRC], &recv_chksum, 2); /* calculate checksum */ calc_chksum = 0; for(c=0; c < NEOCLOCK4X_OFFSET_CRC; c++) { calc_chksum += pp->a_lastcode[c]; } if(recv_chksum != calc_chksum) { NLOG(NLOG_CLOCKEVENT) msyslog(LOG_WARNING, "NeoClock4X(%d): received data has invalid chksum: %s", up->unit, pp->a_lastcode); refclock_report(peer, CEVNT_BADREPLY); return; } /* Allow synchronization even is quartz clock is * never initialized. * WARNING: This is dangerous! */ up->quarzstatus = pp->a_lastcode[NEOCLOCK4X_OFFSET_QUARZSTATUS]; if(0==(pp->sloppyclockflag & CLK_FLAG2)) { if('I' != up->quarzstatus) { NLOG(NLOG_CLOCKEVENT) msyslog(LOG_NOTICE, "NeoClock4X(%d): quartz clock is not initialized: %s", up->unit, pp->a_lastcode); pp->leap = LEAP_NOTINSYNC; refclock_report(peer, CEVNT_BADDATE); return; } } if('I' != up->quarzstatus) { NLOG(NLOG_CLOCKEVENT) msyslog(LOG_NOTICE, "NeoClock4X(%d): using uninitialized quartz clock for time synchronization: %s", up->unit, pp->a_lastcode); } /* * If NeoClock4X is not synchronized to a radio clock * check if we're allowed to synchronize with the quartz * clock. */ up->timesource = pp->a_lastcode[NEOCLOCK4X_OFFSET_TIMESOURCE]; if(0==(pp->sloppyclockflag & CLK_FLAG2)) { if('A' != up->timesource) { /* not allowed to sync with quartz clock */ if(0==(pp->sloppyclockflag & CLK_FLAG1)) { refclock_report(peer, CEVNT_BADTIME); pp->leap = LEAP_NOTINSYNC; return; } } } /* this should only used when first install is done */ if(pp->sloppyclockflag & CLK_FLAG4) { msyslog(LOG_DEBUG, "NeoClock4X(%d): received data: %s", up->unit, pp->a_lastcode); } /* 123456789012345678901234567890123456789012345 */ /* S/N123456DCF1004021010001202ASX1213CR\r\n */ neol_atoi_len(&pp->a_lastcode[NEOCLOCK4X_OFFSET_YEAR], &pp->year, 2); neol_atoi_len(&pp->a_lastcode[NEOCLOCK4X_OFFSET_MONTH], &month, 2); neol_atoi_len(&pp->a_lastcode[NEOCLOCK4X_OFFSET_DAY], &day, 2); neol_atoi_len(&pp->a_lastcode[NEOCLOCK4X_OFFSET_HOUR], &pp->hour, 2); neol_atoi_len(&pp->a_lastcode[NEOCLOCK4X_OFFSET_MINUTE], &pp->minute, 2); neol_atoi_len(&pp->a_lastcode[NEOCLOCK4X_OFFSET_SECOND], &pp->second, 2); neol_atoi_len(&pp->a_lastcode[NEOCLOCK4X_OFFSET_HSEC], &dsec, 2); #if defined(NTP_PRE_420) pp->msec = dsec * 10; /* convert 1/100s from neoclock to real miliseconds */ #else pp->nsec = dsec * 10 * NSEC_TO_MILLI; /* convert 1/100s from neoclock to nanoseconds */ #endif memcpy(up->radiosignal, &pp->a_lastcode[NEOCLOCK4X_OFFSET_RADIOSIGNAL], 3); up->radiosignal[3] = 0; memcpy(up->serial, &pp->a_lastcode[NEOCLOCK4X_OFFSET_SERIAL], 6); up->serial[6] = 0; up->dststatus = pp->a_lastcode[NEOCLOCK4X_OFFSET_DSTSTATUS]; neol_hexatoi_len(&pp->a_lastcode[NEOCLOCK4X_OFFSET_ANTENNA1], &up->antenna1, 2); neol_hexatoi_len(&pp->a_lastcode[NEOCLOCK4X_OFFSET_ANTENNA2], &up->antenna2, 2); /* Validate received values at least enough to prevent internal array-bounds problems, etc. */ if((pp->hour < 0) || (pp->hour > 23) || (pp->minute < 0) || (pp->minute > 59) || (pp->second < 0) || (pp->second > 60) /*Allow for leap seconds.*/ || (day < 1) || (day > 31) || (month < 1) || (month > 12) || (pp->year < 0) || (pp->year > 99)) { /* Data out of range. */ NLOG(NLOG_CLOCKEVENT) msyslog(LOG_WARNING, "NeoClock4X(%d): date/time out of range: %s", up->unit, pp->a_lastcode); refclock_report(peer, CEVNT_BADDATE); return; } /* Year-2000 check not needed anymore. Same problem * will arise at 2099 but what should we do...? * * wrap 2-digit date into 4-digit * * if(pp->year < YEAR_PIVOT) * { * pp->year += 100; * } */ pp->year += 2000; /* adjust NeoClock4X local time to UTC */ calc_utc = neol_mktime(pp->year, month, day, pp->hour, pp->minute, pp->second); calc_utc -= 3600; /* adjust NeoClock4X daylight saving time if needed */ if('S' == up->dststatus) calc_utc -= 3600; neol_localtime(calc_utc, &pp->year, &month, &day, &pp->hour, &pp->minute, &pp->second); /* some preparations */ pp->day = ymd2yd(pp->year, month, day); pp->leap = 0; if(pp->sloppyclockflag & CLK_FLAG4) { msyslog(LOG_DEBUG, "NeoClock4X(%d): calculated UTC date/time: %04d-%02d-%02d %02d:%02d:%02d.%03ld", up->unit, pp->year, month, day, pp->hour, pp->minute, pp->second, #if defined(NTP_PRE_420) pp->msec #else pp->nsec/NSEC_TO_MILLI #endif ); } up->utc_year = pp->year; up->utc_month = month; up->utc_day = day; up->utc_hour = pp->hour; up->utc_minute = pp->minute; up->utc_second = pp->second; #if defined(NTP_PRE_420) up->utc_msec = pp->msec; #else up->utc_msec = pp->nsec/NSEC_TO_MILLI; #endif if(!refclock_process(pp)) { NLOG(NLOG_CLOCKEVENT) msyslog(LOG_WARNING, "NeoClock4X(%d): refclock_process failed!", up->unit); refclock_report(peer, CEVNT_FAULT); return; } refclock_receive(peer); /* report good status */ refclock_report(peer, CEVNT_NOMINAL); record_clock_stats(&peer->srcadr, pp->a_lastcode); }
static void hopfserial_receive ( struct recvbuf *rbufp ) { struct hopfclock_unit *up; struct refclockproc *pp; struct peer *peer; int synch; /* synchhronization indicator */ int DoW; /* Dow */ int day, month; /* ddd conversion */ /* * Initialize pointers and read the timecode and timestamp. */ peer = (struct peer *)rbufp->recv_srcclock; pp = peer->procptr; up = (struct hopfclock_unit *)pp->unitptr; if (up->rpt_next == 0 ) return; up->rpt_next = 0; /* wait until next poll interval occur */ pp->lencode = (u_short)refclock_gtlin(rbufp, pp->a_lastcode, BMAX, &pp->lastrec); if (pp->lencode == 0) return; sscanf(pp->a_lastcode, #if 1 "%1x%1x%2d%2d%2d%2d%2d%2d", /* ...cr,lf */ #else "%*c%1x%1x%2d%2d%2d%2d%2d%2d", /* stx...cr,lf,etx */ #endif &synch, &DoW, &pp->hour, &pp->minute, &pp->second, &day, &month, &pp->year); /* Validate received values at least enough to prevent internal array-bounds problems, etc. */ if((pp->hour < 0) || (pp->hour > 23) || (pp->minute < 0) || (pp->minute > 59) || (pp->second < 0) || (pp->second > 60) /*Allow for leap seconds.*/ || (day < 1) || (day > 31) || (month < 1) || (month > 12) || (pp->year < 0) || (pp->year > 99)) { /* Data out of range. */ refclock_report(peer, CEVNT_BADREPLY); return; } /* some preparations */ pp->day = ymd2yd(pp->year,month,day); pp->leap=0; /* Year-2000 check! */ /* wrap 2-digit date into 4-digit */ if(pp->year < YEAR_PIVOT) { pp->year += 100; } /* < 98 */ pp->year += 1900; /* preparation for timecode ntpq rl command ! */ #if 0 snprintf(pp->a_lastcode, sizeof(pp->a_lastcode), "STATUS: %1X%1X, DATE: %02d.%02d.%04d TIME: %02d:%02d:%02d", synch, DoW, day, month, pp->year, pp->hour, pp->minute, pp->second); pp->lencode = strlen(pp->a_lastcode); if ((synch && 0xc) == 0 ){ /* time ok? */ refclock_report(peer, CEVNT_BADTIME); pp->leap = LEAP_NOTINSYNC; return; } #endif /* * If clock has no valid status then report error and exit */ if ((synch & HOPF_OPMODE) == HOPF_INVALID ){ /* time ok? */ refclock_report(peer, CEVNT_BADTIME); pp->leap = LEAP_NOTINSYNC; return; } /* * Test if time is running on internal quarz * if CLK_FLAG1 is set, sychronize even if no radio operation */ if ((synch & HOPF_OPMODE) == HOPF_INTERNAL){ if ((pp->sloppyclockflag & CLK_FLAG1) == 0) { refclock_report(peer, CEVNT_BADTIME); pp->leap = LEAP_NOTINSYNC; return; } } if (!refclock_process(pp)) { refclock_report(peer, CEVNT_BADTIME); return; } pp->lastref = pp->lastrec; refclock_receive(peer); #if 0 msyslog(LOG_ERR, " D:%x D:%d D:%d",synch,pp->minute,pp->second); #endif record_clock_stats(&peer->srcadr, pp->a_lastcode); return; }
/* * arb_receive - receive data from the serial interface */ static void arb_receive( struct recvbuf *rbufp ) { register struct arbunit *up; struct refclockproc *pp; struct peer *peer; l_fp trtmp; int temp; u_char syncchar; /* synch indicator */ char tbuf[BMAX]; /* temp buffer */ /* * Initialize pointers and read the timecode and timestamp */ peer = rbufp->recv_peer; pp = peer->procptr; up = pp->unitptr; temp = refclock_gtlin(rbufp, tbuf, sizeof(tbuf), &trtmp); /* * Note we get a buffer and timestamp for both a <cr> and <lf>, * but only the <cr> timestamp is retained. The program first * sends a TQ and expects the echo followed by the time quality * character. It then sends a B5 starting the timecode broadcast * and expects the echo followed some time later by the on-time * character <cr> and then the <lf> beginning the timecode * itself. Finally, at the <cr> beginning the next timecode at * the next second, the program sends a B0 shutting down the * timecode broadcast. * * If flag4 is set, the program snatches the latitude, longitude * and elevation and writes it to the clockstats file. */ if (temp == 0) return; pp->lastrec = up->laststamp; up->laststamp = trtmp; if (temp < 3) return; if (up->tcswitch == 0) { /* * Collect statistics. If nothing is recogized, just * ignore; sometimes the clock doesn't stop spewing * timecodes for awhile after the B0 command. * * If flag4 is not set, send TQ, SR, B5. If flag4 is * sset, send TQ, SR, LA, LO, LH, DB, B5. When the * median filter is full, send B0. */ if (!strncmp(tbuf, "TQ", 2)) { up->qualchar = tbuf[2]; write(pp->io.fd, "SR", 2); return; } else if (!strncmp(tbuf, "SR", 2)) { strlcpy(up->status, tbuf + 2, sizeof(up->status)); if (pp->sloppyclockflag & CLK_FLAG4) write(pp->io.fd, "LA", 2); else write(pp->io.fd, COMMAND_START_BCAST, 2); return; } else if (!strncmp(tbuf, "LA", 2)) { strlcpy(up->latlon, tbuf + 2, sizeof(up->latlon)); write(pp->io.fd, "LO", 2); return; } else if (!strncmp(tbuf, "LO", 2)) { strlcat(up->latlon, " ", sizeof(up->latlon)); strlcat(up->latlon, tbuf + 2, sizeof(up->latlon)); write(pp->io.fd, "LH", 2); return; } else if (!strncmp(tbuf, "LH", 2)) { strlcat(up->latlon, " ", sizeof(up->latlon)); strlcat(up->latlon, tbuf + 2, sizeof(up->latlon)); write(pp->io.fd, "DB", 2); return; } else if (!strncmp(tbuf, "DB", 2)) { strlcat(up->latlon, " ", sizeof(up->latlon)); strlcat(up->latlon, tbuf + 2, sizeof(up->latlon)); record_clock_stats(&peer->srcadr, up->latlon); #ifdef DEBUG if (debug) printf("arbiter: %s\n", up->latlon); #endif write(pp->io.fd, COMMAND_START_BCAST, 2); } } /* * We get down to business, check the timecode format and decode * its contents. If the timecode has valid length, but not in * proper format, we declare bad format and exit. If the * timecode has invalid length, which sometimes occurs when the * B0 amputates the broadcast, we just quietly steal away. Note * that the time quality character and receiver status string is * tacked on the end for clockstats display. */ up->tcswitch++; if (up->tcswitch <= 1 || temp < LENARB) return; /* * Timecode format B5: "i yy ddd hh:mm:ss.000 " */ strlcpy(pp->a_lastcode, tbuf, sizeof(pp->a_lastcode)); pp->a_lastcode[LENARB - 2] = up->qualchar; strlcat(pp->a_lastcode, up->status, sizeof(pp->a_lastcode)); pp->lencode = strlen(pp->a_lastcode); syncchar = ' '; if (sscanf(pp->a_lastcode, "%c%2d %3d %2d:%2d:%2d", &syncchar, &pp->year, &pp->day, &pp->hour, &pp->minute, &pp->second) != 6) { refclock_report(peer, CEVNT_BADREPLY); write(pp->io.fd, COMMAND_HALT_BCAST, 2); return; } /* * We decode the clock dispersion from the time quality * character. */ switch (up->qualchar) { case '0': /* locked, max accuracy */ pp->disp = 1e-7; pp->lastref = pp->lastrec; break; case '4': /* unlock accuracy < 1 us */ pp->disp = 1e-6; break; case '5': /* unlock accuracy < 10 us */ pp->disp = 1e-5; break; case '6': /* unlock accuracy < 100 us */ pp->disp = 1e-4; break; case '7': /* unlock accuracy < 1 ms */ pp->disp = .001; break; case '8': /* unlock accuracy < 10 ms */ pp->disp = .01; break; case '9': /* unlock accuracy < 100 ms */ pp->disp = .1; break; case 'A': /* unlock accuracy < 1 s */ pp->disp = 1; break; case 'B': /* unlock accuracy < 10 s */ pp->disp = 10; break; case 'F': /* clock failure */ pp->disp = MAXDISPERSE; refclock_report(peer, CEVNT_FAULT); write(pp->io.fd, COMMAND_HALT_BCAST, 2); return; default: pp->disp = MAXDISPERSE; refclock_report(peer, CEVNT_BADREPLY); write(pp->io.fd, COMMAND_HALT_BCAST, 2); return; } if (syncchar != ' ') pp->leap = LEAP_NOTINSYNC; else pp->leap = LEAP_NOWARNING; /* * Process the new sample in the median filter and determine the * timecode timestamp. */ if (!refclock_process(pp)) refclock_report(peer, CEVNT_BADTIME); else if (peer->disp > MAXDISTANCE) refclock_receive(peer); /* if (up->tcswitch >= MAXSTAGE) { */ write(pp->io.fd, COMMAND_HALT_BCAST, 2); /* } */ }
/* * pst_receive - receive data from the serial interface */ static void pst_receive( struct recvbuf *rbufp ) { register struct pstunit *up; struct refclockproc *pp; struct peer *peer; l_fp trtmp; u_long ltemp; char ampmchar; /* AM/PM indicator */ char daychar; /* standard/daylight indicator */ char junque[10]; /* "yy/dd/mm/" discard */ char info[14]; /* "frdzycchhSSFT" clock info */ /* * Initialize pointers and read the timecode and timestamp */ peer = rbufp->recv_peer; pp = peer->procptr; up = pp->unitptr; up->lastptr += refclock_gtlin(rbufp, up->lastptr, pp->a_lastcode + BMAX - 2 - up->lastptr, &trtmp); *up->lastptr++ = ' '; *up->lastptr = '\0'; /* * Note we get a buffer and timestamp for each <cr>, but only * the first timestamp is retained. */ if (up->tcswitch == 0) pp->lastrec = trtmp; up->tcswitch++; pp->lencode = up->lastptr - pp->a_lastcode; if (up->tcswitch < 3) return; /* * We get down to business, check the timecode format and decode * its contents. If the timecode has invalid length or is not in * proper format, we declare bad format and exit. */ if (pp->lencode < LENPST) { refclock_report(peer, CEVNT_BADREPLY); return; } /* * Timecode format: * "ahh:mm:ss.fffs yy/dd/mm/ddd frdzycchhSSFTttttuuxx" */ if (sscanf(pp->a_lastcode, "%c%2d:%2d:%2d.%3ld%c %9s%3d%13s%4ld", &mchar, &pp->hour, &pp->minute, &pp->second, &pp->nsec, &daychar, junque, &pp->day, info, <emp) != 10) { refclock_report(peer, CEVNT_BADREPLY); return; } pp->nsec *= 1000000; /* * Decode synchronization, quality and last update. If * unsynchronized, set the leap bits accordingly and exit. Once * synchronized, the dispersion depends only on when the clock * was last heard, which depends on the time since last update, * as reported by the clock. */ if (info[9] != '8') pp->leap = LEAP_NOTINSYNC; if (info[12] == 'H') memcpy((char *)&pp->refid, WWVHREFID, 4); else memcpy((char *)&pp->refid, WWVREFID, 4); if (peer->stratum <= 1) peer->refid = pp->refid; if (ltemp == 0) pp->lastref = pp->lastrec; pp->disp = PST_PHI * ltemp * 60; /* * Process the new sample in the median filter and determine the * timecode timestamp. */ if (!refclock_process(pp)) refclock_report(peer, CEVNT_BADTIME); else if (peer->disp > MAXDISTANCE) refclock_receive(peer); }
/* * dumbclock_receive - receive data from the serial interface */ static void dumbclock_receive( struct recvbuf *rbufp ) { struct dumbclock_unit *up; struct refclockproc *pp; struct peer *peer; l_fp trtmp; /* arrival timestamp */ int hours; /* hour-of-day */ int minutes; /* minutes-past-the-hour */ int seconds; /* seconds */ int temp; /* int temp */ int got_good; /* got a good time flag */ /* * Initialize pointers and read the timecode and timestamp */ peer = rbufp->recv_peer; pp = peer->procptr; up = pp->unitptr; temp = refclock_gtlin(rbufp, pp->a_lastcode, BMAX, &trtmp); if (temp == 0) { if (up->tcswitch == 0) { up->tcswitch = 1; up->laststamp = trtmp; } else up->tcswitch = 0; return; } pp->lencode = (u_short)temp; pp->lastrec = up->laststamp; up->laststamp = trtmp; up->tcswitch = 1; #ifdef DEBUG if (debug) printf("dumbclock: timecode %d %s\n", pp->lencode, pp->a_lastcode); #endif /* * We get down to business. Check the timecode format... */ got_good=0; if (sscanf(pp->a_lastcode,"%02d:%02d:%02d", &hours,&minutes,&seconds) == 3) { struct tm *gmtp; struct tm *lt_p; time_t asserted_time; /* the SPM time based on the composite time+date */ struct tm asserted_tm; /* the struct tm of the same */ int adjyear; int adjmon; time_t reality_delta; time_t now; /* * Convert to GMT for sites that distribute localtime. This * means we have to figure out what day it is. Easier said * than done... */ memset(&asserted_tm, 0, sizeof(asserted_tm)); asserted_tm.tm_year = up->ymd.tm_year; asserted_tm.tm_mon = up->ymd.tm_mon; asserted_tm.tm_mday = up->ymd.tm_mday; asserted_tm.tm_hour = hours; asserted_tm.tm_min = minutes; asserted_tm.tm_sec = seconds; asserted_tm.tm_isdst = -1; #ifdef GET_LOCALTIME asserted_time = mktime (&asserted_tm); time(&now); #else #include "GMT unsupported for dumbclock!" #endif reality_delta = asserted_time - now; /* * We assume that if the time is grossly wrong, it's because we got the * year/month/day wrong. */ if (reality_delta > INSANE_SECONDS) { asserted_time -= SECSPERDAY; /* local clock behind real time */ } else if (-reality_delta > INSANE_SECONDS) { asserted_time += SECSPERDAY; /* local clock ahead of real time */ } lt_p = localtime(&asserted_time); if (lt_p) { up->ymd = *lt_p; } else { refclock_report (peer, CEVNT_FAULT); return; } if ((gmtp = gmtime (&asserted_time)) == NULL) { refclock_report (peer, CEVNT_FAULT); return; } adjyear = gmtp->tm_year+1900; adjmon = gmtp->tm_mon+1; pp->day = ymd2yd (adjyear, adjmon, gmtp->tm_mday); pp->hour = gmtp->tm_hour; pp->minute = gmtp->tm_min; pp->second = gmtp->tm_sec; #ifdef DEBUG if (debug) printf ("time is %04d/%02d/%02d %02d:%02d:%02d UTC\n", adjyear,adjmon,gmtp->tm_mday,pp->hour,pp->minute, pp->second); #endif got_good=1; } if (!got_good) { if (up->linect > 0) up->linect--; else refclock_report(peer, CEVNT_BADREPLY); return; } /* * Process the new sample in the median filter and determine the * timecode timestamp. */ if (!refclock_process(pp)) { refclock_report(peer, CEVNT_BADTIME); return; } pp->lastref = pp->lastrec; refclock_receive(peer); record_clock_stats(&peer->srcadr, pp->a_lastcode); up->lasthour = (u_char)pp->hour; }
/* * acts_timecode - identify the service and parse the timecode message */ void acts_timecode( struct peer *peer, /* peer structure pointer */ char *str /* timecode string */ ) { struct actsunit *up; struct refclockproc *pp; int day; /* day of the month */ int month; /* month of the year */ u_long mjd; /* Modified Julian Day */ double dut1; /* DUT adjustment */ u_int dst; /* ACTS daylight/standard time */ u_int leap; /* ACTS leap indicator */ double msADV; /* ACTS transmit advance (ms) */ char utc[10]; /* ACTS timescale */ char flag; /* ACTS on-time character (* or #) */ char synchar; /* WWVB synchronized indicator */ char qualchar; /* WWVB quality indicator */ char leapchar; /* WWVB leap indicator */ char dstchar; /* WWVB daylight/savings indicator */ int tz; /* WWVB timezone */ int leapmonth; /* PTB/NPL month of leap */ char leapdir; /* PTB/NPL leap direction */ /* * The parser selects the modem format based on the message * length. Since the data are checked carefully, occasional * errors due noise are forgivable. */ pp = peer->procptr; up = (struct actsunit *)pp->unitptr; pp->nsec = 0; switch(strlen(str)) { /* * For USNO format on-time character '*', which is on a line by * itself. Be sure a timecode has been received. */ case 1: if (*str == '*' && up->msgcnt > 0) break; return; /* * ACTS format: "jjjjj yy-mm-dd hh:mm:ss ds l uuu aaaaa * UTC(NIST) *" */ case LENACTS: if (sscanf(str, "%5ld %2d-%2d-%2d %2d:%2d:%2d %2d %1d %3lf %5lf %9s %c", &mjd, &pp->year, &month, &day, &pp->hour, &pp->minute, &pp->second, &dst, &leap, &dut1, &msADV, utc, &flag) != 13) { refclock_report(peer, CEVNT_BADREPLY); return; } /* * Wait until ACTS has calculated the roundtrip delay. * We don't need to do anything, as ACTS adjusts the * on-time epoch. */ if (flag != '#') return; pp->day = ymd2yd(pp->year, month, day); pp->leap = LEAP_NOWARNING; if (leap == 1) pp->leap = LEAP_ADDSECOND; else if (pp->leap == 2) pp->leap = LEAP_DELSECOND; memcpy(&pp->refid, REFACTS, 4); if (up->msgcnt == 0) record_clock_stats(&peer->srcadr, str); up->msgcnt++; break; /* * USNO format: "jjjjj nnn hhmmss UTC" */ case LENUSNO: if (sscanf(str, "%5ld %3d %2d%2d%2d %3s", &mjd, &pp->day, &pp->hour, &pp->minute, &pp->second, utc) != 6) { refclock_report(peer, CEVNT_BADREPLY); return; } /* * Wait for the on-time character, which follows in a * separate message. There is no provision for leap * warning. */ pp->leap = LEAP_NOWARNING; memcpy(&pp->refid, REFUSNO, 4); if (up->msgcnt == 0) record_clock_stats(&peer->srcadr, str); up->msgcnt++; return; /* * PTB/NPL format: "yyyy-mm-dd hh:mm:ss MEZ" */ case LENPTB: if (sscanf(str, "%*4d-%*2d-%*2d %*2d:%*2d:%2d %*5c%*12c%4d%2d%2d%2d%2d%5ld%2lf%c%2d%3lf%*15c%c", &pp->second, &pp->year, &month, &day, &pp->hour, &pp->minute, &mjd, &dut1, &leapdir, &leapmonth, &msADV, &flag) != 12) { refclock_report(peer, CEVNT_BADREPLY); return; } pp->leap = LEAP_NOWARNING; if (leapmonth == month) { if (leapdir == '+') pp->leap = LEAP_ADDSECOND; else if (leapdir == '-') pp->leap = LEAP_DELSECOND; } pp->day = ymd2yd(pp->year, month, day); memcpy(&pp->refid, REFPTB, 4); if (up->msgcnt == 0) record_clock_stats(&peer->srcadr, str); up->msgcnt++; break; /* * WWVB format 0: "I ddd hh:mm:ss DTZ=nn" */ case LENWWVB0: if (sscanf(str, "%c %3d %2d:%2d:%2d %cTZ=%2d", &synchar, &pp->day, &pp->hour, &pp->minute, &pp->second, &dstchar, &tz) != 7) { refclock_report(peer, CEVNT_BADREPLY); return; } pp->leap = LEAP_NOWARNING; if (synchar != ' ') pp->leap = LEAP_NOTINSYNC; memcpy(&pp->refid, REFWWVB, 4); if (up->msgcnt == 0) record_clock_stats(&peer->srcadr, str); up->msgcnt++; break; /* * WWVB format 2: "IQyy ddd hh:mm:ss.mmm LD" */ case LENWWVB2: if (sscanf(str, "%c%c%2d %3d %2d:%2d:%2d.%3ld%c%c%c", &synchar, &qualchar, &pp->year, &pp->day, &pp->hour, &pp->minute, &pp->second, &pp->nsec, &dstchar, &leapchar, &dstchar) != 11) { refclock_report(peer, CEVNT_BADREPLY); return; } pp->nsec *= 1000000; pp->leap = LEAP_NOWARNING; if (synchar != ' ') pp->leap = LEAP_NOTINSYNC; else if (leapchar == 'L') pp->leap = LEAP_ADDSECOND; memcpy(&pp->refid, REFWWVB, 4); if (up->msgcnt == 0) record_clock_stats(&peer->srcadr, str); up->msgcnt++; break; /* * None of the above. Just forget about it and wait for the next * message or timeout. */ default: return; } /* * We have a valid timecode. The fudge time1 value is added to * each sample by the main line routines. Note that in current * telephone networks the propatation time can be different for * each call and can reach 200 ms for some calls. */ peer->refid = pp->refid; pp->lastrec = up->tstamp; if (!refclock_process(pp)) { refclock_report(peer, CEVNT_BADTIME); return; } pp->lastref = pp->lastrec; if (up->state != S_MSG) { up->state = S_MSG; up->timer = TIMECODE; } }
/* * fg_receive - receive data from the serial interface */ static void fg_receive( struct recvbuf *rbufp ) { struct refclockproc *pp; struct fgunit *up; struct peer *peer; char *bpt; /* * Initialize pointers and read the timecode and timestamp * We can't use gtlin function because we need bynary data in buf */ peer = (struct peer *)rbufp->recv_srcclock; pp = peer->procptr; up = (struct fgunit *)pp->unitptr; /* * Below hug to implement receiving of status information */ if(!up->pollnum) { up->pollnum++; return; } if (rbufp->recv_length < (LENFG-2)) { refclock_report(peer, CEVNT_BADREPLY); return; /* The reply is invalid discard it. */ } /* Below I trying to find a correct reply in buffer. * Sometime GPS reply located in the beginnig of buffer, * sometime you can find it with some offset. */ bpt = (char *)rbufp->recv_space.X_recv_buffer; while(*bpt != '') bpt++; #define BP2(x) ( bpt[x] & 15 ) #define BP1(x) (( bpt[x] & 240 ) >> 4) pp->year = BP1(2)*10 + BP2(2); if(pp->year == 94) { refclock_report(peer, CEVNT_BADREPLY); if(!fg_init(pp->io.fd)) refclock_report(peer, CEVNT_FAULT); return; /* GPS is just powered up. The date is invalid - discarding it. Initilize GPS one more time */ /* Sorry - this driver will broken in 2094 ;) */ } if (pp->year < 99) pp->year += 100; pp->year += 1900; pp->day = 100 * BP2(3) + 10 * BP1(4) + BP2(4); /* After Jan, 10 2000 Forum Graphic GPS receiver had a very strange benahour. It doubles day number for an hours in replys after 10:10:10 UTC and doubles min every hour at HH:10:ss for a minute. Hope it is a problem of my unit only and not a Y2K problem of FG GPS. Below small code to avoid such situation. */ if(up->y2kwarn > 10) pp->hour = BP1(6)*10 + BP2(6); else pp->hour = BP1(5)*10 + BP2(5); if((up->y2kwarn > 10) && (pp->hour == 10)) { pp->minute = BP1(7)*10 + BP2(7); pp->second = BP1(8)*10 + BP2(8); pp->nsec = (BP1(9)*10 + BP2(9)) * 1000000; pp->nsec += BP1(10) * 1000; } else { pp->hour = BP1(5)*10 + BP2(5); pp->minute = BP1(6)*10 + BP2(6); pp->second = BP1(7)*10 + BP2(7); pp->nsec = (BP1(8)*10 + BP2(8)) * 1000000; pp->nsec += BP1(9) * 1000; } if((pp->hour == 10) && (pp->minute == 10)) { up->y2kwarn++; } sprintf(pp->a_lastcode, "%d %d %d %d %d", pp->year, pp->day, pp->hour, pp->minute, pp->second); pp->lencode = strlen(pp->a_lastcode); /*get_systime(&pp->lastrec);*/ #ifdef DEBUG if (debug) printf ("fg: time is %04d/%03d %02d:%02d:%02d UTC\n", pp->year, pp->day, pp->hour, pp->minute, pp->second); #endif if (peer->stratum <= 1) peer->refid = pp->refid; pp->disp = (10e-6); pp->lastrec = rbufp->recv_time; /* Is it better than get_systime()? */ /* pp->leap = LEAP_NOWARNING; */ /* * Process the new sample in the median filter and determine the * timecode timestamp. */ if (!refclock_process(pp)) refclock_report(peer, CEVNT_BADTIME); pp->lastref = pp->lastrec; refclock_receive(peer); return; }
/* * tt560_poll - called by the transmit procedure */ static void tt560_poll( int unit, struct peer *peer ) { register struct tt560unit *up; struct refclockproc *pp; time_freeze_reg_t *tp; tt_mem_space_t *mp; int i; unsigned int *p_time_t, *tt_mem_t; /* * This is the main routine. It snatches the time from the TT560 * board and tacks on a local timestamp. */ pp = peer->procptr; up = (struct tt560unit *)pp->unitptr; mp = up->tt_mem; tp = &up->tt560rawt; p_time_t = (unsigned int *)tp; tt_mem_t = (unsigned int *)&mp->time_freeze_reg; *tt_mem_t = 0; /* update the time freeze register */ /* and copy time stamp to memory */ for (i=0; i < TIME_FREEZE_REG_LEN; i++) { *p_time_t = byte_swap(*tt_mem_t); p_time_t++; tt_mem_t++; } get_systime(&pp->lastrec); pp->polls++; /* * We get down to business, check the timecode format and decode * its contents. If the timecode has invalid length or is not in * proper format, we declare bad format and exit. Note: we * can't use the sec/usec conversion produced by the driver, * since the year may be suspect. All format error checking is * done by the sprintf() and sscanf() routines. */ sprintf(pp->a_lastcode, "%1x%1x%1x %1x%1x:%1x%1x:%1x%1x.%1x%1x%1x%1x%1x%1x %1x", tp->hun_day, tp->tens_day, tp->unit_day, tp->tens_hour, tp->unit_hour, tp->tens_min, tp->unit_min, tp->tens_sec, tp->unit_sec, tp->hun_ms, tp->tens_ms, tp->unit_ms, tp->hun_us, tp->tens_us, tp->unit_us, tp->status); pp->lencode = strlen(pp->a_lastcode); #ifdef DEBUG if (debug) printf("tt560: time %s timecode %d %s\n", ulfptoa(&pp->lastrec, 6), pp->lencode, pp->a_lastcode); #endif if (sscanf(pp->a_lastcode, "%3d %2d:%2d:%2d.%6ld", &pp->day, &pp->hour, &pp->minute, &pp->second, &pp->usec) != 5) { refclock_report(peer, CEVNT_BADTIME); return; } if ((tp->status & 0x6) != 0x6) pp->leap = LEAP_NOTINSYNC; else pp->leap = LEAP_NOWARNING; if (!refclock_process(pp)) { refclock_report(peer, CEVNT_BADTIME); return; } if (peer->burst > 0) return; if (pp->coderecv == pp->codeproc) { refclock_report(peer, CEVNT_TIMEOUT); return; } record_clock_stats(&peer->srcadr, pp->a_lastcode); refclock_receive(peer); peer->burst = NSTAGE; }