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