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