File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / ntp / ntpd / refclock_arc.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Tue May 29 12:08:37 2012 UTC (12 years, 1 month ago) by misho
Branches: ntp, MAIN
CVS tags: v4_2_6p5p0, v4_2_6p5, HEAD
ntp 4.2.6p5

    1: /*
    2:  * refclock_arc - clock driver for ARCRON MSF/DCF/WWVB receivers
    3:  */
    4: 
    5: #ifdef HAVE_CONFIG_H
    6: #include <config.h>
    7: #endif
    8: 
    9: #if defined(REFCLOCK) && defined(CLOCK_ARCRON_MSF)
   10: 
   11: static const char arc_version[] = { "V1.3 2003/02/21" };
   12: 
   13: /* define PRE_NTP420 for compatibility to previous versions of NTP (at least
   14:    to 4.1.0 */
   15: #undef PRE_NTP420
   16: 
   17: #ifndef ARCRON_NOT_KEEN
   18: #define ARCRON_KEEN 1 /* Be keen, and trusting of the clock, if defined. */
   19: #endif
   20: 
   21: #ifndef ARCRON_NOT_MULTIPLE_SAMPLES
   22: #define ARCRON_MULTIPLE_SAMPLES 1 /* Use all timestamp bytes as samples. */
   23: #endif
   24: 
   25: #ifndef ARCRON_NOT_LEAPSECOND_KEEN
   26: #ifndef ARCRON_LEAPSECOND_KEEN
   27: #undef ARCRON_LEAPSECOND_KEEN /* Respond quickly to leap seconds: doesn't work yet. */
   28: #endif
   29: #endif
   30: 
   31: /*
   32: Code by Derek Mulcahy, <derek@toybox.demon.co.uk>, 1997.
   33: Modifications by Damon Hart-Davis, <d@hd.org>, 1997.
   34: Modifications by Paul Alfille, <palfille@partners.org>, 2003.
   35: Modifications by Christopher Price, <cprice@cs-home.com>, 2003.
   36: Modifications by Nigel Roles <nigel@9fs.org>, 2003.
   37: 
   38: 
   39: THIS CODE IS SUPPLIED AS IS, WITH NO WARRANTY OF ANY KIND.  USE AT
   40: YOUR OWN RISK.
   41: 
   42: Orginally developed and used with ntp3-5.85 by Derek Mulcahy.
   43: 
   44: Built against ntp3-5.90 on Solaris 2.5 using gcc 2.7.2.
   45: 
   46: This code may be freely copied and used and incorporated in other
   47: systems providing the disclaimer and notice of authorship are
   48: reproduced.
   49: 
   50: -------------------------------------------------------------------------------
   51: 
   52: Nigel's notes:
   53: 
   54: 1) Called tcgetattr() before modifying, so that fields correctly initialised
   55:    for all operating systems
   56: 
   57: 2) Altered parsing of timestamp line so that it copes with fields which are
   58:    not always ASCII digits (e.g. status field when battery low)
   59: 
   60: -------------------------------------------------------------------------------
   61: 
   62: Christopher's notes:
   63: 
   64: MAJOR CHANGES SINCE V1.2 
   65: ========================
   66:  1) Applied patch by Andrey Bray <abuse@madhouse.demon.co.uk>
   67:     2001-02-17 comp.protocols.time.ntp
   68: 
   69:  2) Added WWVB support via clock mode command, localtime/UTC time configured
   70:     via flag1=(0=UTC, 1=localtime)
   71: 
   72:  3) Added ignore resync request via flag2=(0=resync, 1=ignore resync)
   73: 
   74:  4) Added simplified conversion from localtime to UTC with dst/bst translation
   75: 
   76:  5) Added average signal quality poll
   77: 
   78:  6) Fixed a badformat error when no code is available due to stripping 
   79:     \n & \r's 
   80: 
   81:  7) Fixed a badformat error when clearing lencode & memset a_lastcode in poll
   82:     routine
   83: 
   84:  8) Lots of code cleanup, including standardized DEBUG macros and removal 
   85:     of unused code 
   86: 
   87: -------------------------------------------------------------------------------
   88: 
   89: Author's original note:
   90: 
   91: I enclose my ntp driver for the Galleon Systems Arc MSF receiver.
   92: 
   93: It works (after a fashion) on both Solaris-1 and Solaris-2.
   94: 
   95: I am currently using ntp3-5.85.  I have been running the code for
   96: about 7 months without any problems.  Even coped with the change to BST!
   97: 
   98: I had to do some funky things to read from the clock because it uses the
   99: power from the receive lines to drive the transmit lines.  This makes the
  100: code look a bit stupid but it works.  I also had to put in some delays to
  101: allow for the turnaround time from receive to transmit.  These delays
  102: are between characters when requesting a time stamp so that shouldn't affect
  103: the results too drastically.
  104: 
  105: ...
  106: 
  107: The bottom line is that it works but could easily be improved.  You are
  108: free to do what you will with the code.  I haven't been able to determine
  109: how good the clock is.  I think that this requires a known good clock
  110: to compare it against.
  111: 
  112: -------------------------------------------------------------------------------
  113: 
  114: Damon's notes for adjustments:
  115: 
  116: MAJOR CHANGES SINCE V1.0
  117: ========================
  118:  1) Removal of pollcnt variable that made the clock go permanently
  119:     off-line once two time polls failed to gain responses.
  120: 
  121:  2) Avoiding (at least on Solaris-2) terminal becoming the controlling
  122:     terminal of the process when we do a low-level open().
  123: 
  124:  3) Additional logic (conditional on ARCRON_LEAPSECOND_KEEN being
  125:     defined) to try to resync quickly after a potential leap-second
  126:     insertion or deletion.
  127: 
  128:  4) Code significantly slimmer at run-time than V1.0.
  129: 
  130: 
  131: GENERAL
  132: =======
  133: 
  134:  1) The C preprocessor symbol to have the clock built has been changed
  135:     from ARC to ARCRON_MSF to CLOCK_ARCRON_MSF to minimise the
  136:     possiblity of clashes with other symbols in the future.
  137: 
  138:  2) PRECISION should be -4/-5 (63ms/31ms) for the following reasons:
  139: 
  140:      a) The ARC documentation claims the internal clock is (only)
  141: 	accurate to about 20ms relative to Rugby (plus there must be
  142: 	noticable drift and delay in the ms range due to transmission
  143: 	delays and changing atmospheric effects).  This clock is not
  144: 	designed for ms accuracy as NTP has spoilt us all to expect.
  145: 
  146:      b) The clock oscillator looks like a simple uncompensated quartz
  147: 	crystal of the sort used in digital watches (ie 32768Hz) which
  148: 	can have large temperature coefficients and drifts; it is not
  149: 	clear if this oscillator is properly disciplined to the MSF
  150: 	transmission, but as the default is to resync only once per
  151: 	*day*, we can imagine that it is not, and is free-running.  We
  152: 	can minimise drift by resyncing more often (at the cost of
  153: 	reduced battery life), but drift/wander may still be
  154: 	significant.
  155: 
  156:      c) Note that the bit time of 3.3ms adds to the potential error in
  157: 	the the clock timestamp, since the bit clock of the serial link
  158: 	may effectively be free-running with respect to the host clock
  159: 	and the MSF clock.  Actually, the error is probably 1/16th of
  160: 	the above, since the input data is probably sampled at at least
  161: 	16x the bit rate.
  162: 
  163:     By keeping the clock marked as not very precise, it will have a
  164:     fairly large dispersion, and thus will tend to be used as a
  165:     `backup' time source and sanity checker, which this clock is
  166:     probably ideal for.  For an isolated network without other time
  167:     sources, this clock can probably be expected to provide *much*
  168:     better than 1s accuracy, which will be fine.
  169: 
  170:     By default, PRECISION is set to -4, but experience, especially at a
  171:     particular geographic location with a particular clock, may allow
  172:     this to be altered to -5.  (Note that skews of +/- 10ms are to be
  173:     expected from the clock from time-to-time.)  This improvement of
  174:     reported precision can be instigated by setting flag3 to 1, though
  175:     the PRECISION will revert to the normal value while the clock
  176:     signal quality is unknown whatever the flag3 setting.
  177: 
  178:     IN ANY CASE, BE SURE TO SET AN APPROPRIATE FUDGE FACTOR TO REMOVE
  179:     ANY RESIDUAL SKEW, eg:
  180: 
  181: 	server 127.127.27.0 # ARCRON MSF radio clock unit 0.
  182: 	# Fudge timestamps by about 20ms.
  183: 	fudge 127.127.27.0 time1 0.020
  184: 
  185:     You will need to observe your system's behaviour, assuming you have
  186:     some other NTP source to compare it with, to work out what the
  187:     fudge factor should be.  For my Sun SS1 running SunOS 4.1.3_U1 with
  188:     my MSF clock with my distance from the MSF transmitter, +20ms
  189:     seemed about right, after some observation.
  190: 
  191:  3) REFID has been made "MSFa" to reflect the MSF time source and the
  192:     ARCRON receiver.
  193: 
  194:  4) DEFAULT_RESYNC_TIME is the time in seconds (by default) before
  195:     forcing a resync since the last attempt.  This is picked to give a
  196:     little less than an hour between resyncs and to try to avoid
  197:     clashing with any regular event at a regular time-past-the-hour
  198:     which might cause systematic errors.
  199: 
  200:     The INITIAL_RESYNC_DELAY is to avoid bothering the clock and
  201:     running down its batteries unnecesarily if ntpd is going to crash
  202:     or be killed or reconfigured quickly.  If ARCRON_KEEN is defined
  203:     then this period is long enough for (with normal polling rates)
  204:     enough time samples to have been taken to allow ntpd to sync to
  205:     the clock before the interruption for the clock to resync to MSF.
  206:     This avoids ntpd syncing to another peer first and then
  207:     almost immediately hopping to the MSF clock.
  208: 
  209:     The RETRY_RESYNC_TIME is used before rescheduling a resync after a
  210:     resync failed to reveal a statisfatory signal quality (too low or
  211:     unknown).
  212: 
  213:  5) The clock seems quite jittery, so I have increased the
  214:     median-filter size from the typical (previous) value of 3.  I
  215:     discard up to half the results in the filter.  It looks like maybe
  216:     1 sample in 10 or so (maybe less) is a spike, so allow the median
  217:     filter to discard at least 10% of its entries or 1 entry, whichever
  218:     is greater.
  219: 
  220:  6) Sleeping *before* each character sent to the unit to allow required
  221:     inter-character time but without introducting jitter and delay in
  222:     handling the response if possible.
  223: 
  224:  7) If the flag ARCRON_KEEN is defined, take time samples whenever
  225:     possible, even while resyncing, etc.  We rely, in this case, on the
  226:     clock always giving us a reasonable time or else telling us in the
  227:     status byte at the end of the timestamp that it failed to sync to
  228:     MSF---thus we should never end up syncing to completely the wrong
  229:     time.
  230: 
  231:  8) If the flag ARCRON_OWN_FILTER is defined, use own versions of
  232:     refclock median-filter routines to get round small bug in 3-5.90
  233:     code which does not return the median offset. XXX Removed this
  234:     bit due NTP Version 4 upgrade - dlm.
  235: 
  236:  9) We would appear to have a year-2000 problem with this clock since
  237:     it returns only the two least-significant digits of the year.  But
  238:     ntpd ignores the year and uses the local-system year instead, so
  239:     this is in fact not a problem.  Nevertheless, we attempt to do a
  240:     sensible thing with the dates, wrapping them into a 100-year
  241:     window.
  242: 
  243:  10)Logs stats information that can be used by Derek's Tcl/Tk utility
  244:     to show the status of the clock.
  245: 
  246:  11)The clock documentation insists that the number of bits per
  247:     character to be sent to the clock, and sent by it, is 11, including
  248:     one start bit and two stop bits.  The data format is either 7+even
  249:     or 8+none.
  250: 
  251: 
  252: TO-DO LIST
  253: ==========
  254: 
  255:   * Eliminate use of scanf(), and maybe sprintf().
  256: 
  257:   * Allow user setting of resync interval to trade battery life for
  258:     accuracy; maybe could be done via fudge factor or unit number.
  259: 
  260:   * Possibly note the time since the last resync of the MSF clock to
  261:     MSF as the age of the last reference timestamp, ie trust the
  262:     clock's oscillator not very much...
  263: 
  264:   * Add very slow auto-adjustment up to a value of +/- time2 to correct
  265:     for long-term errors in the clock value (time2 defaults to 0 so the
  266:     correction would be disabled by default).
  267: 
  268:   * Consider trying to use the tty_clk/ppsclock support.
  269: 
  270:   * Possibly use average or maximum signal quality reported during
  271:     resync, rather than just the last one, which may be atypical.
  272: 
  273: */
  274: 
  275: 
  276: /* Notes for HKW Elektronik GmBH Radio clock driver */
  277: /* Author Lyndon David, Sentinet Ltd, Feb 1997      */
  278: /* These notes seem also to apply usefully to the ARCRON clock. */
  279: 
  280: /* The HKW clock module is a radio receiver tuned into the Rugby */
  281: /* MSF time signal tranmitted on 60 kHz. The clock module connects */
  282: /* to the computer via a serial line and transmits the time encoded */
  283: /* in 15 bytes at 300 baud 7 bits two stop bits even parity */
  284: 
  285: /* Clock communications, from the datasheet */
  286: /* All characters sent to the clock are echoed back to the controlling */
  287: /* device. */
  288: /* Transmit time/date information */
  289: /* syntax ASCII o<cr> */
  290: /* Character o may be replaced if neccesary by a character whose code */
  291: /* contains the lowest four bits f(hex) eg */
  292: /* syntax binary: xxxx1111 00001101 */
  293: 
  294: /* DHD note:
  295: You have to wait for character echo + 10ms before sending next character.
  296: */
  297: 
  298: /* The clock replies to this command with a sequence of 15 characters */
  299: /* which contain the complete time and a final <cr> making 16 characters */
  300: /* in total. */
  301: /* The RC computer clock will not reply immediately to this command because */
  302: /* the start bit edge of the first reply character marks the beginning of */
  303: /* the second. So the RC Computer Clock will reply to this command at the */
  304: /* start of the next second */
  305: /* The characters have the following meaning */
  306: /* 1. hours tens   */
  307: /* 2. hours units  */
  308: /* 3. minutes tens */
  309: /* 4. minutes units */
  310: /* 5. seconds tens  */
  311: /* 6. seconds units */
  312: /* 7. day of week 1-monday 7-sunday */
  313: /* 8. day of month tens */
  314: /* 9. day of month units */
  315: /* 10. month tens */
  316: /* 11. month units */
  317: /* 12. year tens */
  318: /* 13. year units */
  319: /* 14. BST/UTC status */
  320: /*	bit 7	parity */
  321: /*	bit 6	always 0 */
  322: /*	bit 5	always 1 */
  323: /*	bit 4	always 1 */
  324: /*	bit 3	always 0 */
  325: /*	bit 2	=1 if UTC is in effect, complementary to the BST bit */
  326: /*	bit 1	=1 if BST is in effect, according to the BST bit     */
  327: /*	bit 0	BST/UTC change impending bit=1 in case of change impending */
  328: /* 15. status */
  329: /*	bit 7	parity */
  330: /*	bit 6	always 0 */
  331: /*	bit 5	always 1 */
  332: /*	bit 4	always 1 */
  333: /*	bit 3	=1 if low battery is detected */
  334: /*	bit 2	=1 if the very last reception attempt failed and a valid */
  335: /*		time information already exists (bit0=1) */
  336: /*		=0 if the last reception attempt was successful */
  337: /*	bit 1	=1 if at least one reception since 2:30 am was successful */
  338: /*		=0 if no reception attempt since 2:30 am was successful */
  339: /*	bit 0	=1 if the RC Computer Clock contains valid time information */
  340: /*		This bit is zero after reset and one after the first */
  341: /*		successful reception attempt */
  342: 
  343: /* DHD note:
  344: Also note g<cr> command which confirms that a resync is in progress, and
  345: if so what signal quality (0--5) is available.
  346: Also note h<cr> command which starts a resync to MSF signal.
  347: */
  348: 
  349: 
  350: #include "ntpd.h"
  351: #include "ntp_io.h"
  352: #include "ntp_refclock.h"
  353: #include "ntp_calendar.h"
  354: #include "ntp_stdlib.h"
  355: 
  356: #include <stdio.h>
  357: #include <ctype.h>
  358: 
  359: #if defined(HAVE_BSD_TTYS)
  360: #include <sgtty.h>
  361: #endif /* HAVE_BSD_TTYS */
  362: 
  363: #if defined(HAVE_SYSV_TTYS)
  364: #include <termio.h>
  365: #endif /* HAVE_SYSV_TTYS */
  366: 
  367: #if defined(HAVE_TERMIOS)
  368: #include <termios.h>
  369: #endif
  370: 
  371: /*
  372:  * This driver supports the ARCRON MSF/DCF/WWVB Radio Controlled Clock
  373:  */
  374: 
  375: /*
  376:  * Interface definitions
  377:  */
  378: #define DEVICE		"/dev/arc%d"	/* Device name and unit. */
  379: #define SPEED		B300		/* UART speed (300 baud) */
  380: #define PRECISION	(-4)		/* Precision  (~63 ms). */
  381: #define HIGHPRECISION	(-5)		/* If things are going well... */
  382: #define REFID		"MSFa"		/* Reference ID. */
  383: #define REFID_MSF	"MSF"		/* Reference ID. */
  384: #define REFID_DCF77	"DCF"		/* Reference ID. */
  385: #define REFID_WWVB	"WWVB"		/* Reference ID. */
  386: #define DESCRIPTION	"ARCRON MSF/DCF/WWVB Receiver"
  387: 
  388: #ifdef PRE_NTP420
  389: #define MODE ttlmax
  390: #else
  391: #define MODE ttl
  392: #endif
  393: 
  394: #define LENARC		16		/* Format `o' timecode length. */
  395: 
  396: #define BITSPERCHAR	11		/* Bits per character. */
  397: #define BITTIME		0x0DA740E	/* Time for 1 bit at 300bps. */
  398: #define CHARTIME10	0x8888888	/* Time for 10-bit char at 300bps. */
  399: #define CHARTIME11	0x962FC96	/* Time for 11-bit char at 300bps. */
  400: #define CHARTIME			/* Time for char at 300bps. */ \
  401: ( (BITSPERCHAR == 11) ? CHARTIME11 : ( (BITSPERCHAR == 10) ? CHARTIME10 : \
  402: 				       (BITSPERCHAR * BITTIME) ) )
  403: 
  404:      /* Allow for UART to accept char half-way through final stop bit. */
  405: #define INITIALOFFSET (u_int32)(-BITTIME/2)
  406: 
  407:      /*
  408:     charoffsets[x] is the time after the start of the second that byte
  409:     x (with the first byte being byte 1) is received by the UART,
  410:     assuming that the initial edge of the start bit of the first byte
  411:     is on-time.  The values are represented as the fractional part of
  412:     an l_fp.
  413: 
  414:     We store enough values to have the offset of each byte including
  415:     the trailing \r, on the assumption that the bytes follow one
  416:     another without gaps.
  417:     */
  418:      static const u_int32 charoffsets[LENARC+1] = {
  419: #if BITSPERCHAR == 11 /* Usual case. */
  420: 	     /* Offsets computed as accurately as possible... */
  421: 	     0,
  422: 	     INITIALOFFSET + 0x0962fc96, /*  1 chars,  11 bits */
  423: 	     INITIALOFFSET + 0x12c5f92c, /*  2 chars,  22 bits */
  424: 	     INITIALOFFSET + 0x1c28f5c3, /*  3 chars,  33 bits */
  425: 	     INITIALOFFSET + 0x258bf259, /*  4 chars,  44 bits */
  426: 	     INITIALOFFSET + 0x2eeeeeef, /*  5 chars,  55 bits */
  427: 	     INITIALOFFSET + 0x3851eb85, /*  6 chars,  66 bits */
  428: 	     INITIALOFFSET + 0x41b4e81b, /*  7 chars,  77 bits */
  429: 	     INITIALOFFSET + 0x4b17e4b1, /*  8 chars,  88 bits */
  430: 	     INITIALOFFSET + 0x547ae148, /*  9 chars,  99 bits */
  431: 	     INITIALOFFSET + 0x5dddddde, /* 10 chars, 110 bits */
  432: 	     INITIALOFFSET + 0x6740da74, /* 11 chars, 121 bits */
  433: 	     INITIALOFFSET + 0x70a3d70a, /* 12 chars, 132 bits */
  434: 	     INITIALOFFSET + 0x7a06d3a0, /* 13 chars, 143 bits */
  435: 	     INITIALOFFSET + 0x8369d037, /* 14 chars, 154 bits */
  436: 	     INITIALOFFSET + 0x8ccccccd, /* 15 chars, 165 bits */
  437: 	     INITIALOFFSET + 0x962fc963  /* 16 chars, 176 bits */
  438: #else
  439: 	     /* Offsets computed with a small rounding error... */
  440: 	     0,
  441: 	     INITIALOFFSET +  1 * CHARTIME,
  442: 	     INITIALOFFSET +  2 * CHARTIME,
  443: 	     INITIALOFFSET +  3 * CHARTIME,
  444: 	     INITIALOFFSET +  4 * CHARTIME,
  445: 	     INITIALOFFSET +  5 * CHARTIME,
  446: 	     INITIALOFFSET +  6 * CHARTIME,
  447: 	     INITIALOFFSET +  7 * CHARTIME,
  448: 	     INITIALOFFSET +  8 * CHARTIME,
  449: 	     INITIALOFFSET +  9 * CHARTIME,
  450: 	     INITIALOFFSET + 10 * CHARTIME,
  451: 	     INITIALOFFSET + 11 * CHARTIME,
  452: 	     INITIALOFFSET + 12 * CHARTIME,
  453: 	     INITIALOFFSET + 13 * CHARTIME,
  454: 	     INITIALOFFSET + 14 * CHARTIME,
  455: 	     INITIALOFFSET + 15 * CHARTIME,
  456: 	     INITIALOFFSET + 16 * CHARTIME
  457: #endif
  458:      };
  459: 
  460: #define DEFAULT_RESYNC_TIME  (57*60)	/* Gap between resync attempts (s). */
  461: #define RETRY_RESYNC_TIME    (27*60)	/* Gap to emergency resync attempt. */
  462: #ifdef ARCRON_KEEN
  463: #define INITIAL_RESYNC_DELAY 500	/* Delay before first resync. */
  464: #else
  465: #define INITIAL_RESYNC_DELAY 50		/* Delay before first resync. */
  466: #endif
  467: 
  468:      static const int moff[12] =
  469: { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 };
  470: /* Flags for a raw open() of the clock serial device. */
  471: #ifdef O_NOCTTY /* Good, we can avoid tty becoming controlling tty. */
  472: #define OPEN_FLAGS (O_RDWR | O_NOCTTY)
  473: #else		/* Oh well, it may not matter... */
  474: #define OPEN_FLAGS (O_RDWR)
  475: #endif
  476: 
  477: 
  478: /* Length of queue of command bytes to be sent. */
  479: #define CMDQUEUELEN 4			/* Enough for two cmds + each \r. */
  480: /* Queue tick time; interval in seconds between chars taken off queue. */
  481: /* Must be >= 2 to allow o\r response to come back uninterrupted. */
  482: #define QUEUETICK   2			/* Allow o\r reply to finish. */
  483: 
  484: /*
  485:  * ARC unit control structure
  486:  */
  487: struct arcunit {
  488: 	l_fp lastrec;	    /* Time tag for the receive time (system). */
  489: 	int status;	    /* Clock status. */
  490: 
  491: 	int quality;	    /* Quality of reception 0--5 for unit. */
  492: 	/* We may also use the values -1 or 6 internally. */
  493: 	u_long quality_stamp; /* Next time to reset quality average. */
  494: 
  495: 	u_long next_resync; /* Next resync time (s) compared to current_time. */
  496: 	int resyncing;	    /* Resync in progress if true. */
  497: 
  498: 	/* In the outgoing queue, cmdqueue[0] is next to be sent. */
  499: 	char cmdqueue[CMDQUEUELEN+1]; /* Queue of outgoing commands + \0. */
  500: 
  501: 	u_long saved_flags; /* Saved fudge flags. */
  502: };
  503: 
  504: #ifdef ARCRON_LEAPSECOND_KEEN
  505: /* The flag `possible_leap' is set non-zero when any MSF unit
  506:        thinks a leap-second may have happened.
  507: 
  508:        Set whenever we receive a valid time sample in the first hour of
  509:        the first day of the first/seventh months.
  510: 
  511:        Outside the special hour this value is unconditionally set
  512:        to zero by the receive routine.
  513: 
  514:        On finding itself in this timeslot, as long as the value is
  515:        non-negative, the receive routine sets it to a positive value to
  516:        indicate a resync to MSF should be performed.
  517: 
  518:        In the poll routine, if this value is positive and we are not
  519:        already resyncing (eg from a sync that started just before
  520:        midnight), start resyncing and set this value negative to
  521:        indicate that a leap-triggered resync has been started.  Having
  522:        set this negative prevents the receive routine setting it
  523:        positive and thus prevents multiple resyncs during the witching
  524:        hour.
  525:      */
  526: static int possible_leap = 0;       /* No resync required by default. */
  527: #endif
  528: 
  529: #if 0
  530: static void dummy_event_handler (struct peer *);
  531: static void   arc_event_handler (struct peer *);
  532: #endif /* 0 */
  533: 
  534: #define QUALITY_UNKNOWN	    -1 /* Indicates unknown clock quality. */
  535: #define MIN_CLOCK_QUALITY    0 /* Min quality clock will return. */
  536: #define MIN_CLOCK_QUALITY_OK 3 /* Min quality for OK reception. */
  537: #define MAX_CLOCK_QUALITY    5 /* Max quality clock will return. */
  538: 
  539: /*
  540:  * Function prototypes
  541:  */
  542: static	int	arc_start	(int, struct peer *);
  543: static	void	arc_shutdown	(int, struct peer *);
  544: static	void	arc_receive	(struct recvbuf *);
  545: static	void	arc_poll	(int, struct peer *);
  546: 
  547: /*
  548:  * Transfer vector
  549:  */
  550: struct  refclock refclock_arc = {
  551: 	arc_start,		/* start up driver */
  552: 	arc_shutdown,		/* shut down driver */
  553: 	arc_poll,		/* transmit poll message */
  554: 	noentry,		/* not used (old arc_control) */
  555: 	noentry,		/* initialize driver (not used) */
  556: 	noentry,		/* not used (old arc_buginfo) */
  557: 	NOFLAGS			/* not used */
  558: };
  559: 
  560: /* Queue us up for the next tick. */
  561: #define ENQUEUE(up) \
  562: 	do { \
  563: 	     peer->nextaction = current_time + QUEUETICK; \
  564: 	} while(0)
  565: 
  566: /* Placeholder event handler---does nothing safely---soaks up loose tick. */
  567: static void
  568: dummy_event_handler(
  569: 	struct peer *peer
  570: 	)
  571: {
  572: #ifdef DEBUG
  573: 	if(debug) { printf("arc: dummy_event_handler() called.\n"); }
  574: #endif
  575: }
  576: 
  577: /*
  578: Normal event handler.
  579: 
  580: Take first character off queue and send to clock if not a null.
  581: 
  582: Shift characters down and put a null on the end.
  583: 
  584: We assume that there is no parallelism so no race condition, but even
  585: if there is nothing bad will happen except that we might send some bad
  586: data to the clock once in a while.
  587: */
  588: static void
  589: arc_event_handler(
  590: 	struct peer *peer
  591: 	)
  592: {
  593: 	struct refclockproc *pp = peer->procptr;
  594: 	register struct arcunit *up = pp->unitptr;
  595: 	int i;
  596: 	char c;
  597: #ifdef DEBUG
  598: 	if(debug > 2) { printf("arc: arc_event_handler() called.\n"); }
  599: #endif
  600: 
  601: 	c = up->cmdqueue[0];       /* Next char to be sent. */
  602: 	/* Shift down characters, shifting trailing \0 in at end. */
  603: 	for(i = 0; i < CMDQUEUELEN; ++i)
  604: 	{ up->cmdqueue[i] = up->cmdqueue[i+1]; }
  605: 
  606: 	/* Don't send '\0' characters. */
  607: 	if(c != '\0') {
  608: 		if(write(pp->io.fd, &c, 1) != 1) {
  609: 			msyslog(LOG_NOTICE, "ARCRON: write to fd %d failed", pp->io.fd);
  610: 		}
  611: #ifdef DEBUG
  612: 		else if(debug) { printf("arc: sent `%2.2x', fd %d.\n", c, pp->io.fd); }
  613: #endif
  614: 	}
  615: 
  616: 	ENQUEUE(up);
  617: }
  618: 
  619: /*
  620:  * arc_start - open the devices and initialize data for processing
  621:  */
  622: static int
  623: arc_start(
  624: 	int unit,
  625: 	struct peer *peer
  626: 	)
  627: {
  628: 	register struct arcunit *up;
  629: 	struct refclockproc *pp;
  630: 	int temp_fd;
  631: 	int fd;
  632: 	char device[20];
  633: #ifdef HAVE_TERMIOS
  634: 	struct termios arg;
  635: #endif
  636: 
  637: 	msyslog(LOG_NOTICE, "MSF_ARCRON %s: opening unit %d",
  638: 		arc_version, unit);
  639: 	DPRINTF(1, ("arc: %s: attempt to open unit %d.\n", arc_version,
  640: 		unit));
  641: 
  642: 	/*
  643: 	 * Open serial port. Use CLK line discipline, if available.
  644: 	 */
  645: 	snprintf(device, sizeof(device), DEVICE, unit);
  646: 	temp_fd = refclock_open(device, SPEED, LDISC_CLK);
  647: 	if (temp_fd <= 0)
  648: 		return 0;
  649: 	DPRINTF(1, ("arc: unit %d using tty_open().\n", unit));
  650: 	fd = tty_open(device, OPEN_FLAGS, 0777);
  651: 	if (fd < 0) {
  652: 		msyslog(LOG_ERR, "MSF_ARCRON(%d): failed second open(%s, 0777): %m.\n",
  653: 			unit, device);
  654: 		close(temp_fd);
  655: 		return 0;
  656: 	}
  657: 	close(temp_fd);
  658: 	temp_fd = -1;
  659: 
  660: #ifndef SYS_WINNT
  661: 	fcntl(fd, F_SETFL, 0); /* clear the descriptor flags */
  662: #endif
  663: 	DPRINTF(1, ("arc: opened RS232 port with file descriptor %d.\n", fd));
  664: 
  665: #ifdef HAVE_TERMIOS
  666: 
  667: 	if (tcgetattr(fd, &arg) < 0) {
  668: 		msyslog(LOG_ERR, "MSF_ARCRON(%d): tcgetattr(%s): %m.\n",
  669: 			unit, device);
  670: 		close(fd);
  671: 		return 0;
  672: 	}
  673: 
  674: 	arg.c_iflag = IGNBRK | ISTRIP;
  675: 	arg.c_oflag = 0;
  676: 	arg.c_cflag = B300 | CS8 | CREAD | CLOCAL | CSTOPB;
  677: 	arg.c_lflag = 0;
  678: 	arg.c_cc[VMIN] = 1;
  679: 	arg.c_cc[VTIME] = 0;
  680: 
  681: 	if (tcsetattr(fd, TCSANOW, &arg) < 0) {
  682: 		msyslog(LOG_ERR, "MSF_ARCRON(%d): tcsetattr(%s): %m.\n",
  683: 			unit, device);
  684: 		close(fd);
  685: 		return 0;
  686: 	}
  687: 
  688: #else
  689: 
  690: 	msyslog(LOG_ERR, "ARCRON: termios required by this driver");
  691: 	(void)close(fd);
  692: 
  693: 	return 0;
  694: 
  695: #endif
  696: 
  697: 	/* Set structure to all zeros... */
  698: 	up = emalloc_zero(sizeof(*up));
  699: 	pp = peer->procptr;
  700: 	pp->io.clock_recv = arc_receive;
  701: 	pp->io.srcclock = (caddr_t)peer;
  702: 	pp->io.datalen = 0;
  703: 	pp->io.fd = fd;
  704: 	if (!io_addclock(&pp->io)) {
  705: 		close(fd);
  706: 		pp->io.fd = -1;
  707: 		free(up); 
  708: 		return(0); 
  709: 	}
  710: 	pp->unitptr = up;
  711: 
  712: 	/*
  713: 	 * Initialize miscellaneous variables
  714: 	 */
  715: 	peer->precision = PRECISION;
  716: 	peer->stratum = 2;              /* Default to stratum 2 not 0. */
  717: 	pp->clockdesc = DESCRIPTION;
  718: 	if (peer->MODE > 3) {
  719: 		msyslog(LOG_NOTICE, "ARCRON: Invalid mode %d", peer->MODE);
  720: 		return 0;
  721: 	}
  722: #ifdef DEBUG
  723: 	if(debug) { printf("arc: mode = %d.\n", peer->MODE); }
  724: #endif
  725: 	switch (peer->MODE) {
  726: 	    case 1:
  727: 		memcpy((char *)&pp->refid, REFID_MSF, 4);
  728: 		break;
  729: 	    case 2:
  730: 		memcpy((char *)&pp->refid, REFID_DCF77, 4);
  731: 		break;
  732: 	    case 3:
  733: 		memcpy((char *)&pp->refid, REFID_WWVB, 4);
  734: 		break;
  735: 	    default:
  736: 		memcpy((char *)&pp->refid, REFID, 4);
  737: 		break;
  738: 	}
  739: 	/* Spread out resyncs so that they should remain separated. */
  740: 	up->next_resync = current_time + INITIAL_RESYNC_DELAY + (67*unit)%1009;
  741: 
  742: #if 0 /* Not needed because of zeroing of arcunit structure... */
  743: 	up->resyncing = 0;              /* Not resyncing yet. */
  744: 	up->saved_flags = 0;            /* Default is all flags off. */
  745: 	/* Clear send buffer out... */
  746: 	{
  747: 		int i;
  748: 		for(i = CMDQUEUELEN; i >= 0; --i) { up->cmdqueue[i] = '\0'; }
  749: 	}
  750: #endif
  751: 
  752: #ifdef ARCRON_KEEN
  753: 	up->quality = QUALITY_UNKNOWN;  /* Trust the clock immediately. */
  754: #else
  755: 	up->quality = MIN_CLOCK_QUALITY;/* Don't trust the clock yet. */
  756: #endif
  757: 
  758: 	peer->action = arc_event_handler;
  759: 
  760: 	ENQUEUE(up);
  761: 
  762: 	return(1);
  763: }
  764: 
  765: 
  766: /*
  767:  * arc_shutdown - shut down the clock
  768:  */
  769: static void
  770: arc_shutdown(
  771: 	int unit,
  772: 	struct peer *peer
  773: 	)
  774: {
  775: 	register struct arcunit *up;
  776: 	struct refclockproc *pp;
  777: 
  778: 	peer->action = dummy_event_handler;
  779: 
  780: 	pp = peer->procptr;
  781: 	up = pp->unitptr;
  782: 	if (-1 != pp->io.fd)
  783: 		io_closeclock(&pp->io);
  784: 	if (NULL != up)
  785: 		free(up);
  786: }
  787: 
  788: /*
  789: Compute space left in output buffer.
  790: */
  791: static int
  792: space_left(
  793: 	register struct arcunit *up
  794: 	)
  795: {
  796: 	int spaceleft;
  797: 
  798: 	/* Compute space left in buffer after any pending output. */
  799: 	for(spaceleft = 0; spaceleft < CMDQUEUELEN; ++spaceleft)
  800: 	{ if(up->cmdqueue[CMDQUEUELEN - 1 - spaceleft] != '\0') { break; } }
  801: 	return(spaceleft);
  802: }
  803: 
  804: /*
  805: Send command by copying into command buffer as far forward as possible,
  806: after any pending output.
  807: 
  808: Indicate an error by returning 0 if there is not space for the command.
  809: */
  810: static int
  811: send_slow(
  812: 	register struct arcunit *up,
  813: 	int fd,
  814: 	const char *s
  815: 	)
  816: {
  817: 	int sl = strlen(s);
  818: 	int spaceleft = space_left(up);
  819: 
  820: #ifdef DEBUG
  821: 	if(debug > 1) { printf("arc: spaceleft = %d.\n", spaceleft); }
  822: #endif
  823: 	if(spaceleft < sl) { /* Should not normally happen... */
  824: #ifdef DEBUG
  825: 		msyslog(LOG_NOTICE, "ARCRON: send-buffer overrun (%d/%d)",
  826: 			sl, spaceleft);
  827: #endif
  828: 		return(0);			/* FAILED! */
  829: 	}
  830: 
  831: 	/* Copy in the command to be sent. */
  832: 	while(*s && spaceleft > 0) { up->cmdqueue[CMDQUEUELEN - spaceleft--] = *s++; }
  833: 
  834: 	return(1);
  835: }
  836: 
  837: 
  838: static int
  839: get2(char *p, int *val)
  840: {
  841:   if (!isdigit((int)p[0]) || !isdigit((int)p[1])) return 0;
  842:   *val = (p[0] - '0') * 10 + p[1] - '0';
  843:   return 1;
  844: }
  845: 
  846: static int
  847: get1(char *p, int *val)
  848: {
  849:   if (!isdigit((int)p[0])) return 0;
  850:   *val = p[0] - '0';
  851:   return 1;
  852: }
  853: 
  854: /* Macro indicating action we will take for different quality values. */
  855: #define quality_action(q) \
  856: (((q) == QUALITY_UNKNOWN) ?         "UNKNOWN, will use clock anyway" : \
  857:  (((q) < MIN_CLOCK_QUALITY_OK) ? "TOO POOR, will not use clock" : \
  858:   "OK, will use clock"))
  859: 
  860: /*
  861:  * arc_receive - receive data from the serial interface
  862:  */
  863: static void
  864: arc_receive(
  865: 	struct recvbuf *rbufp
  866: 	)
  867: {
  868: 	register struct arcunit *up;
  869: 	struct refclockproc *pp;
  870: 	struct peer *peer;
  871: 	char c;
  872: 	int i, n, wday, month, flags, status;
  873: 	int arc_last_offset;
  874: 	static int quality_average = 0;
  875: 	static int quality_sum = 0;
  876: 	static int quality_polls = 0;
  877: 
  878: 	/*
  879: 	 * Initialize pointers and read the timecode and timestamp
  880: 	 */
  881: 	peer = (struct peer *)rbufp->recv_srcclock;
  882: 	pp = peer->procptr;
  883: 	up = pp->unitptr;
  884: 
  885: 
  886: 	/*
  887: 	  If the command buffer is empty, and we are resyncing, insert a
  888: 	  g\r quality request into it to poll for signal quality again.
  889: 	*/
  890: 	if((up->resyncing) && (space_left(up) == CMDQUEUELEN)) {
  891: #ifdef DEBUG
  892: 		if(debug > 1) { printf("arc: inserting signal-quality poll.\n"); }
  893: #endif
  894: 		send_slow(up, pp->io.fd, "g\r");
  895: 	}
  896: 
  897: 	/*
  898: 	  The `arc_last_offset' is the offset in lastcode[] of the last byte
  899: 	  received, and which we assume actually received the input
  900: 	  timestamp.
  901: 
  902: 	  (When we get round to using tty_clk and it is available, we
  903: 	  assume that we will receive the whole timecode with the
  904: 	  trailing \r, and that that \r will be timestamped.  But this
  905: 	  assumption also works if receive the characters one-by-one.)
  906: 	*/
  907: 	arc_last_offset = pp->lencode+rbufp->recv_length - 1;
  908: 
  909: 	/*
  910: 	  We catch a timestamp iff:
  911: 
  912: 	  * The command code is `o' for a timestamp.
  913: 
  914: 	  * If ARCRON_MULTIPLE_SAMPLES is undefined then we must have
  915: 	  exactly char in the buffer (the command code) so that we
  916: 	  only sample the first character of the timecode as our
  917: 	  `on-time' character.
  918: 
  919: 	  * The first character in the buffer is not the echoed `\r'
  920: 	  from the `o` command (so if we are to timestamp an `\r' it
  921: 	  must not be first in the receive buffer with lencode==1.
  922: 	  (Even if we had other characters following it, we probably
  923: 	  would have a premature timestamp on the '\r'.)
  924: 
  925: 	  * We have received at least one character (I cannot imagine
  926: 	  how it could be otherwise, but anyway...).
  927: 	*/
  928: 	c = rbufp->recv_buffer[0];
  929: 	if((pp->a_lastcode[0] == 'o') &&
  930: #ifndef ARCRON_MULTIPLE_SAMPLES
  931: 	   (pp->lencode == 1) &&
  932: #endif
  933: 	   ((pp->lencode != 1) || (c != '\r')) &&
  934: 	   (arc_last_offset >= 1)) {
  935: 		/* Note that the timestamp should be corrected if >1 char rcvd. */
  936: 		l_fp timestamp;
  937: 		timestamp = rbufp->recv_time;
  938: #ifdef DEBUG
  939: 		if(debug) { /* Show \r as `R', other non-printing char as `?'. */
  940: 			printf("arc: stamp -->%c<-- (%d chars rcvd)\n",
  941: 			       ((c == '\r') ? 'R' : (isgraph((int)c) ? c : '?')),
  942: 			       rbufp->recv_length);
  943: 		}
  944: #endif
  945: 
  946: 		/*
  947: 		  Now correct timestamp by offset of last byte received---we
  948: 		  subtract from the receive time the delay implied by the
  949: 		  extra characters received.
  950: 
  951: 		  Reject the input if the resulting code is too long, but
  952: 		  allow for the trailing \r, normally not used but a good
  953: 		  handle for tty_clk or somesuch kernel timestamper.
  954: 		*/
  955: 		if(arc_last_offset > LENARC) {
  956: #ifdef DEBUG
  957: 			if(debug) {
  958: 				printf("arc: input code too long (%d cf %d); rejected.\n",
  959: 				       arc_last_offset, LENARC);
  960: 			}
  961: #endif
  962: 			pp->lencode = 0;
  963: 			refclock_report(peer, CEVNT_BADREPLY);
  964: 			return;
  965: 		}
  966: 
  967: 		L_SUBUF(&timestamp, charoffsets[arc_last_offset]);
  968: #ifdef DEBUG
  969: 		if(debug > 1) {
  970: 			printf(
  971: 				"arc: %s%d char(s) rcvd, the last for lastcode[%d]; -%sms offset applied.\n",
  972: 				((rbufp->recv_length > 1) ? "*** " : ""),
  973: 				rbufp->recv_length,
  974: 				arc_last_offset,
  975: 				mfptoms((unsigned long)0,
  976: 					charoffsets[arc_last_offset],
  977: 					1));
  978: 		}
  979: #endif
  980: 
  981: #ifdef ARCRON_MULTIPLE_SAMPLES
  982: 		/*
  983: 		  If taking multiple samples, capture the current adjusted
  984: 		  sample iff:
  985: 
  986: 		  * No timestamp has yet been captured (it is zero), OR
  987: 
  988: 		  * This adjusted timestamp is earlier than the one already
  989: 		  captured, on the grounds that this one suffered less
  990: 		  delay in being delivered to us and is more accurate.
  991: 
  992: 		*/
  993: 		if(L_ISZERO(&(up->lastrec)) ||
  994: 		   L_ISGEQ(&(up->lastrec), &timestamp))
  995: #endif
  996: 		{
  997: #ifdef DEBUG
  998: 			if(debug > 1) {
  999: 				printf("arc: system timestamp captured.\n");
 1000: #ifdef ARCRON_MULTIPLE_SAMPLES
 1001: 				if(!L_ISZERO(&(up->lastrec))) {
 1002: 					l_fp diff;
 1003: 					diff = up->lastrec;
 1004: 					L_SUB(&diff, &timestamp);
 1005: 					printf("arc: adjusted timestamp by -%sms.\n",
 1006: 					       mfptoms(diff.l_i, diff.l_f, 3));
 1007: 				}
 1008: #endif
 1009: 			}
 1010: #endif
 1011: 			up->lastrec = timestamp;
 1012: 		}
 1013: 
 1014: 	}
 1015: 
 1016: 	/* Just in case we still have lots of rubbish in the buffer... */
 1017: 	/* ...and to avoid the same timestamp being reused by mistake, */
 1018: 	/* eg on receipt of the \r coming in on its own after the      */
 1019: 	/* timecode.						       */
 1020: 	if(pp->lencode >= LENARC) {
 1021: #ifdef DEBUG
 1022: 		if(debug && (rbufp->recv_buffer[0] != '\r'))
 1023: 		{ printf("arc: rubbish in pp->a_lastcode[].\n"); }
 1024: #endif
 1025: 		pp->lencode = 0;
 1026: 		return;
 1027: 	}
 1028: 
 1029: 	/* Append input to code buffer, avoiding overflow. */
 1030: 	for(i = 0; i < rbufp->recv_length; i++) {
 1031: 		if(pp->lencode >= LENARC) { break; } /* Avoid overflow... */
 1032: 		c = rbufp->recv_buffer[i];
 1033: 
 1034: 		/* Drop trailing '\r's and drop `h' command echo totally. */
 1035: 		if(c != '\r' && c != 'h') { pp->a_lastcode[pp->lencode++] = c; }
 1036: 
 1037: 		/*
 1038: 		  If we've just put an `o' in the lastcode[0], clear the
 1039: 		  timestamp in anticipation of a timecode arriving soon.
 1040: 
 1041: 		  We would expect to get to process this before any of the
 1042: 		  timecode arrives.
 1043: 		*/
 1044: 		if((c == 'o') && (pp->lencode == 1)) {
 1045: 			L_CLR(&(up->lastrec));
 1046: #ifdef DEBUG
 1047: 			if(debug > 1) { printf("arc: clearing timestamp.\n"); }
 1048: #endif
 1049: 		}
 1050: 	}
 1051: 	if (pp->lencode == 0) return;
 1052: 
 1053: 	/* Handle a quality message. */
 1054: 	if(pp->a_lastcode[0] == 'g') {
 1055: 		int r, q;
 1056: 
 1057: 		if(pp->lencode < 3) { return; } /* Need more data... */
 1058: 		r = (pp->a_lastcode[1] & 0x7f); /* Strip parity. */
 1059: 		q = (pp->a_lastcode[2] & 0x7f); /* Strip parity. */
 1060: 		if(((q & 0x70) != 0x30) || ((q & 0xf) > MAX_CLOCK_QUALITY) ||
 1061: 		   ((r & 0x70) != 0x30)) {
 1062: 			/* Badly formatted response. */
 1063: #ifdef DEBUG
 1064: 			if(debug) { printf("arc: bad `g' response %2x %2x.\n", r, q); }
 1065: #endif
 1066: 			return;
 1067: 		}
 1068: 		if(r == '3') { /* Only use quality value whilst sync in progress. */
 1069: 			if (up->quality_stamp < current_time) {
 1070: 				struct calendar cal;
 1071: 				l_fp new_stamp;
 1072: 			
 1073: 				get_systime (&new_stamp);
 1074: 				caljulian (new_stamp.l_ui, &cal);
 1075: 				up->quality_stamp = 
 1076: 					current_time + 60 - cal.second + 5;
 1077: 				quality_sum = 0;
 1078: 				quality_polls = 0;
 1079: 			}
 1080: 			quality_sum += (q & 0xf);
 1081: 			quality_polls++;
 1082: 			quality_average = (quality_sum / quality_polls);
 1083: #ifdef DEBUG
 1084: 			if(debug) { printf("arc: signal quality %d (%d).\n", quality_average, (q & 0xf)); }
 1085: #endif
 1086: 		} else if( /* (r == '2') && */ up->resyncing) {
 1087: 			up->quality = quality_average;
 1088: #ifdef DEBUG
 1089: 			if(debug)
 1090: 			{
 1091: 				printf("arc: sync finished, signal quality %d: %s\n",
 1092: 				       up->quality,
 1093: 				       quality_action(up->quality));
 1094: 			}
 1095: #endif
 1096: 			msyslog(LOG_NOTICE,
 1097: 				"ARCRON: sync finished, signal quality %d: %s",
 1098: 				up->quality,
 1099: 				quality_action(up->quality));
 1100: 			up->resyncing = 0; /* Resync is over. */
 1101: 			quality_average = 0;
 1102: 			quality_sum = 0;
 1103: 			quality_polls = 0;
 1104: 
 1105: #ifdef ARCRON_KEEN
 1106: 			/* Clock quality dubious; resync earlier than usual. */
 1107: 			if((up->quality == QUALITY_UNKNOWN) ||
 1108: 			   (up->quality < MIN_CLOCK_QUALITY_OK))
 1109: 			{ up->next_resync = current_time + RETRY_RESYNC_TIME; }
 1110: #endif
 1111: 		}
 1112: 		pp->lencode = 0;
 1113: 		return;
 1114: 	}
 1115: 
 1116: 	/* Stop now if this is not a timecode message. */
 1117: 	if(pp->a_lastcode[0] != 'o') {
 1118: 		pp->lencode = 0;
 1119: 		refclock_report(peer, CEVNT_BADREPLY);
 1120: 		return;
 1121: 	}
 1122: 
 1123: 	/* If we don't have enough data, wait for more... */
 1124: 	if(pp->lencode < LENARC) { return; }
 1125: 
 1126: 
 1127: 	/* WE HAVE NOW COLLECTED ONE TIMESTAMP (phew)... */
 1128: #ifdef DEBUG
 1129: 	if(debug > 1) { printf("arc: NOW HAVE TIMESTAMP...\n"); }
 1130: #endif
 1131: 
 1132: 	/* But check that we actually captured a system timestamp on it. */
 1133: 	if(L_ISZERO(&(up->lastrec))) {
 1134: #ifdef DEBUG
 1135: 		if(debug) { printf("arc: FAILED TO GET SYSTEM TIMESTAMP\n"); }
 1136: #endif
 1137: 		pp->lencode = 0;
 1138: 		refclock_report(peer, CEVNT_BADREPLY);
 1139: 		return;
 1140: 	}
 1141: 	/*
 1142: 	  Append a mark of the clock's received signal quality for the
 1143: 	  benefit of Derek Mulcahy's Tcl/Tk utility (we map the `unknown'
 1144: 	  quality value to `6' for his s/w) and terminate the string for
 1145: 	  sure.  This should not go off the buffer end.
 1146: 	*/
 1147: 	pp->a_lastcode[pp->lencode] = ((up->quality == QUALITY_UNKNOWN) ?
 1148: 				       '6' : ('0' + up->quality));
 1149: 	pp->a_lastcode[pp->lencode + 1] = '\0'; /* Terminate for printf(). */
 1150: 
 1151: #ifdef PRE_NTP420
 1152: 	/* We don't use the micro-/milli- second part... */
 1153: 	pp->usec = 0;
 1154: 	pp->msec = 0;
 1155: #else
 1156: 	/* We don't use the nano-second part... */
 1157: 	pp->nsec = 0;
 1158: #endif	
 1159: 	/* Validate format and numbers. */
 1160: 	if (pp->a_lastcode[0] != 'o'
 1161: 		|| !get2(pp->a_lastcode + 1, &pp->hour)
 1162: 		|| !get2(pp->a_lastcode + 3, &pp->minute)
 1163: 		|| !get2(pp->a_lastcode + 5, &pp->second)
 1164: 		|| !get1(pp->a_lastcode + 7, &wday)
 1165: 		|| !get2(pp->a_lastcode + 8, &pp->day)
 1166: 		|| !get2(pp->a_lastcode + 10, &month)
 1167: 		|| !get2(pp->a_lastcode + 12, &pp->year)) {
 1168: #ifdef DEBUG
 1169: 		/* Would expect to have caught major problems already... */
 1170: 		if(debug) { printf("arc: badly formatted data.\n"); }
 1171: #endif
 1172: 		pp->lencode = 0;
 1173: 		refclock_report(peer, CEVNT_BADREPLY);
 1174: 		return;
 1175: 	}
 1176: 	flags = pp->a_lastcode[14];
 1177: 	status = pp->a_lastcode[15];
 1178: #ifdef DEBUG
 1179: 	if(debug) { printf("arc: status 0x%.2x flags 0x%.2x\n", flags, status); }
 1180: #endif
 1181: 	n = 9;
 1182: 
 1183: 	/*
 1184: 	  Validate received values at least enough to prevent internal
 1185: 	  array-bounds problems, etc.
 1186: 	*/
 1187: 	if((pp->hour < 0) || (pp->hour > 23) ||
 1188: 	   (pp->minute < 0) || (pp->minute > 59) ||
 1189: 	   (pp->second < 0) || (pp->second > 60) /*Allow for leap seconds.*/ ||
 1190: 	   (wday < 1) || (wday > 7) ||
 1191: 	   (pp->day < 1) || (pp->day > 31) ||
 1192: 	   (month < 1) || (month > 12) ||
 1193: 	   (pp->year < 0) || (pp->year > 99)) {
 1194: 		/* Data out of range. */
 1195: 		pp->lencode = 0;
 1196: 		refclock_report(peer, CEVNT_BADREPLY);
 1197: 		return;
 1198: 	}
 1199: 
 1200: 
 1201: 	if(peer->MODE == 0) { /* compatiblity to original version */
 1202: 		int bst = flags;
 1203: 		/* Check that BST/UTC bits are the complement of one another. */
 1204: 		if(!(bst & 2) == !(bst & 4)) {
 1205: 			pp->lencode = 0;
 1206: 			refclock_report(peer, CEVNT_BADREPLY);
 1207: 			return;
 1208: 		}
 1209: 	}
 1210: 	if(status & 0x8) { msyslog(LOG_NOTICE, "ARCRON: battery low"); }
 1211: 
 1212: 	/* Year-2000 alert! */
 1213: 	/* Attempt to wrap 2-digit date into sensible window. */
 1214: 	if(pp->year < YEAR_PIVOT) { pp->year += 100; }		/* Y2KFixes */
 1215: 	pp->year += 1900;	/* use full four-digit year */	/* Y2KFixes */
 1216: 	/*
 1217: 	  Attempt to do the right thing by screaming that the code will
 1218: 	  soon break when we get to the end of its useful life.  What a
 1219: 	  hero I am...  PLEASE FIX LEAP-YEAR AND WRAP CODE IN 209X!
 1220: 	*/
 1221: 	if(pp->year >= YEAR_PIVOT+2000-2 ) {  			/* Y2KFixes */
 1222: 		/*This should get attention B^> */
 1223: 		msyslog(LOG_NOTICE,
 1224: 			"ARCRON: fix me!  EITHER YOUR DATE IS BADLY WRONG or else I will break soon!");
 1225: 	}
 1226: #ifdef DEBUG
 1227: 	if(debug) {
 1228: 		printf("arc: n=%d %02d:%02d:%02d %02d/%02d/%04d %1d %1d\n",
 1229: 		       n,
 1230: 		       pp->hour, pp->minute, pp->second,
 1231: 		       pp->day, month, pp->year, flags, status);
 1232: 	}
 1233: #endif
 1234: 
 1235: 	/*
 1236: 	  The status value tested for is not strictly supported by the
 1237: 	  clock spec since the value of bit 2 (0x4) is claimed to be
 1238: 	  undefined for MSF, yet does seem to indicate if the last resync
 1239: 	  was successful or not.
 1240: 	*/
 1241: 	pp->leap = LEAP_NOWARNING;
 1242: 	status &= 0x7;
 1243: 	if(status == 0x3) {
 1244: 		if(status != up->status)
 1245: 		{ msyslog(LOG_NOTICE, "ARCRON: signal acquired"); }
 1246: 	} else {
 1247: 		if(status != up->status) {
 1248: 			msyslog(LOG_NOTICE, "ARCRON: signal lost");
 1249: 			pp->leap = LEAP_NOTINSYNC; /* MSF clock is free-running. */
 1250: 			up->status = status;
 1251: 			pp->lencode = 0;
 1252: 			refclock_report(peer, CEVNT_FAULT);
 1253: 			return;
 1254: 		}
 1255: 	}
 1256: 	up->status = status;
 1257: 
 1258: 	if (peer->MODE == 0) { /* compatiblity to original version */
 1259: 		int bst = flags;
 1260: 
 1261: 		pp->day += moff[month - 1];
 1262: 
 1263: 		if(isleap_4(pp->year) && month > 2) { pp->day++; }/* Y2KFixes */
 1264: 
 1265: 		/* Convert to UTC if required */
 1266: 		if(bst & 2) {
 1267: 			pp->hour--;
 1268: 			if (pp->hour < 0) {
 1269: 				pp->hour = 23;
 1270: 				pp->day--;
 1271: 				/* If we try to wrap round the year
 1272: 				 * (BST on 1st Jan), reject.*/
 1273: 				if(pp->day < 0) {
 1274: 					pp->lencode = 0;
 1275: 					refclock_report(peer, CEVNT_BADTIME);
 1276: 					return;
 1277: 				}
 1278: 			}
 1279: 		}
 1280: 	}
 1281: 
 1282: 	if(peer->MODE > 0) {
 1283: 		if(pp->sloppyclockflag & CLK_FLAG1) {
 1284: 			struct tm  local;
 1285: 			struct tm *gmtp;
 1286: 			time_t	   unixtime;
 1287: 
 1288: 			/*
 1289: 			 * Convert to GMT for sites that distribute localtime.
 1290: 			 * This means we have to do Y2K conversion on the
 1291: 			 * 2-digit year; otherwise, we get the time wrong.
 1292: 			 */
 1293: 
 1294: 			memset(&local, 0, sizeof(local));
 1295: 
 1296: 			local.tm_year  = pp->year-1900;
 1297: 			local.tm_mon   = month-1;
 1298: 			local.tm_mday  = pp->day;
 1299: 			local.tm_hour  = pp->hour;
 1300: 			local.tm_min   = pp->minute;
 1301: 			local.tm_sec   = pp->second;
 1302: 			switch (peer->MODE) {
 1303: 			    case 1:
 1304: 				local.tm_isdst = (flags & 2);
 1305: 				break;
 1306: 			    case 2:
 1307: 				local.tm_isdst = (flags & 2);
 1308: 				break;
 1309: 			    case 3:
 1310: 				switch (flags & 3) {
 1311: 				    case 0: /* It is unclear exactly when the 
 1312: 					       Arcron changes from DST->ST and 
 1313: 					       ST->DST. Testing has shown this
 1314: 					       to be irregular. For the time 
 1315: 					       being, let the OS decide. */
 1316: 					local.tm_isdst = 0;
 1317: #ifdef DEBUG
 1318: 					if (debug)
 1319: 					    printf ("arc: DST = 00 (0)\n"); 
 1320: #endif
 1321: 					break;
 1322: 				    case 1: /* dst->st time */
 1323: 					local.tm_isdst = -1;
 1324: #ifdef DEBUG
 1325: 					if (debug) 
 1326: 					    printf ("arc: DST = 01 (1)\n"); 
 1327: #endif
 1328: 					break;
 1329: 				    case 2: /* st->dst time */
 1330: 					local.tm_isdst = -1;
 1331: #ifdef DEBUG
 1332: 					if (debug) 
 1333: 					    printf ("arc: DST = 10 (2)\n"); 
 1334: #endif
 1335: 					break;
 1336: 				    case 3: /* dst time */
 1337: 				        local.tm_isdst = 1;
 1338: #ifdef DEBUG
 1339: 					if (debug) 
 1340: 					    printf ("arc: DST = 11 (3)\n"); 
 1341: #endif
 1342: 					break;
 1343: 				}
 1344: 				break;
 1345: 			    default:
 1346: 				msyslog(LOG_NOTICE, "ARCRON: Invalid mode %d",
 1347: 					peer->MODE);
 1348: 				return;
 1349: 				break;
 1350: 			}
 1351: 			unixtime = mktime (&local);
 1352: 			if ((gmtp = gmtime (&unixtime)) == NULL)
 1353: 			{
 1354: 				pp->lencode = 0;
 1355: 				refclock_report (peer, CEVNT_FAULT);
 1356: 				return;
 1357: 			}
 1358: 			pp->year = gmtp->tm_year+1900;
 1359: 			month = gmtp->tm_mon+1;
 1360: 			pp->day = ymd2yd(pp->year,month,gmtp->tm_mday);
 1361: 			/* pp->day = gmtp->tm_yday; */
 1362: 			pp->hour = gmtp->tm_hour;
 1363: 			pp->minute = gmtp->tm_min;
 1364: 			pp->second = gmtp->tm_sec;
 1365: #ifdef DEBUG
 1366: 			if (debug)
 1367: 			{
 1368: 				printf ("arc: time is %04d/%02d/%02d %02d:%02d:%02d UTC\n",
 1369: 					pp->year,month,gmtp->tm_mday,pp->hour,pp->minute,
 1370: 					pp->second);
 1371: 			}
 1372: #endif
 1373: 		} else 
 1374: 		{
 1375: 			/*
 1376: 			* For more rational sites distributing UTC
 1377: 			*/
 1378: 			pp->day    = ymd2yd(pp->year,month,pp->day);
 1379: 		}
 1380: 	}
 1381: 
 1382: 	if (peer->MODE == 0) { /* compatiblity to original version */
 1383: 				/* If clock signal quality is 
 1384: 				 * unknown, revert to default PRECISION...*/
 1385: 		if(up->quality == QUALITY_UNKNOWN) { 
 1386: 			peer->precision = PRECISION; 
 1387: 		} else { /* ...else improve precision if flag3 is set... */
 1388: 			peer->precision = ((pp->sloppyclockflag & CLK_FLAG3) ?
 1389: 					   HIGHPRECISION : PRECISION);
 1390: 		}
 1391: 	} else {
 1392: 		if ((status == 0x3) && (pp->sloppyclockflag & CLK_FLAG2)) {
 1393: 			peer->precision = ((pp->sloppyclockflag & CLK_FLAG3) ?
 1394: 					   HIGHPRECISION : PRECISION);
 1395: 		} else if (up->quality == QUALITY_UNKNOWN) {
 1396: 			peer->precision = PRECISION;
 1397: 		} else {
 1398: 			peer->precision = ((pp->sloppyclockflag & CLK_FLAG3) ?
 1399: 					   HIGHPRECISION : PRECISION);
 1400: 		}
 1401: 	}
 1402: 
 1403: 	/* Notice and log any change (eg from initial defaults) for flags. */
 1404: 	if(up->saved_flags != pp->sloppyclockflag) {
 1405: #ifdef DEBUG
 1406: 		msyslog(LOG_NOTICE, "ARCRON: flags enabled: %s%s%s%s",
 1407: 			((pp->sloppyclockflag & CLK_FLAG1) ? "1" : "."),
 1408: 			((pp->sloppyclockflag & CLK_FLAG2) ? "2" : "."),
 1409: 			((pp->sloppyclockflag & CLK_FLAG3) ? "3" : "."),
 1410: 			((pp->sloppyclockflag & CLK_FLAG4) ? "4" : "."));
 1411: 		/* Note effects of flags changing... */
 1412: 		if(debug) {
 1413: 			printf("arc: PRECISION = %d.\n", peer->precision);
 1414: 		}
 1415: #endif
 1416: 		up->saved_flags = pp->sloppyclockflag;
 1417: 	}
 1418: 
 1419: 	/* Note time of last believable timestamp. */
 1420: 	pp->lastrec = up->lastrec;
 1421: 
 1422: #ifdef ARCRON_LEAPSECOND_KEEN
 1423: 	/* Find out if a leap-second might just have happened...
 1424: 	   (ie is this the first hour of the first day of Jan or Jul?)
 1425: 	*/
 1426: 	if((pp->hour == 0) &&
 1427: 	   (pp->day == 1) &&
 1428: 	   ((month == 1) || (month == 7))) {
 1429: 		if(possible_leap >= 0) {
 1430: 			/* A leap may have happened, and no resync has started yet...*/
 1431: 			possible_leap = 1;
 1432: 		}
 1433: 	} else {
 1434: 		/* Definitely not leap-second territory... */
 1435: 		possible_leap = 0;
 1436: 	}
 1437: #endif
 1438: 
 1439: 	if (!refclock_process(pp)) {
 1440: 		pp->lencode = 0;
 1441: 		refclock_report(peer, CEVNT_BADTIME);
 1442: 		return;
 1443: 	}
 1444: 	record_clock_stats(&peer->srcadr, pp->a_lastcode);
 1445: 	refclock_receive(peer);
 1446: }
 1447: 
 1448: 
 1449: /* request_time() sends a time request to the clock with given peer. */
 1450: /* This automatically reports a fault if necessary. */
 1451: /* No data should be sent after this until arc_poll() returns. */
 1452: static  void    request_time    (int, struct peer *);
 1453: static void
 1454: request_time(
 1455: 	int unit,
 1456: 	struct peer *peer
 1457: 	)
 1458: {
 1459: 	struct refclockproc *pp = peer->procptr;
 1460: 	register struct arcunit *up = pp->unitptr;
 1461: #ifdef DEBUG
 1462: 	if(debug) { printf("arc: unit %d: requesting time.\n", unit); }
 1463: #endif
 1464: 	if (!send_slow(up, pp->io.fd, "o\r")) {
 1465: #ifdef DEBUG
 1466: 		if (debug) {
 1467: 			printf("arc: unit %d: problem sending", unit);
 1468: 		}
 1469: #endif
 1470: 		pp->lencode = 0;
 1471: 		refclock_report(peer, CEVNT_FAULT);
 1472: 		return;
 1473: 	}
 1474: 	pp->polls++;
 1475: }
 1476: 
 1477: /*
 1478:  * arc_poll - called by the transmit procedure
 1479:  */
 1480: static void
 1481: arc_poll(
 1482: 	int unit,
 1483: 	struct peer *peer
 1484: 	)
 1485: {
 1486: 	register struct arcunit *up;
 1487: 	struct refclockproc *pp;
 1488: 	int resync_needed;              /* Should we start a resync? */
 1489: 
 1490: 	pp = peer->procptr;
 1491: 	up = pp->unitptr;
 1492: #if 0
 1493: 	pp->lencode = 0;
 1494: 	memset(pp->a_lastcode, 0, sizeof(pp->a_lastcode));
 1495: #endif
 1496: 
 1497: #if 0
 1498: 	/* Flush input. */
 1499: 	tcflush(pp->io.fd, TCIFLUSH);
 1500: #endif
 1501: 
 1502: 	/* Resync if our next scheduled resync time is here or has passed. */
 1503: 	resync_needed = ( !(pp->sloppyclockflag & CLK_FLAG2) &&
 1504: 			  (up->next_resync <= current_time) );
 1505: 
 1506: #ifdef ARCRON_LEAPSECOND_KEEN
 1507: 	/*
 1508: 	  Try to catch a potential leap-second insertion or deletion quickly.
 1509: 
 1510: 	  In addition to the normal NTP fun of clocks that don't report
 1511: 	  leap-seconds spooking their hosts, this clock does not even
 1512: 	  sample the radio sugnal the whole time, so may miss a
 1513: 	  leap-second insertion or deletion for up to a whole sample
 1514: 	  time.
 1515: 
 1516: 	  To try to minimise this effect, if in the first few minutes of
 1517: 	  the day immediately following a leap-second-insertion point
 1518: 	  (ie in the first hour of the first day of the first and sixth
 1519: 	  months), and if the last resync was in the previous day, and a
 1520: 	  resync is not already in progress, resync the clock
 1521: 	  immediately.
 1522: 
 1523: 	*/
 1524: 	if((possible_leap > 0) &&       /* Must be 00:XX 01/0{1,7}/XXXX. */
 1525: 	   (!up->resyncing)) {          /* No resync in progress yet. */
 1526: 		resync_needed = 1;
 1527: 		possible_leap = -1;          /* Prevent multiple resyncs. */
 1528: 		msyslog(LOG_NOTICE,"ARCRON: unit %d: checking for leap second",unit);
 1529: 	}
 1530: #endif
 1531: 
 1532: 	/* Do a resync if required... */
 1533: 	if(resync_needed) {
 1534: 		/* First, reset quality value to `unknown' so we can detect */
 1535: 		/* when a quality message has been responded to by this     */
 1536: 		/* being set to some other value.                           */
 1537: 		up->quality = QUALITY_UNKNOWN;
 1538: 
 1539: 		/* Note that we are resyncing... */
 1540: 		up->resyncing = 1;
 1541: 
 1542: 		/* Now actually send the resync command and an immediate poll. */
 1543: #ifdef DEBUG
 1544: 		if(debug) { printf("arc: sending resync command (h\\r).\n"); }
 1545: #endif
 1546: 		msyslog(LOG_NOTICE, "ARCRON: unit %d: sending resync command", unit);
 1547: 		send_slow(up, pp->io.fd, "h\r");
 1548: 
 1549: 		/* Schedule our next resync... */
 1550: 		up->next_resync = current_time + DEFAULT_RESYNC_TIME;
 1551: 
 1552: 		/* Drop through to request time if appropriate. */
 1553: 	}
 1554: 
 1555: 	/* If clock quality is too poor to trust, indicate a fault. */
 1556: 	/* If quality is QUALITY_UNKNOWN and ARCRON_KEEN is defined,*/
 1557: 	/* we'll cross our fingers and just hope that the thing     */
 1558: 	/* synced so quickly we did not catch it---we'll            */
 1559: 	/* double-check the clock is OK elsewhere.                  */
 1560: 	if(
 1561: #ifdef ARCRON_KEEN
 1562: 		(up->quality != QUALITY_UNKNOWN) &&
 1563: #else
 1564: 		(up->quality == QUALITY_UNKNOWN) ||
 1565: #endif
 1566: 		(up->quality < MIN_CLOCK_QUALITY_OK)) {
 1567: #ifdef DEBUG
 1568: 		if(debug) {
 1569: 			printf("arc: clock quality %d too poor.\n", up->quality);
 1570: 		}
 1571: #endif
 1572: 		pp->lencode = 0;
 1573: 		refclock_report(peer, CEVNT_FAULT);
 1574: 		return;
 1575: 	}
 1576: 	/* This is the normal case: request a timestamp. */
 1577: 	request_time(unit, peer);
 1578: }
 1579: 
 1580: #else
 1581: int refclock_arc_bs;
 1582: #endif

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>