diff options
Diffstat (limited to 'contrib/ntp/ntpd/refclock_arc.c')
-rw-r--r-- | contrib/ntp/ntpd/refclock_arc.c | 372 |
1 files changed, 290 insertions, 82 deletions
diff --git a/contrib/ntp/ntpd/refclock_arc.c b/contrib/ntp/ntpd/refclock_arc.c index c771f47..f556da6 100644 --- a/contrib/ntp/ntpd/refclock_arc.c +++ b/contrib/ntp/ntpd/refclock_arc.c @@ -1,5 +1,5 @@ /* - * refclock_arc - clock driver for ARCRON MSF receivers + * refclock_arc - clock driver for ARCRON MSF/DCF/WWVB receivers */ #ifdef HAVE_CONFIG_H @@ -7,9 +7,11 @@ #endif #if defined(REFCLOCK) && defined(CLOCK_ARCRON_MSF) -static const char arc_version[] = { "V1.1 1997/06/23" }; +static const char arc_version[] = { "V1.3 2003/02/21" }; -#undef ARCRON_DEBUG /* Define only while in development... */ +/* define PRE_NTP420 for compatibility to previous versions of NTP (at least + to 4.1.0 */ +#undef PRE_NTP420 #ifndef ARCRON_NOT_KEEN #define ARCRON_KEEN 1 /* Be keen, and trusting of the clock, if defined. */ @@ -28,6 +30,9 @@ static const char arc_version[] = { "V1.1 1997/06/23" }; /* Code by Derek Mulcahy, <derek@toybox.demon.co.uk>, 1997. Modifications by Damon Hart-Davis, <d@hd.org>, 1997. +Modifications by Paul Alfille, <palfille@partners.org>, 2003. +Modifications by Christopher Price, <cprice@cs-home.com>, 2003. + THIS CODE IS SUPPLIED AS IS, WITH NO WARRANTY OF ANY KIND. USE AT YOUR OWN RISK. @@ -42,6 +47,33 @@ reproduced. ------------------------------------------------------------------------------- +Christopher's notes: + +MAJOR CHANGES SINCE V1.2 +======================== + 1) Applied patch by Andrey Bray <abuse@madhouse.demon.co.uk> + 2001-02-17 comp.protocols.time.ntp + + 2) Added WWVB support via clock mode command, localtime/UTC time configured + via flag1=(0=UTC, 1=localtime) + + 3) Added ignore resync request via flag2=(0=resync, 1=ignore resync) + + 4) Added simplified conversion from localtime to UTC with dst/bst translation + + 5) Added average signal quality poll + + 6) Fixed a badformat error when no code is available due to stripping + \n & \r's + + 7) Fixed a badformat error when clearing lencode & memset a_lastcode in poll + routine + + 8) Lots of code cleanup, including standardized DEBUG macros and removal + of unused code + +------------------------------------------------------------------------------- + Author's original note: I enclose my ntp driver for the Galleon Systems Arc MSF receiver. @@ -306,6 +338,7 @@ Also note h<cr> command which starts a resync to MSF signal. #include "ntpd.h" #include "ntp_io.h" #include "ntp_refclock.h" +#include "ntp_calendar.h" #include "ntp_stdlib.h" #include <stdio.h> @@ -324,7 +357,7 @@ Also note h<cr> command which starts a resync to MSF signal. #endif /* - * This driver supports the ARCRON MSF Radio Controlled Clock + * This driver supports the ARCRON MSF/DCF/WWVB Radio Controlled Clock */ /* @@ -335,9 +368,16 @@ Also note h<cr> command which starts a resync to MSF signal. #define PRECISION (-4) /* Precision (~63 ms). */ #define HIGHPRECISION (-5) /* If things are going well... */ #define REFID "MSFa" /* Reference ID. */ -#define DESCRIPTION "ARCRON MSF Receiver" +#define REFID_MSF "MSF" /* Reference ID. */ +#define REFID_DCF77 "DCF" /* Reference ID. */ +#define REFID_WWVB "WWVB" /* Reference ID. */ +#define DESCRIPTION "ARCRON MSF/DCF/WWVB Receiver" -#define NSAMPLESLONG 8 /* Stages of long filter. */ +#ifdef PRE_NTP420 +#define MODE ttlmax +#else +#define MODE ttl +#endif #define LENARC 16 /* Format `o' timecode length. */ @@ -405,22 +445,6 @@ Also note h<cr> command which starts a resync to MSF signal. #endif }; -/* Chose filter length dependent on fudge flag 4. */ -#define CHOSENSAMPLES(pp) \ -(((pp)->sloppyclockflag & CLK_FLAG4) ? NSAMPLESLONG : NSAMPLES) - /* -Chose how many filter samples to keep. Several factors are in play. - - 1) Discard at least one sample to allow a spike value to be - discarded. - - 2) Discard about 1-in-8 to 1-in-30 samples to handle spikes. - - 3) Keep an odd number of samples to avoid median value being biased - high or low. -*/ -#define NKEEP(pp) ((CHOSENSAMPLES(pp) - 1 - (CHOSENSAMPLES(pp)>>3)) | 1) - #define DEFAULT_RESYNC_TIME (57*60) /* Gap between resync attempts (s). */ #define RETRY_RESYNC_TIME (27*60) /* Gap to emergency resync attempt. */ #ifdef ARCRON_KEEN @@ -454,6 +478,7 @@ struct arcunit { int quality; /* Quality of reception 0--5 for unit. */ /* We may also use the values -1 or 6 internally. */ + u_long quality_stamp; /* Next time to reset quality average. */ u_long next_resync; /* Next resync time (s) compared to current_time. */ int resyncing; /* Resync in progress if true. */ @@ -463,6 +488,7 @@ struct arcunit { u_long saved_flags; /* Saved fudge flags. */ }; + #ifdef ARCRON_LEAPSECOND_KEEN /* The flag `possible_leap' is set non-zero when any MSF unit thinks a leap-second may have happened. @@ -522,18 +548,16 @@ struct refclock refclock_arc = { /* Queue us up for the next tick. */ #define ENQUEUE(up) \ do { \ - if((up)->ev.next != 0) { break; } /* WHOOPS! */ \ - peer->nextdate = current_time + QUEUETICK; \ + peer->nextaction = current_time + QUEUETICK; \ } while(0) -#if 0 -/* Placeholder event handler---does nothing safely---soaks up lose tick. */ +/* Placeholder event handler---does nothing safely---soaks up loose tick. */ static void dummy_event_handler( struct peer *peer ) { -#ifdef ARCRON_DEBUG +#ifdef DEBUG if(debug) { printf("arc: dummy_event_handler() called.\n"); } #endif } @@ -558,7 +582,7 @@ arc_event_handler( register struct arcunit *up = (struct arcunit *)pp->unitptr; int i; char c; -#ifdef ARCRON_DEBUG +#ifdef DEBUG if(debug > 2) { printf("arc: arc_event_handler() called.\n"); } #endif @@ -572,12 +596,13 @@ arc_event_handler( if(write(pp->io.fd, &c, 1) != 1) { msyslog(LOG_NOTICE, "ARCRON: write to fd %d failed", pp->io.fd); } -#ifdef ARCRON_DEBUG +#ifdef DEBUG else if(debug) { printf("arc: sent `%2.2x', fd %d.\n", c, pp->io.fd); } #endif } + + ENQUEUE(up); } -#endif /* 0 */ /* * arc_start - open the devices and initialize data for processing @@ -597,7 +622,7 @@ arc_start( #endif msyslog(LOG_NOTICE, "ARCRON: %s: opening unit %d", arc_version, unit); -#ifdef ARCRON_DEBUG +#ifdef DEBUG if(debug) { printf("arc: %s: attempt to open unit %d.\n", arc_version, unit); } @@ -612,7 +637,7 @@ arc_start( (void)sprintf(device, DEVICE, unit); if (!(fd = refclock_open(device, SPEED, LDISC_CLK))) return(0); -#ifdef ARCRON_DEBUG +#ifdef DEBUG if(debug) { printf("arc: unit %d using open().\n", unit); } #endif fd = open(device, OPEN_FLAGS); @@ -624,9 +649,9 @@ arc_start( } fcntl(fd, F_SETFL, 0); /* clear the descriptor flags */ -#ifdef ARCRON_DEBUG +#ifdef DEBUG if(debug) - { printf("Opened RS232 port with file descriptor %d.\n", fd); } + { printf("arc: opened RS232 port with file descriptor %d.\n", fd); } #endif #ifdef HAVE_TERMIOS @@ -667,7 +692,27 @@ arc_start( peer->precision = PRECISION; peer->stratum = 2; /* Default to stratum 2 not 0. */ pp->clockdesc = DESCRIPTION; - memcpy((char *)&pp->refid, REFID, 4); + if (peer->MODE > 3) { + msyslog(LOG_NOTICE, "ARCRON: Invalid mode %d", peer->MODE); + return 0; + } +#ifdef DEBUG + if(debug) { printf("arc: mode = %d.\n", peer->MODE); } +#endif + switch (peer->MODE) { + case 1: + memcpy((char *)&pp->refid, REFID_MSF, 4); + break; + case 2: + memcpy((char *)&pp->refid, REFID_DCF77, 4); + break; + case 3: + memcpy((char *)&pp->refid, REFID_WWVB, 4); + break; + default: + memcpy((char *)&pp->refid, REFID, 4); + break; + } /* Spread out resyncs so that they should remain separated. */ up->next_resync = current_time + INITIAL_RESYNC_DELAY + (67*unit)%1009; @@ -686,6 +731,11 @@ arc_start( #else up->quality = MIN_CLOCK_QUALITY;/* Don't trust the clock yet. */ #endif + + peer->action = arc_event_handler; + + ENQUEUE(up); + return(1); } @@ -702,6 +752,8 @@ arc_shutdown( register struct arcunit *up; struct refclockproc *pp; + peer->action = dummy_event_handler; + pp = peer->procptr; up = (struct arcunit *)pp->unitptr; io_closeclock(&pp->io); @@ -740,11 +792,11 @@ send_slow( int sl = strlen(s); int spaceleft = space_left(up); -#ifdef ARCRON_DEBUG +#ifdef DEBUG if(debug > 1) { printf("arc: spaceleft = %d.\n", spaceleft); } #endif if(spaceleft < sl) { /* Should not normally happen... */ -#ifdef ARCRON_DEBUG +#ifdef DEBUG msyslog(LOG_NOTICE, "ARCRON: send-buffer overrun (%d/%d)", sl, spaceleft); #endif @@ -776,8 +828,11 @@ arc_receive( struct refclockproc *pp; struct peer *peer; char c; - int i, n, wday, month, bst, status; + 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 @@ -857,7 +912,7 @@ arc_receive( handle for tty_clk or somesuch kernel timestamper. */ if(arc_last_offset > LENARC) { -#ifdef ARCRON_DEBUG +#ifdef DEBUG if(debug) { printf("arc: input code too long (%d cf %d); rejected.\n", arc_last_offset, LENARC); @@ -869,7 +924,7 @@ arc_receive( } L_SUBUF(×tamp, charoffsets[arc_last_offset]); -#ifdef ARCRON_DEBUG +#ifdef DEBUG if(debug > 1) { printf( "arc: %s%d char(s) rcvd, the last for lastcode[%d]; -%sms offset applied.\n", @@ -898,7 +953,7 @@ arc_receive( L_ISGEQ(&(up->lastrec), ×tamp)) #endif { -#ifdef ARCRON_DEBUG +#ifdef DEBUG if(debug > 1) { printf("arc: system timestamp captured.\n"); #ifdef ARCRON_MULTIPLE_SAMPLES @@ -922,7 +977,7 @@ arc_receive( /* eg on receipt of the \r coming in on its own after the */ /* timecode. */ if(pp->lencode >= LENARC) { -#ifdef ARCRON_DEBUG +#ifdef DEBUG if(debug && (rbufp->recv_buffer[0] != '\r')) { printf("arc: rubbish in pp->a_lastcode[].\n"); } #endif @@ -947,11 +1002,12 @@ arc_receive( */ if((c == 'o') && (pp->lencode == 1)) { L_CLR(&(up->lastrec)); -#ifdef ARCRON_DEBUG +#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') { @@ -963,17 +1019,31 @@ arc_receive( if(((q & 0x70) != 0x30) || ((q & 0xf) > MAX_CLOCK_QUALITY) || ((r & 0x70) != 0x30)) { /* Badly formatted response. */ -#ifdef ARCRON_DEBUG +#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. */ - up->quality = (q & 0xf); + 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.\n", up->quality); } + 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) { @@ -987,6 +1057,9 @@ arc_receive( 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. */ @@ -1011,13 +1084,13 @@ arc_receive( /* WE HAVE NOW COLLECTED ONE TIMESTAMP (phew)... */ -#ifdef ARCRON_DEBUG +#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 ARCRON_DEBUG +#ifdef DEBUG if(debug) { printf("arc: FAILED TO GET SYSTEM TIMESTAMP\n"); } #endif pp->lencode = 0; @@ -1033,22 +1106,26 @@ arc_receive( pp->a_lastcode[pp->lencode] = ((up->quality == QUALITY_UNKNOWN) ? '6' : ('0' + up->quality)); pp->a_lastcode[pp->lencode + 1] = '\0'; /* Terminate for printf(). */ - record_clock_stats(&peer->srcadr, pp->a_lastcode); +#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 n = sscanf(pp->a_lastcode, "o%2d%2d%2d%1d%2d%2d%2d%1d%1d", &pp->hour, &pp->minute, &pp->second, - &wday, &pp->day, &month, &pp->year, &bst, &status); + &wday, &pp->day, &month, &pp->year, &flags, &status); /* Validate format and numbers. */ if(n != 9) { -#ifdef ARCRON_DEBUG +#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; } @@ -1064,15 +1141,21 @@ arc_receive( (month < 1) || (month > 12) || (pp->year < 0) || (pp->year > 99)) { /* Data out of range. */ + pp->lencode = 0; refclock_report(peer, CEVNT_BADREPLY); return; } - /* Check that BST/UTC bits are the complement of one another. */ - if(!(bst & 2) == !(bst & 4)) { - 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! */ @@ -1094,7 +1177,7 @@ arc_receive( 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, bst, status); + pp->day, month, pp->year, flags, status); } #endif @@ -1114,41 +1197,159 @@ arc_receive( 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; - pp->day += moff[month - 1]; - - if(isleap_4(pp->year) && month > 2) { pp->day++; } /* Y2KFixes */ + 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; + } + } + } + } - /* 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) { - refclock_report(peer, CEVNT_BADTIME); + 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. + */ + + 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 clock signal quality is unknown, revert to default PRECISION...*/ - if(up->quality == QUALITY_UNKNOWN) { peer->precision = PRECISION; } - /* ...else improve precision if flag3 is set... */ - else { - peer->precision = ((pp->sloppyclockflag & CLK_FLAG3) ? - HIGHPRECISION : PRECISION); + 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 ARCRON_DEBUG +#ifdef DEBUG msyslog(LOG_NOTICE, "ARCRON: flags enabled: %s%s%s%s", ((pp->sloppyclockflag & CLK_FLAG1) ? "1" : "."), ((pp->sloppyclockflag & CLK_FLAG2) ? "2" : "."), @@ -1156,8 +1357,6 @@ arc_receive( ((pp->sloppyclockflag & CLK_FLAG4) ? "4" : ".")); /* Note effects of flags changing... */ if(debug) { - printf("arc: CHOSENSAMPLES(pp) = %d.\n", CHOSENSAMPLES(pp)); - printf("arc: NKEEP(pp) = %d.\n", NKEEP(pp)); printf("arc: PRECISION = %d.\n", peer->precision); } #endif @@ -1185,9 +1384,11 @@ arc_receive( #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); } @@ -1208,9 +1409,12 @@ request_time( if(debug) { printf("arc: unit %d: requesting time.\n", unit); } #endif if (!send_slow(up, pp->io.fd, "o\r")) { -#ifdef ARCRON_DEBUG - msyslog(LOG_NOTICE, "ARCRON: unit %d: problem sending", unit); +#ifdef DEBUG + if (debug) { + printf("arc: unit %d: problem sending", unit); + } #endif + pp->lencode = 0; refclock_report(peer, CEVNT_FAULT); return; } @@ -1232,8 +1436,10 @@ arc_poll( pp = peer->procptr; up = (struct arcunit *)pp->unitptr; +#if 0 pp->lencode = 0; memset(pp->a_lastcode, 0, sizeof(pp->a_lastcode)); +#endif #if 0 /* Flush input. */ @@ -1241,7 +1447,8 @@ arc_poll( #endif /* Resync if our next scheduled resync time is here or has passed. */ - resync_needed = (up->next_resync <= current_time); + resync_needed = ( !(pp->sloppyclockflag & CLK_FLAG2) && + (up->next_resync <= current_time) ); #ifdef ARCRON_LEAPSECOND_KEEN /* @@ -1309,6 +1516,7 @@ arc_poll( printf("arc: clock quality %d too poor.\n", up->quality); } #endif + pp->lencode = 0; refclock_report(peer, CEVNT_FAULT); return; } |