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
11static 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/*
32Code by Derek Mulcahy, <derek@toybox.demon.co.uk>, 1997.
33Modifications by Damon Hart-Davis, <d@hd.org>, 1997.
34Modifications by Paul Alfille, <palfille@partners.org>, 2003.
35Modifications by Christopher Price, <cprice@cs-home.com>, 2003.
36Modifications by Nigel Roles <nigel@9fs.org>, 2003.
37
38
39THIS CODE IS SUPPLIED AS IS, WITH NO WARRANTY OF ANY KIND.  USE AT
40YOUR OWN RISK.
41
42Orginally developed and used with ntp3-5.85 by Derek Mulcahy.
43
44Built against ntp3-5.90 on Solaris 2.5 using gcc 2.7.2.
45
46This code may be freely copied and used and incorporated in other
47systems providing the disclaimer and notice of authorship are
48reproduced.
49
50-------------------------------------------------------------------------------
51
52Nigel's notes:
53
541) Called tcgetattr() before modifying, so that fields correctly initialised
55   for all operating systems
56
572) 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
62Christopher's notes:
63
64MAJOR 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
89Author's original note:
90
91I enclose my ntp driver for the Galleon Systems Arc MSF receiver.
92
93It works (after a fashion) on both Solaris-1 and Solaris-2.
94
95I am currently using ntp3-5.85.  I have been running the code for
96about 7 months without any problems.  Even coped with the change to BST!
97
98I had to do some funky things to read from the clock because it uses the
99power from the receive lines to drive the transmit lines.  This makes the
100code look a bit stupid but it works.  I also had to put in some delays to
101allow for the turnaround time from receive to transmit.  These delays
102are between characters when requesting a time stamp so that shouldn't affect
103the results too drastically.
104
105...
106
107The bottom line is that it works but could easily be improved.  You are
108free to do what you will with the code.  I haven't been able to determine
109how good the clock is.  I think that this requires a known good clock
110to compare it against.
111
112-------------------------------------------------------------------------------
113
114Damon's notes for adjustments:
115
116MAJOR 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
131GENERAL
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
252TO-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:
295You 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:
344Also note g<cr> command which confirms that a resync is in progress, and
345if so what signal quality (0--5) is available.
346Also 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 */
487struct 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     */
526static int possible_leap = 0;       /* No resync required by default. */
527#endif
528
529#if 0
530static void dummy_event_handler (struct peer *);
531static 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 */
542static	int	arc_start	(int, struct peer *);
543static	void	arc_shutdown	(int, struct peer *);
544static	void	arc_receive	(struct recvbuf *);
545static	void	arc_poll	(int, struct peer *);
546
547/*
548 * Transfer vector
549 */
550struct  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. */
567static void
568dummy_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/*
578Normal event handler.
579
580Take first character off queue and send to clock if not a null.
581
582Shift characters down and put a null on the end.
583
584We assume that there is no parallelism so no race condition, but even
585if there is nothing bad will happen except that we might send some bad
586data to the clock once in a while.
587*/
588static void
589arc_event_handler(
590	struct peer *peer
591	)
592{
593	struct refclockproc *pp = peer->procptr;
594	register struct arcunit *up = (struct arcunit *)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 */
622static int
623arc_start(
624	int unit,
625	struct peer *peer
626	)
627{
628	register struct arcunit *up;
629	struct refclockproc *pp;
630	int fd;
631	char device[20];
632#ifdef HAVE_TERMIOS
633	struct termios arg;
634#endif
635
636	msyslog(LOG_NOTICE, "ARCRON: %s: opening unit %d", arc_version, unit);
637#ifdef DEBUG
638	if(debug) {
639		printf("arc: %s: attempt to open unit %d.\n", arc_version, unit);
640	}
641#endif
642
643	/* Prevent a ridiculous device number causing overflow of device[]. */
644	if((unit < 0) || (unit > 255)) { return(0); }
645
646	/*
647	 * Open serial port. Use CLK line discipline, if available.
648	 */
649	(void)sprintf(device, DEVICE, unit);
650	if (!(fd = refclock_open(device, SPEED, LDISC_CLK)))
651		return(0);
652#ifdef DEBUG
653	if(debug) { printf("arc: unit %d using open().\n", unit); }
654#endif
655	fd = tty_open(device, OPEN_FLAGS, 0777);
656	if(fd < 0) {
657#ifdef DEBUG
658		if(debug) { printf("arc: failed [tty_open()] to open %s.\n", device); }
659#endif
660		return(0);
661	}
662
663#ifndef SYS_WINNT
664	fcntl(fd, F_SETFL, 0); /* clear the descriptor flags */
665#endif
666#ifdef DEBUG
667	if(debug)
668	{ printf("arc: opened RS232 port with file descriptor %d.\n", fd); }
669#endif
670
671#ifdef HAVE_TERMIOS
672
673	tcgetattr(fd, &arg);
674
675	arg.c_iflag = IGNBRK | ISTRIP;
676	arg.c_oflag = 0;
677	arg.c_cflag = B300 | CS8 | CREAD | CLOCAL | CSTOPB;
678	arg.c_lflag = 0;
679	arg.c_cc[VMIN] = 1;
680	arg.c_cc[VTIME] = 0;
681
682	tcsetattr(fd, TCSANOW, &arg);
683
684#else
685
686	msyslog(LOG_ERR, "ARCRON: termios not supported in this driver");
687	(void)close(fd);
688
689	return 0;
690
691#endif
692
693	up = (struct arcunit *) emalloc(sizeof(struct arcunit));
694	if(!up) { (void) close(fd); return(0); }
695	/* Set structure to all zeros... */
696	memset((char *)up, 0, sizeof(struct arcunit));
697	pp = peer->procptr;
698	pp->io.clock_recv = arc_receive;
699	pp->io.srcclock = (caddr_t)peer;
700	pp->io.datalen = 0;
701	pp->io.fd = fd;
702	if(!io_addclock(&pp->io)) { (void) close(fd); free(up); return(0); }
703	pp->unitptr = (caddr_t)up;
704
705	/*
706	 * Initialize miscellaneous variables
707	 */
708	peer->precision = PRECISION;
709	peer->stratum = 2;              /* Default to stratum 2 not 0. */
710	pp->clockdesc = DESCRIPTION;
711	if (peer->MODE > 3) {
712		msyslog(LOG_NOTICE, "ARCRON: Invalid mode %d", peer->MODE);
713		return 0;
714	}
715#ifdef DEBUG
716	if(debug) { printf("arc: mode = %d.\n", peer->MODE); }
717#endif
718	switch (peer->MODE) {
719	    case 1:
720		memcpy((char *)&pp->refid, REFID_MSF, 4);
721		break;
722	    case 2:
723		memcpy((char *)&pp->refid, REFID_DCF77, 4);
724		break;
725	    case 3:
726		memcpy((char *)&pp->refid, REFID_WWVB, 4);
727		break;
728	    default:
729		memcpy((char *)&pp->refid, REFID, 4);
730		break;
731	}
732	/* Spread out resyncs so that they should remain separated. */
733	up->next_resync = current_time + INITIAL_RESYNC_DELAY + (67*unit)%1009;
734
735#if 0 /* Not needed because of zeroing of arcunit structure... */
736	up->resyncing = 0;              /* Not resyncing yet. */
737	up->saved_flags = 0;            /* Default is all flags off. */
738	/* Clear send buffer out... */
739	{
740		int i;
741		for(i = CMDQUEUELEN; i >= 0; --i) { up->cmdqueue[i] = '\0'; }
742	}
743#endif
744
745#ifdef ARCRON_KEEN
746	up->quality = QUALITY_UNKNOWN;  /* Trust the clock immediately. */
747#else
748	up->quality = MIN_CLOCK_QUALITY;/* Don't trust the clock yet. */
749#endif
750
751	peer->action = arc_event_handler;
752
753	ENQUEUE(up);
754
755	return(1);
756}
757
758
759/*
760 * arc_shutdown - shut down the clock
761 */
762static void
763arc_shutdown(
764	int unit,
765	struct peer *peer
766	)
767{
768	register struct arcunit *up;
769	struct refclockproc *pp;
770
771	peer->action = dummy_event_handler;
772
773	pp = peer->procptr;
774	up = (struct arcunit *)pp->unitptr;
775	io_closeclock(&pp->io);
776	free(up);
777}
778
779/*
780Compute space left in output buffer.
781*/
782static int
783space_left(
784	register struct arcunit *up
785	)
786{
787	int spaceleft;
788
789	/* Compute space left in buffer after any pending output. */
790	for(spaceleft = 0; spaceleft < CMDQUEUELEN; ++spaceleft)
791	{ if(up->cmdqueue[CMDQUEUELEN - 1 - spaceleft] != '\0') { break; } }
792	return(spaceleft);
793}
794
795/*
796Send command by copying into command buffer as far forward as possible,
797after any pending output.
798
799Indicate an error by returning 0 if there is not space for the command.
800*/
801static int
802send_slow(
803	register struct arcunit *up,
804	int fd,
805	const char *s
806	)
807{
808	int sl = strlen(s);
809	int spaceleft = space_left(up);
810
811#ifdef DEBUG
812	if(debug > 1) { printf("arc: spaceleft = %d.\n", spaceleft); }
813#endif
814	if(spaceleft < sl) { /* Should not normally happen... */
815#ifdef DEBUG
816		msyslog(LOG_NOTICE, "ARCRON: send-buffer overrun (%d/%d)",
817			sl, spaceleft);
818#endif
819		return(0);			/* FAILED! */
820	}
821
822	/* Copy in the command to be sent. */
823	while(*s && spaceleft > 0) { up->cmdqueue[CMDQUEUELEN - spaceleft--] = *s++; }
824
825	return(1);
826}
827
828
829static int
830get2(char *p, int *val)
831{
832  if (!isdigit((int)p[0]) || !isdigit((int)p[1])) return 0;
833  *val = (p[0] - '0') * 10 + p[1] - '0';
834  return 1;
835}
836
837static int
838get1(char *p, int *val)
839{
840  if (!isdigit((int)p[0])) return 0;
841  *val = p[0] - '0';
842  return 1;
843}
844
845/* Macro indicating action we will take for different quality values. */
846#define quality_action(q) \
847(((q) == QUALITY_UNKNOWN) ?         "UNKNOWN, will use clock anyway" : \
848 (((q) < MIN_CLOCK_QUALITY_OK) ? "TOO POOR, will not use clock" : \
849  "OK, will use clock"))
850
851/*
852 * arc_receive - receive data from the serial interface
853 */
854static void
855arc_receive(
856	struct recvbuf *rbufp
857	)
858{
859	register struct arcunit *up;
860	struct refclockproc *pp;
861	struct peer *peer;
862	char c;
863	int i, n, wday, month, flags, status;
864	int arc_last_offset;
865	static int quality_average = 0;
866	static int quality_sum = 0;
867	static int quality_polls = 0;
868
869	/*
870	 * Initialize pointers and read the timecode and timestamp
871	 */
872	peer = (struct peer *)rbufp->recv_srcclock;
873	pp = peer->procptr;
874	up = (struct arcunit *)pp->unitptr;
875
876
877	/*
878	  If the command buffer is empty, and we are resyncing, insert a
879	  g\r quality request into it to poll for signal quality again.
880	*/
881	if((up->resyncing) && (space_left(up) == CMDQUEUELEN)) {
882#ifdef DEBUG
883		if(debug > 1) { printf("arc: inserting signal-quality poll.\n"); }
884#endif
885		send_slow(up, pp->io.fd, "g\r");
886	}
887
888	/*
889	  The `arc_last_offset' is the offset in lastcode[] of the last byte
890	  received, and which we assume actually received the input
891	  timestamp.
892
893	  (When we get round to using tty_clk and it is available, we
894	  assume that we will receive the whole timecode with the
895	  trailing \r, and that that \r will be timestamped.  But this
896	  assumption also works if receive the characters one-by-one.)
897	*/
898	arc_last_offset = pp->lencode+rbufp->recv_length - 1;
899
900	/*
901	  We catch a timestamp iff:
902
903	  * The command code is `o' for a timestamp.
904
905	  * If ARCRON_MULTIPLE_SAMPLES is undefined then we must have
906	  exactly char in the buffer (the command code) so that we
907	  only sample the first character of the timecode as our
908	  `on-time' character.
909
910	  * The first character in the buffer is not the echoed `\r'
911	  from the `o` command (so if we are to timestamp an `\r' it
912	  must not be first in the receive buffer with lencode==1.
913	  (Even if we had other characters following it, we probably
914	  would have a premature timestamp on the '\r'.)
915
916	  * We have received at least one character (I cannot imagine
917	  how it could be otherwise, but anyway...).
918	*/
919	c = rbufp->recv_buffer[0];
920	if((pp->a_lastcode[0] == 'o') &&
921#ifndef ARCRON_MULTIPLE_SAMPLES
922	   (pp->lencode == 1) &&
923#endif
924	   ((pp->lencode != 1) || (c != '\r')) &&
925	   (arc_last_offset >= 1)) {
926		/* Note that the timestamp should be corrected if >1 char rcvd. */
927		l_fp timestamp;
928		timestamp = rbufp->recv_time;
929#ifdef DEBUG
930		if(debug) { /* Show \r as `R', other non-printing char as `?'. */
931			printf("arc: stamp -->%c<-- (%d chars rcvd)\n",
932			       ((c == '\r') ? 'R' : (isgraph((int)c) ? c : '?')),
933			       rbufp->recv_length);
934		}
935#endif
936
937		/*
938		  Now correct timestamp by offset of last byte received---we
939		  subtract from the receive time the delay implied by the
940		  extra characters received.
941
942		  Reject the input if the resulting code is too long, but
943		  allow for the trailing \r, normally not used but a good
944		  handle for tty_clk or somesuch kernel timestamper.
945		*/
946		if(arc_last_offset > LENARC) {
947#ifdef DEBUG
948			if(debug) {
949				printf("arc: input code too long (%d cf %d); rejected.\n",
950				       arc_last_offset, LENARC);
951			}
952#endif
953			pp->lencode = 0;
954			refclock_report(peer, CEVNT_BADREPLY);
955			return;
956		}
957
958		L_SUBUF(&timestamp, charoffsets[arc_last_offset]);
959#ifdef DEBUG
960		if(debug > 1) {
961			printf(
962				"arc: %s%d char(s) rcvd, the last for lastcode[%d]; -%sms offset applied.\n",
963				((rbufp->recv_length > 1) ? "*** " : ""),
964				rbufp->recv_length,
965				arc_last_offset,
966				mfptoms((unsigned long)0,
967					charoffsets[arc_last_offset],
968					1));
969		}
970#endif
971
972#ifdef ARCRON_MULTIPLE_SAMPLES
973		/*
974		  If taking multiple samples, capture the current adjusted
975		  sample iff:
976
977		  * No timestamp has yet been captured (it is zero), OR
978
979		  * This adjusted timestamp is earlier than the one already
980		  captured, on the grounds that this one suffered less
981		  delay in being delivered to us and is more accurate.
982
983		*/
984		if(L_ISZERO(&(up->lastrec)) ||
985		   L_ISGEQ(&(up->lastrec), &timestamp))
986#endif
987		{
988#ifdef DEBUG
989			if(debug > 1) {
990				printf("arc: system timestamp captured.\n");
991#ifdef ARCRON_MULTIPLE_SAMPLES
992				if(!L_ISZERO(&(up->lastrec))) {
993					l_fp diff;
994					diff = up->lastrec;
995					L_SUB(&diff, &timestamp);
996					printf("arc: adjusted timestamp by -%sms.\n",
997					       mfptoms(diff.l_i, diff.l_f, 3));
998				}
999#endif
1000			}
1001#endif
1002			up->lastrec = timestamp;
1003		}
1004
1005	}
1006
1007	/* Just in case we still have lots of rubbish in the buffer... */
1008	/* ...and to avoid the same timestamp being reused by mistake, */
1009	/* eg on receipt of the \r coming in on its own after the      */
1010	/* timecode.						       */
1011	if(pp->lencode >= LENARC) {
1012#ifdef DEBUG
1013		if(debug && (rbufp->recv_buffer[0] != '\r'))
1014		{ printf("arc: rubbish in pp->a_lastcode[].\n"); }
1015#endif
1016		pp->lencode = 0;
1017		return;
1018	}
1019
1020	/* Append input to code buffer, avoiding overflow. */
1021	for(i = 0; i < rbufp->recv_length; i++) {
1022		if(pp->lencode >= LENARC) { break; } /* Avoid overflow... */
1023		c = rbufp->recv_buffer[i];
1024
1025		/* Drop trailing '\r's and drop `h' command echo totally. */
1026		if(c != '\r' && c != 'h') { pp->a_lastcode[pp->lencode++] = c; }
1027
1028		/*
1029		  If we've just put an `o' in the lastcode[0], clear the
1030		  timestamp in anticipation of a timecode arriving soon.
1031
1032		  We would expect to get to process this before any of the
1033		  timecode arrives.
1034		*/
1035		if((c == 'o') && (pp->lencode == 1)) {
1036			L_CLR(&(up->lastrec));
1037#ifdef DEBUG
1038			if(debug > 1) { printf("arc: clearing timestamp.\n"); }
1039#endif
1040		}
1041	}
1042	if (pp->lencode == 0) return;
1043
1044	/* Handle a quality message. */
1045	if(pp->a_lastcode[0] == 'g') {
1046		int r, q;
1047
1048		if(pp->lencode < 3) { return; } /* Need more data... */
1049		r = (pp->a_lastcode[1] & 0x7f); /* Strip parity. */
1050		q = (pp->a_lastcode[2] & 0x7f); /* Strip parity. */
1051		if(((q & 0x70) != 0x30) || ((q & 0xf) > MAX_CLOCK_QUALITY) ||
1052		   ((r & 0x70) != 0x30)) {
1053			/* Badly formatted response. */
1054#ifdef DEBUG
1055			if(debug) { printf("arc: bad `g' response %2x %2x.\n", r, q); }
1056#endif
1057			return;
1058		}
1059		if(r == '3') { /* Only use quality value whilst sync in progress. */
1060			if (up->quality_stamp < current_time) {
1061				struct calendar cal;
1062				l_fp new_stamp;
1063
1064				get_systime (&new_stamp);
1065				caljulian (new_stamp.l_ui, &cal);
1066				up->quality_stamp =
1067					current_time + 60 - cal.second + 5;
1068				quality_sum = 0;
1069				quality_polls = 0;
1070			}
1071			quality_sum += (q & 0xf);
1072			quality_polls++;
1073			quality_average = (quality_sum / quality_polls);
1074#ifdef DEBUG
1075			if(debug) { printf("arc: signal quality %d (%d).\n", quality_average, (q & 0xf)); }
1076#endif
1077		} else if( /* (r == '2') && */ up->resyncing) {
1078			up->quality = quality_average;
1079#ifdef DEBUG
1080			if(debug)
1081			{
1082				printf("arc: sync finished, signal quality %d: %s\n",
1083				       up->quality,
1084				       quality_action(up->quality));
1085			}
1086#endif
1087			msyslog(LOG_NOTICE,
1088				"ARCRON: sync finished, signal quality %d: %s",
1089				up->quality,
1090				quality_action(up->quality));
1091			up->resyncing = 0; /* Resync is over. */
1092			quality_average = 0;
1093			quality_sum = 0;
1094			quality_polls = 0;
1095
1096#ifdef ARCRON_KEEN
1097			/* Clock quality dubious; resync earlier than usual. */
1098			if((up->quality == QUALITY_UNKNOWN) ||
1099			   (up->quality < MIN_CLOCK_QUALITY_OK))
1100			{ up->next_resync = current_time + RETRY_RESYNC_TIME; }
1101#endif
1102		}
1103		pp->lencode = 0;
1104		return;
1105	}
1106
1107	/* Stop now if this is not a timecode message. */
1108	if(pp->a_lastcode[0] != 'o') {
1109		pp->lencode = 0;
1110		refclock_report(peer, CEVNT_BADREPLY);
1111		return;
1112	}
1113
1114	/* If we don't have enough data, wait for more... */
1115	if(pp->lencode < LENARC) { return; }
1116
1117
1118	/* WE HAVE NOW COLLECTED ONE TIMESTAMP (phew)... */
1119#ifdef DEBUG
1120	if(debug > 1) { printf("arc: NOW HAVE TIMESTAMP...\n"); }
1121#endif
1122
1123	/* But check that we actually captured a system timestamp on it. */
1124	if(L_ISZERO(&(up->lastrec))) {
1125#ifdef DEBUG
1126		if(debug) { printf("arc: FAILED TO GET SYSTEM TIMESTAMP\n"); }
1127#endif
1128		pp->lencode = 0;
1129		refclock_report(peer, CEVNT_BADREPLY);
1130		return;
1131	}
1132	/*
1133	  Append a mark of the clock's received signal quality for the
1134	  benefit of Derek Mulcahy's Tcl/Tk utility (we map the `unknown'
1135	  quality value to `6' for his s/w) and terminate the string for
1136	  sure.  This should not go off the buffer end.
1137	*/
1138	pp->a_lastcode[pp->lencode] = ((up->quality == QUALITY_UNKNOWN) ?
1139				       '6' : ('0' + up->quality));
1140	pp->a_lastcode[pp->lencode + 1] = '\0'; /* Terminate for printf(). */
1141
1142#ifdef PRE_NTP420
1143	/* We don't use the micro-/milli- second part... */
1144	pp->usec = 0;
1145	pp->msec = 0;
1146#else
1147	/* We don't use the nano-second part... */
1148	pp->nsec = 0;
1149#endif
1150	/* Validate format and numbers. */
1151	if (pp->a_lastcode[0] != 'o'
1152		|| !get2(pp->a_lastcode + 1, &pp->hour)
1153		|| !get2(pp->a_lastcode + 3, &pp->minute)
1154		|| !get2(pp->a_lastcode + 5, &pp->second)
1155		|| !get1(pp->a_lastcode + 7, &wday)
1156		|| !get2(pp->a_lastcode + 8, &pp->day)
1157		|| !get2(pp->a_lastcode + 10, &month)
1158		|| !get2(pp->a_lastcode + 12, &pp->year)) {
1159#ifdef DEBUG
1160		/* Would expect to have caught major problems already... */
1161		if(debug) { printf("arc: badly formatted data.\n"); }
1162#endif
1163		pp->lencode = 0;
1164		refclock_report(peer, CEVNT_BADREPLY);
1165		return;
1166	}
1167	flags = pp->a_lastcode[14];
1168	status = pp->a_lastcode[15];
1169#ifdef DEBUG
1170	if(debug) { printf("arc: status 0x%.2x flags 0x%.2x\n", flags, status); }
1171#endif
1172	n = 9;
1173
1174	/*
1175	  Validate received values at least enough to prevent internal
1176	  array-bounds problems, etc.
1177	*/
1178	if((pp->hour < 0) || (pp->hour > 23) ||
1179	   (pp->minute < 0) || (pp->minute > 59) ||
1180	   (pp->second < 0) || (pp->second > 60) /*Allow for leap seconds.*/ ||
1181	   (wday < 1) || (wday > 7) ||
1182	   (pp->day < 1) || (pp->day > 31) ||
1183	   (month < 1) || (month > 12) ||
1184	   (pp->year < 0) || (pp->year > 99)) {
1185		/* Data out of range. */
1186		pp->lencode = 0;
1187		refclock_report(peer, CEVNT_BADREPLY);
1188		return;
1189	}
1190
1191
1192	if(peer->MODE == 0) { /* compatiblity to original version */
1193		int bst = flags;
1194		/* Check that BST/UTC bits are the complement of one another. */
1195		if(!(bst & 2) == !(bst & 4)) {
1196			pp->lencode = 0;
1197			refclock_report(peer, CEVNT_BADREPLY);
1198			return;
1199		}
1200	}
1201	if(status & 0x8) { msyslog(LOG_NOTICE, "ARCRON: battery low"); }
1202
1203	/* Year-2000 alert! */
1204	/* Attempt to wrap 2-digit date into sensible window. */
1205	if(pp->year < YEAR_PIVOT) { pp->year += 100; }		/* Y2KFixes */
1206	pp->year += 1900;	/* use full four-digit year */	/* Y2KFixes */
1207	/*
1208	  Attempt to do the right thing by screaming that the code will
1209	  soon break when we get to the end of its useful life.  What a
1210	  hero I am...  PLEASE FIX LEAP-YEAR AND WRAP CODE IN 209X!
1211	*/
1212	if(pp->year >= YEAR_PIVOT+2000-2 ) {  			/* Y2KFixes */
1213		/*This should get attention B^> */
1214		msyslog(LOG_NOTICE,
1215			"ARCRON: fix me!  EITHER YOUR DATE IS BADLY WRONG or else I will break soon!");
1216	}
1217#ifdef DEBUG
1218	if(debug) {
1219		printf("arc: n=%d %02d:%02d:%02d %02d/%02d/%04d %1d %1d\n",
1220		       n,
1221		       pp->hour, pp->minute, pp->second,
1222		       pp->day, month, pp->year, flags, status);
1223	}
1224#endif
1225
1226	/*
1227	  The status value tested for is not strictly supported by the
1228	  clock spec since the value of bit 2 (0x4) is claimed to be
1229	  undefined for MSF, yet does seem to indicate if the last resync
1230	  was successful or not.
1231	*/
1232	pp->leap = LEAP_NOWARNING;
1233	status &= 0x7;
1234	if(status == 0x3) {
1235		if(status != up->status)
1236		{ msyslog(LOG_NOTICE, "ARCRON: signal acquired"); }
1237	} else {
1238		if(status != up->status) {
1239			msyslog(LOG_NOTICE, "ARCRON: signal lost");
1240			pp->leap = LEAP_NOTINSYNC; /* MSF clock is free-running. */
1241			up->status = status;
1242			pp->lencode = 0;
1243			refclock_report(peer, CEVNT_FAULT);
1244			return;
1245		}
1246	}
1247	up->status = status;
1248
1249	if (peer->MODE == 0) { /* compatiblity to original version */
1250		int bst = flags;
1251
1252		pp->day += moff[month - 1];
1253
1254		if(isleap_4(pp->year) && month > 2) { pp->day++; }/* Y2KFixes */
1255
1256		/* Convert to UTC if required */
1257		if(bst & 2) {
1258			pp->hour--;
1259			if (pp->hour < 0) {
1260				pp->hour = 23;
1261				pp->day--;
1262				/* If we try to wrap round the year
1263				 * (BST on 1st Jan), reject.*/
1264				if(pp->day < 0) {
1265					pp->lencode = 0;
1266					refclock_report(peer, CEVNT_BADTIME);
1267					return;
1268				}
1269			}
1270		}
1271	}
1272
1273	if(peer->MODE > 0) {
1274		if(pp->sloppyclockflag & CLK_FLAG1) {
1275			struct tm  local;
1276			struct tm *gmtp;
1277			time_t	   unixtime;
1278
1279			/*
1280			 * Convert to GMT for sites that distribute localtime.
1281			 * This means we have to do Y2K conversion on the
1282			 * 2-digit year; otherwise, we get the time wrong.
1283			 */
1284
1285			memset(&local, 0, sizeof(local));
1286
1287			local.tm_year  = pp->year-1900;
1288			local.tm_mon   = month-1;
1289			local.tm_mday  = pp->day;
1290			local.tm_hour  = pp->hour;
1291			local.tm_min   = pp->minute;
1292			local.tm_sec   = pp->second;
1293			switch (peer->MODE) {
1294			    case 1:
1295				local.tm_isdst = (flags & 2);
1296				break;
1297			    case 2:
1298				local.tm_isdst = (flags & 2);
1299				break;
1300			    case 3:
1301				switch (flags & 3) {
1302				    case 0: /* It is unclear exactly when the
1303					       Arcron changes from DST->ST and
1304					       ST->DST. Testing has shown this
1305					       to be irregular. For the time
1306					       being, let the OS decide. */
1307					local.tm_isdst = 0;
1308#ifdef DEBUG
1309					if (debug)
1310					    printf ("arc: DST = 00 (0)\n");
1311#endif
1312					break;
1313				    case 1: /* dst->st time */
1314					local.tm_isdst = -1;
1315#ifdef DEBUG
1316					if (debug)
1317					    printf ("arc: DST = 01 (1)\n");
1318#endif
1319					break;
1320				    case 2: /* st->dst time */
1321					local.tm_isdst = -1;
1322#ifdef DEBUG
1323					if (debug)
1324					    printf ("arc: DST = 10 (2)\n");
1325#endif
1326					break;
1327				    case 3: /* dst time */
1328				        local.tm_isdst = 1;
1329#ifdef DEBUG
1330					if (debug)
1331					    printf ("arc: DST = 11 (3)\n");
1332#endif
1333					break;
1334				}
1335				break;
1336			    default:
1337				msyslog(LOG_NOTICE, "ARCRON: Invalid mode %d",
1338					peer->MODE);
1339				return;
1340				break;
1341			}
1342			unixtime = mktime (&local);
1343			if ((gmtp = gmtime (&unixtime)) == NULL)
1344			{
1345				pp->lencode = 0;
1346				refclock_report (peer, CEVNT_FAULT);
1347				return;
1348			}
1349			pp->year = gmtp->tm_year+1900;
1350			month = gmtp->tm_mon+1;
1351			pp->day = ymd2yd(pp->year,month,gmtp->tm_mday);
1352			/* pp->day = gmtp->tm_yday; */
1353			pp->hour = gmtp->tm_hour;
1354			pp->minute = gmtp->tm_min;
1355			pp->second = gmtp->tm_sec;
1356#ifdef DEBUG
1357			if (debug)
1358			{
1359				printf ("arc: time is %04d/%02d/%02d %02d:%02d:%02d UTC\n",
1360					pp->year,month,gmtp->tm_mday,pp->hour,pp->minute,
1361					pp->second);
1362			}
1363#endif
1364		} else
1365		{
1366			/*
1367			* For more rational sites distributing UTC
1368			*/
1369			pp->day    = ymd2yd(pp->year,month,pp->day);
1370		}
1371	}
1372
1373	if (peer->MODE == 0) { /* compatiblity to original version */
1374				/* If clock signal quality is
1375				 * unknown, revert to default PRECISION...*/
1376		if(up->quality == QUALITY_UNKNOWN) {
1377			peer->precision = PRECISION;
1378		} else { /* ...else improve precision if flag3 is set... */
1379			peer->precision = ((pp->sloppyclockflag & CLK_FLAG3) ?
1380					   HIGHPRECISION : PRECISION);
1381		}
1382	} else {
1383		if ((status == 0x3) && (pp->sloppyclockflag & CLK_FLAG2)) {
1384			peer->precision = ((pp->sloppyclockflag & CLK_FLAG3) ?
1385					   HIGHPRECISION : PRECISION);
1386		} else if (up->quality == QUALITY_UNKNOWN) {
1387			peer->precision = PRECISION;
1388		} else {
1389			peer->precision = ((pp->sloppyclockflag & CLK_FLAG3) ?
1390					   HIGHPRECISION : PRECISION);
1391		}
1392	}
1393
1394	/* Notice and log any change (eg from initial defaults) for flags. */
1395	if(up->saved_flags != pp->sloppyclockflag) {
1396#ifdef DEBUG
1397		msyslog(LOG_NOTICE, "ARCRON: flags enabled: %s%s%s%s",
1398			((pp->sloppyclockflag & CLK_FLAG1) ? "1" : "."),
1399			((pp->sloppyclockflag & CLK_FLAG2) ? "2" : "."),
1400			((pp->sloppyclockflag & CLK_FLAG3) ? "3" : "."),
1401			((pp->sloppyclockflag & CLK_FLAG4) ? "4" : "."));
1402		/* Note effects of flags changing... */
1403		if(debug) {
1404			printf("arc: PRECISION = %d.\n", peer->precision);
1405		}
1406#endif
1407		up->saved_flags = pp->sloppyclockflag;
1408	}
1409
1410	/* Note time of last believable timestamp. */
1411	pp->lastrec = up->lastrec;
1412
1413#ifdef ARCRON_LEAPSECOND_KEEN
1414	/* Find out if a leap-second might just have happened...
1415	   (ie is this the first hour of the first day of Jan or Jul?)
1416	*/
1417	if((pp->hour == 0) &&
1418	   (pp->day == 1) &&
1419	   ((month == 1) || (month == 7))) {
1420		if(possible_leap >= 0) {
1421			/* A leap may have happened, and no resync has started yet...*/
1422			possible_leap = 1;
1423		}
1424	} else {
1425		/* Definitely not leap-second territory... */
1426		possible_leap = 0;
1427	}
1428#endif
1429
1430	if (!refclock_process(pp)) {
1431		pp->lencode = 0;
1432		refclock_report(peer, CEVNT_BADTIME);
1433		return;
1434	}
1435	record_clock_stats(&peer->srcadr, pp->a_lastcode);
1436	refclock_receive(peer);
1437}
1438
1439
1440/* request_time() sends a time request to the clock with given peer. */
1441/* This automatically reports a fault if necessary. */
1442/* No data should be sent after this until arc_poll() returns. */
1443static  void    request_time    (int, struct peer *);
1444static void
1445request_time(
1446	int unit,
1447	struct peer *peer
1448	)
1449{
1450	struct refclockproc *pp = peer->procptr;
1451	register struct arcunit *up = (struct arcunit *)pp->unitptr;
1452#ifdef DEBUG
1453	if(debug) { printf("arc: unit %d: requesting time.\n", unit); }
1454#endif
1455	if (!send_slow(up, pp->io.fd, "o\r")) {
1456#ifdef DEBUG
1457		if (debug) {
1458			printf("arc: unit %d: problem sending", unit);
1459		}
1460#endif
1461		pp->lencode = 0;
1462		refclock_report(peer, CEVNT_FAULT);
1463		return;
1464	}
1465	pp->polls++;
1466}
1467
1468/*
1469 * arc_poll - called by the transmit procedure
1470 */
1471static void
1472arc_poll(
1473	int unit,
1474	struct peer *peer
1475	)
1476{
1477	register struct arcunit *up;
1478	struct refclockproc *pp;
1479	int resync_needed;              /* Should we start a resync? */
1480
1481	pp = peer->procptr;
1482	up = (struct arcunit *)pp->unitptr;
1483#if 0
1484	pp->lencode = 0;
1485	memset(pp->a_lastcode, 0, sizeof(pp->a_lastcode));
1486#endif
1487
1488#if 0
1489	/* Flush input. */
1490	tcflush(pp->io.fd, TCIFLUSH);
1491#endif
1492
1493	/* Resync if our next scheduled resync time is here or has passed. */
1494	resync_needed = ( !(pp->sloppyclockflag & CLK_FLAG2) &&
1495			  (up->next_resync <= current_time) );
1496
1497#ifdef ARCRON_LEAPSECOND_KEEN
1498	/*
1499	  Try to catch a potential leap-second insertion or deletion quickly.
1500
1501	  In addition to the normal NTP fun of clocks that don't report
1502	  leap-seconds spooking their hosts, this clock does not even
1503	  sample the radio sugnal the whole time, so may miss a
1504	  leap-second insertion or deletion for up to a whole sample
1505	  time.
1506
1507	  To try to minimise this effect, if in the first few minutes of
1508	  the day immediately following a leap-second-insertion point
1509	  (ie in the first hour of the first day of the first and sixth
1510	  months), and if the last resync was in the previous day, and a
1511	  resync is not already in progress, resync the clock
1512	  immediately.
1513
1514	*/
1515	if((possible_leap > 0) &&       /* Must be 00:XX 01/0{1,7}/XXXX. */
1516	   (!up->resyncing)) {          /* No resync in progress yet. */
1517		resync_needed = 1;
1518		possible_leap = -1;          /* Prevent multiple resyncs. */
1519		msyslog(LOG_NOTICE,"ARCRON: unit %d: checking for leap second",unit);
1520	}
1521#endif
1522
1523	/* Do a resync if required... */
1524	if(resync_needed) {
1525		/* First, reset quality value to `unknown' so we can detect */
1526		/* when a quality message has been responded to by this     */
1527		/* being set to some other value.                           */
1528		up->quality = QUALITY_UNKNOWN;
1529
1530		/* Note that we are resyncing... */
1531		up->resyncing = 1;
1532
1533		/* Now actually send the resync command and an immediate poll. */
1534#ifdef DEBUG
1535		if(debug) { printf("arc: sending resync command (h\\r).\n"); }
1536#endif
1537		msyslog(LOG_NOTICE, "ARCRON: unit %d: sending resync command", unit);
1538		send_slow(up, pp->io.fd, "h\r");
1539
1540		/* Schedule our next resync... */
1541		up->next_resync = current_time + DEFAULT_RESYNC_TIME;
1542
1543		/* Drop through to request time if appropriate. */
1544	}
1545
1546	/* If clock quality is too poor to trust, indicate a fault. */
1547	/* If quality is QUALITY_UNKNOWN and ARCRON_KEEN is defined,*/
1548	/* we'll cross our fingers and just hope that the thing     */
1549	/* synced so quickly we did not catch it---we'll            */
1550	/* double-check the clock is OK elsewhere.                  */
1551	if(
1552#ifdef ARCRON_KEEN
1553		(up->quality != QUALITY_UNKNOWN) &&
1554#else
1555		(up->quality == QUALITY_UNKNOWN) ||
1556#endif
1557		(up->quality < MIN_CLOCK_QUALITY_OK)) {
1558#ifdef DEBUG
1559		if(debug) {
1560			printf("arc: clock quality %d too poor.\n", up->quality);
1561		}
1562#endif
1563		pp->lencode = 0;
1564		refclock_report(peer, CEVNT_FAULT);
1565		return;
1566	}
1567	/* This is the normal case: request a timestamp. */
1568	request_time(unit, peer);
1569}
1570
1571#else
1572int refclock_arc_bs;
1573#endif
1574