refclock_arc.c revision 82498
1229997Sken/*
2229997Sken * refclock_arc - clock driver for ARCRON MSF receivers
3229997Sken */
4229997Sken
5229997Sken#ifdef HAVE_CONFIG_H
6229997Sken#include <config.h>
7229997Sken#endif
8229997Sken
9229997Sken#if defined(REFCLOCK) && defined(CLOCK_ARCRON_MSF)
10229997Skenstatic const char arc_version[] = { "V1.1 1997/06/23" };
11229997Sken
12229997Sken#undef ARCRON_DEBUG /* Define only while in development... */
13229997Sken
14229997Sken#ifndef ARCRON_NOT_KEEN
15229997Sken#define ARCRON_KEEN 1 /* Be keen, and trusting of the clock, if defined. */
16229997Sken#endif
17229997Sken
18229997Sken#ifndef ARCRON_NOT_MULTIPLE_SAMPLES
19229997Sken#define ARCRON_MULTIPLE_SAMPLES 1 /* Use all timestamp bytes as samples. */
20229997Sken#endif
21229997Sken
22229997Sken#ifndef ARCRON_NOT_LEAPSECOND_KEEN
23229997Sken#ifndef ARCRON_LEAPSECOND_KEEN
24229997Sken#undef ARCRON_LEAPSECOND_KEEN /* Respond quickly to leap seconds: doesn't work yet. */
25229997Sken#endif
26229997Sken#endif
27229997Sken
28229997Sken/*
29229997SkenCode by Derek Mulcahy, <derek@toybox.demon.co.uk>, 1997.
30229997SkenModifications by Damon Hart-Davis, <d@hd.org>, 1997.
31229997Sken
32229997SkenTHIS CODE IS SUPPLIED AS IS, WITH NO WARRANTY OF ANY KIND.  USE AT
33229997SkenYOUR OWN RISK.
34229997Sken
35229997SkenOrginally developed and used with ntp3-5.85 by Derek Mulcahy.
36229997Sken
37229997SkenBuilt against ntp3-5.90 on Solaris 2.5 using gcc 2.7.2.
38229997Sken
39229997SkenThis code may be freely copied and used and incorporated in other
40229997Skensystems providing the disclaimer and notice of authorship are
41229997Skenreproduced.
42229997Sken
43229997Sken-------------------------------------------------------------------------------
44229997Sken
45229997SkenAuthor's original note:
46229997Sken
47229997SkenI enclose my ntp driver for the Galleon Systems Arc MSF receiver.
48229997Sken
49229997SkenIt works (after a fashion) on both Solaris-1 and Solaris-2.
50229997Sken
51229997SkenI am currently using ntp3-5.85.  I have been running the code for
52229997Skenabout 7 months without any problems.  Even coped with the change to BST!
53229997Sken
54229997SkenI had to do some funky things to read from the clock because it uses the
55229997Skenpower from the receive lines to drive the transmit lines.  This makes the
56229997Skencode look a bit stupid but it works.  I also had to put in some delays to
57229997Skenallow for the turnaround time from receive to transmit.  These delays
58229997Skenare between characters when requesting a time stamp so that shouldn't affect
59229997Skenthe results too drastically.
60229997Sken
61229997Sken...
62229997Sken
63229997SkenThe bottom line is that it works but could easily be improved.  You are
64229997Skenfree to do what you will with the code.  I haven't been able to determine
65229997Skenhow good the clock is.  I think that this requires a known good clock
66229997Skento compare it against.
67229997Sken
68229997Sken-------------------------------------------------------------------------------
69229997Sken
70229997SkenDamon's notes for adjustments:
71229997Sken
72229997SkenMAJOR CHANGES SINCE V1.0
73229997Sken========================
74229997Sken 1) Removal of pollcnt variable that made the clock go permanently
75229997Sken    off-line once two time polls failed to gain responses.
76229997Sken
77229997Sken 2) Avoiding (at least on Solaris-2) terminal becoming the controlling
78229997Sken    terminal of the process when we do a low-level open().
79229997Sken
80229997Sken 3) Additional logic (conditional on ARCRON_LEAPSECOND_KEEN being
81229997Sken    defined) to try to resync quickly after a potential leap-second
82229997Sken    insertion or deletion.
83229997Sken
84229997Sken 4) Code significantly slimmer at run-time than V1.0.
85229997Sken
86229997Sken
87229997SkenGENERAL
88229997Sken=======
89229997Sken
90229997Sken 1) The C preprocessor symbol to have the clock built has been changed
91229997Sken    from ARC to ARCRON_MSF to CLOCK_ARCRON_MSF to minimise the
92229997Sken    possiblity of clashes with other symbols in the future.
93229997Sken
94229997Sken 2) PRECISION should be -4/-5 (63ms/31ms) for the following reasons:
95229997Sken
96229997Sken     a) The ARC documentation claims the internal clock is (only)
97229997Sken        accurate to about 20ms relative to Rugby (plus there must be
98229997Sken        noticable drift and delay in the ms range due to transmission
99229997Sken        delays and changing atmospheric effects).  This clock is not
100229997Sken        designed for ms accuracy as NTP has spoilt us all to expect.
101229997Sken
102229997Sken     b) The clock oscillator looks like a simple uncompensated quartz
103229997Sken        crystal of the sort used in digital watches (ie 32768Hz) which
104229997Sken        can have large temperature coefficients and drifts; it is not
105229997Sken        clear if this oscillator is properly disciplined to the MSF
106229997Sken        transmission, but as the default is to resync only once per
107229997Sken        *day*, we can imagine that it is not, and is free-running.  We
108229997Sken        can minimise drift by resyncing more often (at the cost of
109229997Sken        reduced battery life), but drift/wander may still be
110229997Sken        significant.
111229997Sken
112229997Sken     c) Note that the bit time of 3.3ms adds to the potential error in
113229997Sken        the the clock timestamp, since the bit clock of the serial link
114229997Sken        may effectively be free-running with respect to the host clock
115229997Sken        and the MSF clock.  Actually, the error is probably 1/16th of
116229997Sken        the above, since the input data is probably sampled at at least
117229997Sken        16x the bit rate.
118229997Sken
119229997Sken    By keeping the clock marked as not very precise, it will have a
120229997Sken    fairly large dispersion, and thus will tend to be used as a
121229997Sken    `backup' time source and sanity checker, which this clock is
122229997Sken    probably ideal for.  For an isolated network without other time
123229997Sken    sources, this clock can probably be expected to provide *much*
124229997Sken    better than 1s accuracy, which will be fine.
125229997Sken
126229997Sken    By default, PRECISION is set to -4, but experience, especially at a
127229997Sken    particular geographic location with a particular clock, may allow
128229997Sken    this to be altered to -5.  (Note that skews of +/- 10ms are to be
129229997Sken    expected from the clock from time-to-time.)  This improvement of
130229997Sken    reported precision can be instigated by setting flag3 to 1, though
131229997Sken    the PRECISION will revert to the normal value while the clock
132229997Sken    signal quality is unknown whatever the flag3 setting.
133229997Sken
134229997Sken    IN ANY CASE, BE SURE TO SET AN APPROPRIATE FUDGE FACTOR TO REMOVE
135229997Sken    ANY RESIDUAL SKEW, eg:
136229997Sken
137229997Sken        server 127.127.27.0 # ARCRON MSF radio clock unit 0.
138229997Sken        # Fudge timestamps by about 20ms.
139229997Sken        fudge 127.127.27.0 time1 0.020
140229997Sken
141229997Sken    You will need to observe your system's behaviour, assuming you have
142229997Sken    some other NTP source to compare it with, to work out what the
143229997Sken    fudge factor should be.  For my Sun SS1 running SunOS 4.1.3_U1 with
144229997Sken    my MSF clock with my distance from the MSF transmitter, +20ms
145229997Sken    seemed about right, after some observation.
146229997Sken
147229997Sken 3) REFID has been made "MSFa" to reflect the MSF time source and the
148229997Sken    ARCRON receiver.
149229997Sken
150229997Sken 4) DEFAULT_RESYNC_TIME is the time in seconds (by default) before
151229997Sken    forcing a resync since the last attempt.  This is picked to give a
152229997Sken    little less than an hour between resyncs and to try to avoid
153229997Sken    clashing with any regular event at a regular time-past-the-hour
154229997Sken    which might cause systematic errors.
155229997Sken
156229997Sken    The INITIAL_RESYNC_DELAY is to avoid bothering the clock and
157229997Sken    running down its batteries unnecesarily if ntpd is going to crash
158229997Sken    or be killed or reconfigured quickly.  If ARCRON_KEEN is defined
159229997Sken    then this period is long enough for (with normal polling rates)
160229997Sken    enough time samples to have been taken to allow ntpd to sync to
161229997Sken    the clock before the interruption for the clock to resync to MSF.
162229997Sken    This avoids ntpd syncing to another peer first and then
163229997Sken    almost immediately hopping to the MSF clock.
164229997Sken
165229997Sken    The RETRY_RESYNC_TIME is used before rescheduling a resync after a
166229997Sken    resync failed to reveal a statisfatory signal quality (too low or
167229997Sken    unknown).
168229997Sken
169229997Sken 5) The clock seems quite jittery, so I have increased the
170229997Sken    median-filter size from the typical (previous) value of 3.  I
171229997Sken    discard up to half the results in the filter.  It looks like maybe
172229997Sken    1 sample in 10 or so (maybe less) is a spike, so allow the median
173229997Sken    filter to discard at least 10% of its entries or 1 entry, whichever
174229997Sken    is greater.
175229997Sken
176254759Strasz 6) Sleeping *before* each character sent to the unit to allow required
177254759Strasz    inter-character time but without introducting jitter and delay in
178254759Strasz    handling the response if possible.
179254759Strasz
180254759Strasz 7) If the flag ARCRON_KEEN is defined, take time samples whenever
181254759Strasz    possible, even while resyncing, etc.  We rely, in this case, on the
182229997Sken    clock always giving us a reasonable time or else telling us in the
183229997Sken    status byte at the end of the timestamp that it failed to sync to
184229997Sken    MSF---thus we should never end up syncing to completely the wrong
185229997Sken    time.
186229997Sken
187229997Sken 8) If the flag ARCRON_OWN_FILTER is defined, use own versions of
188229997Sken    refclock median-filter routines to get round small bug in 3-5.90
189229997Sken    code which does not return the median offset. XXX Removed this
190229997Sken    bit due NTP Version 4 upgrade - dlm.
191229997Sken
192229997Sken 9) We would appear to have a year-2000 problem with this clock since
193229997Sken    it returns only the two least-significant digits of the year.  But
194229997Sken    ntpd ignores the year and uses the local-system year instead, so
195229997Sken    this is in fact not a problem.  Nevertheless, we attempt to do a
196254759Strasz    sensible thing with the dates, wrapping them into a 100-year
197229997Sken    window.
198229997Sken
199229997Sken 10)Logs stats information that can be used by Derek's Tcl/Tk utility
200229997Sken    to show the status of the clock.
201229997Sken
202229997Sken 11)The clock documentation insists that the number of bits per
203229997Sken    character to be sent to the clock, and sent by it, is 11, including
204229997Sken    one start bit and two stop bits.  The data format is either 7+even
205229997Sken    or 8+none.
206229997Sken
207229997Sken
208229997SkenTO-DO LIST
209229997Sken==========
210229997Sken
211229997Sken  * Eliminate use of scanf(), and maybe sprintf().
212229997Sken
213229997Sken  * Allow user setting of resync interval to trade battery life for
214229997Sken    accuracy; maybe could be done via fudge factor or unit number.
215229997Sken
216229997Sken  * Possibly note the time since the last resync of the MSF clock to
217229997Sken    MSF as the age of the last reference timestamp, ie trust the
218229997Sken    clock's oscillator not very much...
219229997Sken
220229997Sken  * Add very slow auto-adjustment up to a value of +/- time2 to correct
221229997Sken    for long-term errors in the clock value (time2 defaults to 0 so the
222229997Sken    correction would be disabled by default).
223229997Sken
224229997Sken  * Consider trying to use the tty_clk/ppsclock support.
225229997Sken
226229997Sken  * Possibly use average or maximum signal quality reported during
227229997Sken    resync, rather than just the last one, which may be atypical.
228229997Sken
229229997Sken*/
230229997Sken
231229997Sken
232229997Sken/* Notes for HKW Elektronik GmBH Radio clock driver */
233229997Sken/* Author Lyndon David, Sentinet Ltd, Feb 1997      */
234229997Sken/* These notes seem also to apply usefully to the ARCRON clock. */
235229997Sken
236229997Sken/* The HKW clock module is a radio receiver tuned into the Rugby */
237229997Sken/* MSF time signal tranmitted on 60 kHz. The clock module connects */
238229997Sken/* to the computer via a serial line and transmits the time encoded */
239229997Sken/* in 15 bytes at 300 baud 7 bits two stop bits even parity */
240229997Sken
241229997Sken/* Clock communications, from the datasheet */
242229997Sken/* All characters sent to the clock are echoed back to the controlling */
243229997Sken/* device. */
244229997Sken/* Transmit time/date information */
245229997Sken/* syntax ASCII o<cr> */
246229997Sken/* Character o may be replaced if neccesary by a character whose code */
247229997Sken/* contains the lowest four bits f(hex) eg */
248229997Sken/* syntax binary: xxxx1111 00001101 */
249229997Sken
250229997Sken/* DHD note:
251229997SkenYou have to wait for character echo + 10ms before sending next character.
252229997Sken*/
253229997Sken
254229997Sken/* The clock replies to this command with a sequence of 15 characters */
255229997Sken/* which contain the complete time and a final <cr> making 16 characters */
256229997Sken/* in total. */
257229997Sken/* The RC computer clock will not reply immediately to this command because */
258229997Sken/* the start bit edge of the first reply character marks the beginning of */
259229997Sken/* the second. So the RC Computer Clock will reply to this command at the */
260229997Sken/* start of the next second */
261229997Sken/* The characters have the following meaning */
262229997Sken/* 1. hours tens   */
263229997Sken/* 2. hours units  */
264229997Sken/* 3. minutes tens */
265229997Sken/* 4. minutes units */
266229997Sken/* 5. seconds tens  */
267229997Sken/* 6. seconds units */
268229997Sken/* 7. day of week 1-monday 7-sunday */
269229997Sken/* 8. day of month tens */
270229997Sken/* 9. day of month units */
271229997Sken/* 10. month tens */
272229997Sken/* 11. month units */
273229997Sken/* 12. year tens */
274229997Sken/* 13. year units */
275229997Sken/* 14. BST/UTC status */
276229997Sken/*      bit 7   parity */
277229997Sken/*      bit 6   always 0 */
278229997Sken/*      bit 5   always 1 */
279229997Sken/*      bit 4   always 1 */
280229997Sken/*      bit 3   always 0 */
281229997Sken/*      bit 2   =1 if UTC is in effect, complementary to the BST bit */
282229997Sken/*      bit 1   =1 if BST is in effect, according to the BST bit     */
283229997Sken/*      bit 0   BST/UTC change impending bit=1 in case of change impending */
284229997Sken/* 15. status */
285229997Sken/*      bit 7   parity */
286229997Sken/*      bit 6   always 0 */
287229997Sken/*      bit 5   always 1 */
288229997Sken/*      bit 4   always 1 */
289229997Sken/*      bit 3   =1 if low battery is detected */
290232604Strasz/*      bit 2   =1 if the very last reception attempt failed and a valid */
291232604Strasz/*              time information already exists (bit0=1) */
292232604Strasz/*              =0 if the last reception attempt was successful */
293232604Strasz/*      bit 1   =1 if at least one reception since 2:30 am was successful */
294232604Strasz/*              =0 if no reception attempt since 2:30 am was successful */
295229997Sken/*      bit 0   =1 if the RC Computer Clock contains valid time information */
296229997Sken/*              This bit is zero after reset and one after the first */
297229997Sken/*              successful reception attempt */
298229997Sken
299229997Sken/* DHD note:
300229997SkenAlso note g<cr> command which confirms that a resync is in progress, and
301if so what signal quality (0--5) is available.
302Also note h<cr> command which starts a resync to MSF signal.
303*/
304
305
306#include "ntpd.h"
307#include "ntp_io.h"
308#include "ntp_refclock.h"
309#include "ntp_stdlib.h"
310
311#include <stdio.h>
312#include <ctype.h>
313
314#if defined(HAVE_BSD_TTYS)
315#include <sgtty.h>
316#endif /* HAVE_BSD_TTYS */
317
318#if defined(HAVE_SYSV_TTYS)
319#include <termio.h>
320#endif /* HAVE_SYSV_TTYS */
321
322#if defined(HAVE_TERMIOS)
323#include <termios.h>
324#endif
325
326/*
327 * This driver supports the ARCRON MSF Radio Controlled Clock
328 */
329
330/*
331 * Interface definitions
332 */
333#define DEVICE          "/dev/arc%d"    /* Device name and unit. */
334#define SPEED           B300            /* UART speed (300 baud) */
335#define PRECISION       (-4)            /* Precision  (~63 ms). */
336#define HIGHPRECISION   (-5)            /* If things are going well... */
337#define REFID           "MSFa"          /* Reference ID. */
338#define DESCRIPTION     "ARCRON MSF Receiver"
339
340#define NSAMPLESLONG    8               /* Stages of long filter. */
341
342#define LENARC          16              /* Format `o' timecode length. */
343
344#define BITSPERCHAR     11              /* Bits per character. */
345#define BITTIME         0x0DA740E       /* Time for 1 bit at 300bps. */
346#define CHARTIME10      0x8888888       /* Time for 10-bit char at 300bps. */
347#define CHARTIME11      0x962FC96       /* Time for 11-bit char at 300bps. */
348#define CHARTIME                        /* Time for char at 300bps. */ \
349( (BITSPERCHAR == 11) ? CHARTIME11 : ( (BITSPERCHAR == 10) ? CHARTIME10 : \
350				       (BITSPERCHAR * BITTIME) ) )
351
352     /* Allow for UART to accept char half-way through final stop bit. */
353#define INITIALOFFSET (u_int32)(-BITTIME/2)
354
355     /*
356    charoffsets[x] is the time after the start of the second that byte
357    x (with the first byte being byte 1) is received by the UART,
358    assuming that the initial edge of the start bit of the first byte
359    is on-time.  The values are represented as the fractional part of
360    an l_fp.
361
362    We store enough values to have the offset of each byte including
363    the trailing \r, on the assumption that the bytes follow one
364    another without gaps.
365    */
366     static const u_int32 charoffsets[LENARC+1] = {
367#if BITSPERCHAR == 11 /* Usual case. */
368	     /* Offsets computed as accurately as possible... */
369	     0,
370	     INITIALOFFSET + 0x0962fc96, /*  1 chars,  11 bits */
371	     INITIALOFFSET + 0x12c5f92c, /*  2 chars,  22 bits */
372	     INITIALOFFSET + 0x1c28f5c3, /*  3 chars,  33 bits */
373	     INITIALOFFSET + 0x258bf259, /*  4 chars,  44 bits */
374	     INITIALOFFSET + 0x2eeeeeef, /*  5 chars,  55 bits */
375	     INITIALOFFSET + 0x3851eb85, /*  6 chars,  66 bits */
376	     INITIALOFFSET + 0x41b4e81b, /*  7 chars,  77 bits */
377	     INITIALOFFSET + 0x4b17e4b1, /*  8 chars,  88 bits */
378	     INITIALOFFSET + 0x547ae148, /*  9 chars,  99 bits */
379	     INITIALOFFSET + 0x5dddddde, /* 10 chars, 110 bits */
380	     INITIALOFFSET + 0x6740da74, /* 11 chars, 121 bits */
381	     INITIALOFFSET + 0x70a3d70a, /* 12 chars, 132 bits */
382	     INITIALOFFSET + 0x7a06d3a0, /* 13 chars, 143 bits */
383	     INITIALOFFSET + 0x8369d037, /* 14 chars, 154 bits */
384	     INITIALOFFSET + 0x8ccccccd, /* 15 chars, 165 bits */
385	     INITIALOFFSET + 0x962fc963  /* 16 chars, 176 bits */
386#else
387	     /* Offsets computed with a small rounding error... */
388	     0,
389	     INITIALOFFSET +  1 * CHARTIME,
390	     INITIALOFFSET +  2 * CHARTIME,
391	     INITIALOFFSET +  3 * CHARTIME,
392	     INITIALOFFSET +  4 * CHARTIME,
393	     INITIALOFFSET +  5 * CHARTIME,
394	     INITIALOFFSET +  6 * CHARTIME,
395	     INITIALOFFSET +  7 * CHARTIME,
396	     INITIALOFFSET +  8 * CHARTIME,
397	     INITIALOFFSET +  9 * CHARTIME,
398	     INITIALOFFSET + 10 * CHARTIME,
399	     INITIALOFFSET + 11 * CHARTIME,
400	     INITIALOFFSET + 12 * CHARTIME,
401	     INITIALOFFSET + 13 * CHARTIME,
402	     INITIALOFFSET + 14 * CHARTIME,
403	     INITIALOFFSET + 15 * CHARTIME,
404	     INITIALOFFSET + 16 * CHARTIME
405#endif
406     };
407
408/* Chose filter length dependent on fudge flag 4. */
409#define CHOSENSAMPLES(pp) \
410(((pp)->sloppyclockflag & CLK_FLAG4) ? NSAMPLESLONG : NSAMPLES)
411     /*
412Chose how many filter samples to keep.  Several factors are in play.
413
414 1) Discard at least one sample to allow a spike value to be
415    discarded.
416
417 2) Discard about 1-in-8 to 1-in-30 samples to handle spikes.
418
419 3) Keep an odd number of samples to avoid median value being biased
420    high or low.
421*/
422#define NKEEP(pp) ((CHOSENSAMPLES(pp) - 1 - (CHOSENSAMPLES(pp)>>3)) | 1)
423
424#define DEFAULT_RESYNC_TIME  (57*60)    /* Gap between resync attempts (s). */
425#define RETRY_RESYNC_TIME    (27*60)    /* Gap to emergency resync attempt. */
426#ifdef ARCRON_KEEN
427#define INITIAL_RESYNC_DELAY 500        /* Delay before first resync. */
428#else
429#define INITIAL_RESYNC_DELAY 50         /* Delay before first resync. */
430#endif
431
432     static const int moff[12] =
433{ 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 };
434/* Flags for a raw open() of the clock serial device. */
435#ifdef O_NOCTTY /* Good, we can avoid tty becoming controlling tty. */
436#define OPEN_FLAGS (O_RDWR | O_NOCTTY)
437#else           /* Oh well, it may not matter... */
438#define OPEN_FLAGS (O_RDWR)
439#endif
440
441
442/* Length of queue of command bytes to be sent. */
443#define CMDQUEUELEN 4                   /* Enough for two cmds + each \r. */
444/* Queue tick time; interval in seconds between chars taken off queue. */
445/* Must be >= 2 to allow o\r response to come back uninterrupted. */
446#define QUEUETICK   2                   /* Allow o\r reply to finish. */
447
448/*
449 * ARC unit control structure
450 */
451struct arcunit {
452	l_fp lastrec;       /* Time tag for the receive time (system). */
453	int status;         /* Clock status. */
454
455	int quality;        /* Quality of reception 0--5 for unit. */
456	/* We may also use the values -1 or 6 internally. */
457
458	u_long next_resync; /* Next resync time (s) compared to current_time. */
459	int resyncing;      /* Resync in progress if true. */
460
461	/* In the outgoing queue, cmdqueue[0] is next to be sent. */
462	char cmdqueue[CMDQUEUELEN+1]; /* Queue of outgoing commands + \0. */
463
464	u_long saved_flags; /* Saved fudge flags. */
465};
466#ifdef ARCRON_LEAPSECOND_KEEN
467/* The flag `possible_leap' is set non-zero when any MSF unit
468       thinks a leap-second may have happened.
469
470       Set whenever we receive a valid time sample in the first hour of
471       the first day of the first/seventh months.
472
473       Outside the special hour this value is unconditionally set
474       to zero by the receive routine.
475
476       On finding itself in this timeslot, as long as the value is
477       non-negative, the receive routine sets it to a positive value to
478       indicate a resync to MSF should be performed.
479
480       In the poll routine, if this value is positive and we are not
481       already resyncing (eg from a sync that started just before
482       midnight), start resyncing and set this value negative to
483       indicate that a leap-triggered resync has been started.  Having
484       set this negative prevents the receive routine setting it
485       positive and thus prevents multiple resyncs during the witching
486       hour.
487     */
488static int possible_leap = 0;       /* No resync required by default. */
489#endif
490
491#if 0
492static void dummy_event_handler P((struct peer *));
493static void   arc_event_handler P((struct peer *));
494#endif /* 0 */
495
496#define QUALITY_UNKNOWN     -1 /* Indicates unknown clock quality. */
497#define MIN_CLOCK_QUALITY    0 /* Min quality clock will return. */
498#define MIN_CLOCK_QUALITY_OK 3 /* Min quality for OK reception. */
499#define MAX_CLOCK_QUALITY    5 /* Max quality clock will return. */
500
501/*
502 * Function prototypes
503 */
504static  int     arc_start       P((int, struct peer *));
505static  void    arc_shutdown    P((int, struct peer *));
506static  void    arc_receive     P((struct recvbuf *));
507static  void    arc_poll        P((int, struct peer *));
508
509/*
510 * Transfer vector
511 */
512struct  refclock refclock_arc = {
513	arc_start,              /* start up driver */
514	arc_shutdown,           /* shut down driver */
515	arc_poll,               /* transmit poll message */
516	noentry,                /* not used (old arc_control) */
517	noentry,                /* initialize driver (not used) */
518	noentry,                /* not used (old arc_buginfo) */
519	NOFLAGS                 /* not used */
520};
521
522/* Queue us up for the next tick. */
523#define ENQUEUE(up) \
524	do { \
525	     if((up)->ev.next != 0) { break; } /* WHOOPS! */ \
526	     peer->nextdate = current_time + QUEUETICK; \
527	} while(0)
528
529#if 0
530/* Placeholder event handler---does nothing safely---soaks up lose tick. */
531static void
532dummy_event_handler(
533	struct peer *peer
534	)
535{
536#ifdef ARCRON_DEBUG
537	if(debug) { printf("arc: dummy_event_handler() called.\n"); }
538#endif
539}
540
541/*
542Normal event handler.
543
544Take first character off queue and send to clock if not a null.
545
546Shift characters down and put a null on the end.
547
548We assume that there is no parallelism so no race condition, but even
549if there is nothing bad will happen except that we might send some bad
550data to the clock once in a while.
551*/
552static void
553arc_event_handler(
554	struct peer *peer
555	)
556{
557	struct refclockproc *pp = peer->procptr;
558	register struct arcunit *up = (struct arcunit *)pp->unitptr;
559	int i;
560	char c;
561#ifdef ARCRON_DEBUG
562	if(debug > 2) { printf("arc: arc_event_handler() called.\n"); }
563#endif
564
565	c = up->cmdqueue[0];       /* Next char to be sent. */
566	/* Shift down characters, shifting trailing \0 in at end. */
567	for(i = 0; i < CMDQUEUELEN; ++i)
568	{ up->cmdqueue[i] = up->cmdqueue[i+1]; }
569
570	/* Don't send '\0' characters. */
571	if(c != '\0') {
572		if(write(pp->io.fd, &c, 1) != 1) {
573			msyslog(LOG_NOTICE, "ARCRON: write to fd %d failed", pp->io.fd);
574		}
575#ifdef ARCRON_DEBUG
576		else if(debug) { printf("arc: sent `%2.2x', fd %d.\n", c, pp->io.fd); }
577#endif
578	}
579}
580#endif /* 0 */
581
582/*
583 * arc_start - open the devices and initialize data for processing
584 */
585static int
586arc_start(
587	int unit,
588	struct peer *peer
589	)
590{
591	register struct arcunit *up;
592	struct refclockproc *pp;
593	int fd;
594	char device[20];
595#ifdef HAVE_TERMIOS
596	struct termios arg;
597#endif
598
599	msyslog(LOG_NOTICE, "ARCRON: %s: opening unit %d", arc_version, unit);
600#ifdef ARCRON_DEBUG
601	if(debug) {
602		printf("arc: %s: attempt to open unit %d.\n", arc_version, unit);
603	}
604#endif
605
606	/* Prevent a ridiculous device number causing overflow of device[]. */
607	if((unit < 0) || (unit > 255)) { return(0); }
608
609	/*
610	 * Open serial port. Use CLK line discipline, if available.
611	 */
612	(void)sprintf(device, DEVICE, unit);
613	if (!(fd = refclock_open(device, SPEED, LDISC_CLK)))
614		return(0);
615#ifdef ARCRON_DEBUG
616	if(debug) { printf("arc: unit %d using open().\n", unit); }
617#endif
618	fd = open(device, OPEN_FLAGS);
619	if(fd < 0) {
620#ifdef DEBUG
621		if(debug) { printf("arc: failed [open()] to open %s.\n", device); }
622#endif
623		return(0);
624	}
625
626	fcntl(fd, F_SETFL, 0); /* clear the descriptor flags */
627#ifdef ARCRON_DEBUG
628	if(debug)
629	{ printf("Opened RS232 port with file descriptor %d.\n", fd); }
630#endif
631
632#ifdef HAVE_TERMIOS
633
634	arg.c_iflag = IGNBRK | ISTRIP;
635	arg.c_oflag = 0;
636	arg.c_cflag = B300 | CS8 | CREAD | CLOCAL | CSTOPB;
637	arg.c_lflag = 0;
638	arg.c_cc[VMIN] = 1;
639	arg.c_cc[VTIME] = 0;
640
641	tcsetattr(fd, TCSANOW, &arg);
642
643#else
644
645	msyslog(LOG_ERR, "ARCRON: termios not supported in this driver");
646	(void)close(fd);
647
648	return 0;
649
650#endif
651
652	up = (struct arcunit *) emalloc(sizeof(struct arcunit));
653	if(!up) { (void) close(fd); return(0); }
654	/* Set structure to all zeros... */
655	memset((char *)up, 0, sizeof(struct arcunit));
656	pp = peer->procptr;
657	pp->io.clock_recv = arc_receive;
658	pp->io.srcclock = (caddr_t)peer;
659	pp->io.datalen = 0;
660	pp->io.fd = fd;
661	if(!io_addclock(&pp->io)) { (void) close(fd); free(up); return(0); }
662	pp->unitptr = (caddr_t)up;
663
664	/*
665	 * Initialize miscellaneous variables
666	 */
667	peer->precision = PRECISION;
668	peer->stratum = 2;              /* Default to stratum 2 not 0. */
669	pp->clockdesc = DESCRIPTION;
670	memcpy((char *)&pp->refid, REFID, 4);
671	/* Spread out resyncs so that they should remain separated. */
672	up->next_resync = current_time + INITIAL_RESYNC_DELAY + (67*unit)%1009;
673
674#if 0 /* Not needed because of zeroing of arcunit structure... */
675	up->resyncing = 0;              /* Not resyncing yet. */
676	up->saved_flags = 0;            /* Default is all flags off. */
677	/* Clear send buffer out... */
678	{
679		int i;
680		for(i = CMDQUEUELEN; i >= 0; --i) { up->cmdqueue[i] = '\0'; }
681	}
682#endif
683
684#ifdef ARCRON_KEEN
685	up->quality = QUALITY_UNKNOWN;  /* Trust the clock immediately. */
686#else
687	up->quality = MIN_CLOCK_QUALITY;/* Don't trust the clock yet. */
688#endif
689	return(1);
690}
691
692
693/*
694 * arc_shutdown - shut down the clock
695 */
696static void
697arc_shutdown(
698	int unit,
699	struct peer *peer
700	)
701{
702	register struct arcunit *up;
703	struct refclockproc *pp;
704
705	pp = peer->procptr;
706	up = (struct arcunit *)pp->unitptr;
707	io_closeclock(&pp->io);
708	free(up);
709}
710
711/*
712Compute space left in output buffer.
713*/
714static int
715space_left(
716	register struct arcunit *up
717	)
718{
719	int spaceleft;
720
721	/* Compute space left in buffer after any pending output. */
722	for(spaceleft = 0; spaceleft < CMDQUEUELEN; ++spaceleft)
723	{ if(up->cmdqueue[CMDQUEUELEN - 1 - spaceleft] != '\0') { break; } }
724	return(spaceleft);
725}
726
727/*
728Send command by copying into command buffer as far forward as possible,
729after any pending output.
730
731Indicate an error by returning 0 if there is not space for the command.
732*/
733static int
734send_slow(
735	register struct arcunit *up,
736	int fd,
737	const char *s
738	)
739{
740	int sl = strlen(s);
741	int spaceleft = space_left(up);
742
743#ifdef ARCRON_DEBUG
744	if(debug > 1) { printf("arc: spaceleft = %d.\n", spaceleft); }
745#endif
746	if(spaceleft < sl) { /* Should not normally happen... */
747#ifdef ARCRON_DEBUG
748		msyslog(LOG_NOTICE, "ARCRON: send-buffer overrun (%d/%d)",
749		       sl, spaceleft);
750#endif
751		return(0);                      /* FAILED! */
752	}
753
754	/* Copy in the command to be sent. */
755	while(*s) { up->cmdqueue[CMDQUEUELEN - spaceleft--] = *s++; }
756
757	return(1);
758}
759
760
761/* Macro indicating action we will take for different quality values. */
762#define quality_action(q) \
763(((q) == QUALITY_UNKNOWN) ?         "UNKNOWN, will use clock anyway" : \
764 (((q) < MIN_CLOCK_QUALITY_OK) ? "TOO POOR, will not use clock" : \
765  "OK, will use clock"))
766
767     /*
768 * arc_receive - receive data from the serial interface
769 */
770     static void
771arc_receive(
772	struct recvbuf *rbufp
773	)
774{
775	register struct arcunit *up;
776	struct refclockproc *pp;
777	struct peer *peer;
778	char c;
779	int i, n, wday, month, bst, status;
780	int arc_last_offset;
781
782	/*
783	 * Initialize pointers and read the timecode and timestamp
784	 */
785	peer = (struct peer *)rbufp->recv_srcclock;
786	pp = peer->procptr;
787	up = (struct arcunit *)pp->unitptr;
788
789
790	/*
791	  If the command buffer is empty, and we are resyncing, insert a
792	  g\r quality request into it to poll for signal quality again.
793	*/
794	if((up->resyncing) && (space_left(up) == CMDQUEUELEN)) {
795#ifdef DEBUG
796		if(debug > 1) { printf("arc: inserting signal-quality poll.\n"); }
797#endif
798		send_slow(up, pp->io.fd, "g\r");
799	}
800
801	/*
802	  The `arc_last_offset' is the offset in lastcode[] of the last byte
803	  received, and which we assume actually received the input
804	  timestamp.
805
806	  (When we get round to using tty_clk and it is available, we
807	  assume that we will receive the whole timecode with the
808	  trailing \r, and that that \r will be timestamped.  But this
809	  assumption also works if receive the characters one-by-one.)
810	*/
811	arc_last_offset = pp->lencode+rbufp->recv_length - 1;
812
813	/*
814	  We catch a timestamp iff:
815
816	  * The command code is `o' for a timestamp.
817
818	  * If ARCRON_MULTIPLE_SAMPLES is undefined then we must have
819	  exactly char in the buffer (the command code) so that we
820	  only sample the first character of the timecode as our
821	  `on-time' character.
822
823	  * The first character in the buffer is not the echoed `\r'
824	  from the `o` command (so if we are to timestamp an `\r' it
825	  must not be first in the receive buffer with lencode==1.
826	  (Even if we had other characters following it, we probably
827	  would have a premature timestamp on the '\r'.)
828
829	  * We have received at least one character (I cannot imagine
830	  how it could be otherwise, but anyway...).
831	*/
832	c = rbufp->recv_buffer[0];
833	if((pp->a_lastcode[0] == 'o') &&
834#ifndef ARCRON_MULTIPLE_SAMPLES
835	   (pp->lencode == 1) &&
836#endif
837	   ((pp->lencode != 1) || (c != '\r')) &&
838	   (arc_last_offset >= 1)) {
839		/* Note that the timestamp should be corrected if >1 char rcvd. */
840		l_fp timestamp;
841		timestamp = rbufp->recv_time;
842#ifdef DEBUG
843		if(debug) { /* Show \r as `R', other non-printing char as `?'. */
844			printf("arc: stamp -->%c<-- (%d chars rcvd)\n",
845			       ((c == '\r') ? 'R' : (isgraph((int)c) ? c : '?')),
846			       rbufp->recv_length);
847		}
848#endif
849
850		/*
851		  Now correct timestamp by offset of last byte received---we
852		  subtract from the receive time the delay implied by the
853		  extra characters received.
854
855		  Reject the input if the resulting code is too long, but
856		  allow for the trailing \r, normally not used but a good
857		  handle for tty_clk or somesuch kernel timestamper.
858		*/
859		if(arc_last_offset > LENARC) {
860#ifdef ARCRON_DEBUG
861			if(debug) {
862				printf("arc: input code too long (%d cf %d); rejected.\n",
863				       arc_last_offset, LENARC);
864			}
865#endif
866			pp->lencode = 0;
867			refclock_report(peer, CEVNT_BADREPLY);
868			return;
869		}
870
871		L_SUBUF(&timestamp, charoffsets[arc_last_offset]);
872#ifdef ARCRON_DEBUG
873		if(debug > 1) {
874			printf(
875				"arc: %s%d char(s) rcvd, the last for lastcode[%d]; -%sms offset applied.\n",
876				((rbufp->recv_length > 1) ? "*** " : ""),
877				rbufp->recv_length,
878				arc_last_offset,
879				mfptoms((unsigned long)0,
880					charoffsets[arc_last_offset],
881					1));
882		}
883#endif
884
885#ifdef ARCRON_MULTIPLE_SAMPLES
886		/*
887		  If taking multiple samples, capture the current adjusted
888		  sample iff:
889
890		  * No timestamp has yet been captured (it is zero), OR
891
892		  * This adjusted timestamp is earlier than the one already
893		  captured, on the grounds that this one suffered less
894		  delay in being delivered to us and is more accurate.
895
896		*/
897		if(L_ISZERO(&(up->lastrec)) ||
898		   L_ISGEQ(&(up->lastrec), &timestamp))
899#endif
900		{
901#ifdef ARCRON_DEBUG
902			if(debug > 1) {
903				printf("arc: system timestamp captured.\n");
904#ifdef ARCRON_MULTIPLE_SAMPLES
905				if(!L_ISZERO(&(up->lastrec))) {
906					l_fp diff;
907					diff = up->lastrec;
908					L_SUB(&diff, &timestamp);
909					printf("arc: adjusted timestamp by -%sms.\n",
910					       mfptoms(diff.l_i, diff.l_f, 3));
911				}
912#endif
913			}
914#endif
915			up->lastrec = timestamp;
916		}
917
918	}
919
920	/* Just in case we still have lots of rubbish in the buffer... */
921	/* ...and to avoid the same timestamp being reused by mistake, */
922	/* eg on receipt of the \r coming in on its own after the      */
923	/* timecode.                                                   */
924	if(pp->lencode >= LENARC) {
925#ifdef ARCRON_DEBUG
926		if(debug && (rbufp->recv_buffer[0] != '\r'))
927		{ printf("arc: rubbish in pp->a_lastcode[].\n"); }
928#endif
929		pp->lencode = 0;
930		return;
931	}
932
933	/* Append input to code buffer, avoiding overflow. */
934	for(i = 0; i < rbufp->recv_length; i++) {
935		if(pp->lencode >= LENARC) { break; } /* Avoid overflow... */
936		c = rbufp->recv_buffer[i];
937
938		/* Drop trailing '\r's and drop `h' command echo totally. */
939		if(c != '\r' && c != 'h') { pp->a_lastcode[pp->lencode++] = c; }
940
941		/*
942		  If we've just put an `o' in the lastcode[0], clear the
943		  timestamp in anticipation of a timecode arriving soon.
944
945		  We would expect to get to process this before any of the
946		  timecode arrives.
947		*/
948		if((c == 'o') && (pp->lencode == 1)) {
949			L_CLR(&(up->lastrec));
950#ifdef ARCRON_DEBUG
951			if(debug > 1) { printf("arc: clearing timestamp.\n"); }
952#endif
953		}
954	}
955
956	/* Handle a quality message. */
957	if(pp->a_lastcode[0] == 'g') {
958		int r, q;
959
960		if(pp->lencode < 3) { return; } /* Need more data... */
961		r = (pp->a_lastcode[1] & 0x7f); /* Strip parity. */
962		q = (pp->a_lastcode[2] & 0x7f); /* Strip parity. */
963		if(((q & 0x70) != 0x30) || ((q & 0xf) > MAX_CLOCK_QUALITY) ||
964		   ((r & 0x70) != 0x30)) {
965			/* Badly formatted response. */
966#ifdef ARCRON_DEBUG
967			if(debug) { printf("arc: bad `g' response %2x %2x.\n", r, q); }
968#endif
969			return;
970		}
971		if(r == '3') { /* Only use quality value whilst sync in progress. */
972			up->quality = (q & 0xf);
973#ifdef DEBUG
974			if(debug) { printf("arc: signal quality %d.\n", up->quality); }
975#endif
976		} else if( /* (r == '2') && */ up->resyncing) {
977#ifdef DEBUG
978			if(debug)
979			{
980				printf("arc: sync finished, signal quality %d: %s\n",
981				       up->quality,
982				       quality_action(up->quality));
983			}
984#endif
985			msyslog(LOG_NOTICE,
986			       "ARCRON: sync finished, signal quality %d: %s",
987			       up->quality,
988			       quality_action(up->quality));
989			up->resyncing = 0; /* Resync is over. */
990
991#ifdef ARCRON_KEEN
992			/* Clock quality dubious; resync earlier than usual. */
993			if((up->quality == QUALITY_UNKNOWN) ||
994			   (up->quality < MIN_CLOCK_QUALITY_OK))
995			{ up->next_resync = current_time + RETRY_RESYNC_TIME; }
996#endif
997		}
998		pp->lencode = 0;
999		return;
1000	}
1001
1002	/* Stop now if this is not a timecode message. */
1003	if(pp->a_lastcode[0] != 'o') {
1004		pp->lencode = 0;
1005		refclock_report(peer, CEVNT_BADREPLY);
1006		return;
1007	}
1008
1009	/* If we don't have enough data, wait for more... */
1010	if(pp->lencode < LENARC) { return; }
1011
1012
1013	/* WE HAVE NOW COLLECTED ONE TIMESTAMP (phew)... */
1014#ifdef ARCRON_DEBUG
1015	if(debug > 1) { printf("arc: NOW HAVE TIMESTAMP...\n"); }
1016#endif
1017
1018	/* But check that we actually captured a system timestamp on it. */
1019	if(L_ISZERO(&(up->lastrec))) {
1020#ifdef ARCRON_DEBUG
1021		if(debug) { printf("arc: FAILED TO GET SYSTEM TIMESTAMP\n"); }
1022#endif
1023		pp->lencode = 0;
1024		refclock_report(peer, CEVNT_BADREPLY);
1025		return;
1026	}
1027	/*
1028	  Append a mark of the clock's received signal quality for the
1029	  benefit of Derek Mulcahy's Tcl/Tk utility (we map the `unknown'
1030	  quality value to `6' for his s/w) and terminate the string for
1031	  sure.  This should not go off the buffer end.
1032	*/
1033	pp->a_lastcode[pp->lencode] = ((up->quality == QUALITY_UNKNOWN) ?
1034				       '6' : ('0' + up->quality));
1035	pp->a_lastcode[pp->lencode + 1] = '\0'; /* Terminate for printf(). */
1036	record_clock_stats(&peer->srcadr, pp->a_lastcode);
1037
1038	/* We don't use the micro-/milli- second part... */
1039	pp->usec = 0;
1040	pp->msec = 0;
1041
1042	n = sscanf(pp->a_lastcode, "o%2d%2d%2d%1d%2d%2d%2d%1d%1d",
1043		   &pp->hour, &pp->minute, &pp->second,
1044		   &wday, &pp->day, &month, &pp->year, &bst, &status);
1045
1046	/* Validate format and numbers. */
1047	if(n != 9) {
1048#ifdef ARCRON_DEBUG
1049		/* Would expect to have caught major problems already... */
1050		if(debug) { printf("arc: badly formatted data.\n"); }
1051#endif
1052		refclock_report(peer, CEVNT_BADREPLY);
1053		return;
1054	}
1055	/*
1056	  Validate received values at least enough to prevent internal
1057	  array-bounds problems, etc.
1058	*/
1059	if((pp->hour < 0) || (pp->hour > 23) ||
1060	   (pp->minute < 0) || (pp->minute > 59) ||
1061	   (pp->second < 0) || (pp->second > 60) /*Allow for leap seconds.*/ ||
1062	   (wday < 1) || (wday > 7) ||
1063	   (pp->day < 1) || (pp->day > 31) ||
1064	   (month < 1) || (month > 12) ||
1065	   (pp->year < 0) || (pp->year > 99)) {
1066		/* Data out of range. */
1067		refclock_report(peer, CEVNT_BADREPLY);
1068		return;
1069	}
1070	/* Check that BST/UTC bits are the complement of one another. */
1071	if(!(bst & 2) == !(bst & 4)) {
1072		refclock_report(peer, CEVNT_BADREPLY);
1073		return;
1074	}
1075
1076	if(status & 0x8) { msyslog(LOG_NOTICE, "ARCRON: battery low"); }
1077
1078	/* Year-2000 alert! */
1079	/* Attempt to wrap 2-digit date into sensible window. */
1080	if(pp->year < YEAR_PIVOT) { pp->year += 100; }		/* Y2KFixes */
1081	pp->year += 1900;	/* use full four-digit year */	/* Y2KFixes */
1082	/*
1083	  Attempt to do the right thing by screaming that the code will
1084	  soon break when we get to the end of its useful life.  What a
1085	  hero I am...  PLEASE FIX LEAP-YEAR AND WRAP CODE IN 209X!
1086	*/
1087	if(pp->year >= YEAR_PIVOT+2000-2 ) {  			/* Y2KFixes */
1088		/*This should get attention B^> */
1089		msyslog(LOG_NOTICE,
1090		       "ARCRON: fix me!  EITHER YOUR DATE IS BADLY WRONG or else I will break soon!");
1091	}
1092#ifdef DEBUG
1093	if(debug) {
1094		printf("arc: n=%d %02d:%02d:%02d %02d/%02d/%04d %1d %1d\n",
1095		       n,
1096		       pp->hour, pp->minute, pp->second,
1097		       pp->day, month, pp->year, bst, status);
1098	}
1099#endif
1100
1101	/*
1102	  The status value tested for is not strictly supported by the
1103	  clock spec since the value of bit 2 (0x4) is claimed to be
1104	  undefined for MSF, yet does seem to indicate if the last resync
1105	  was successful or not.
1106	*/
1107	pp->leap = LEAP_NOWARNING;
1108	status &= 0x7;
1109	if(status == 0x3) {
1110		if(status != up->status)
1111		{ msyslog(LOG_NOTICE, "ARCRON: signal acquired"); }
1112	} else {
1113		if(status != up->status) {
1114			msyslog(LOG_NOTICE, "ARCRON: signal lost");
1115			pp->leap = LEAP_NOTINSYNC; /* MSF clock is free-running. */
1116			up->status = status;
1117			refclock_report(peer, CEVNT_FAULT);
1118			return;
1119		}
1120	}
1121	up->status = status;
1122
1123	pp->day += moff[month - 1];
1124
1125	if(isleap_4(pp->year) && month > 2) { pp->day++; }	/* Y2KFixes */
1126
1127	/* Convert to UTC if required */
1128	if(bst & 2) {
1129		pp->hour--;
1130		if (pp->hour < 0) {
1131			pp->hour = 23;
1132			pp->day--;
1133			/* If we try to wrap round the year (BST on 1st Jan), reject.*/
1134			if(pp->day < 0) {
1135				refclock_report(peer, CEVNT_BADTIME);
1136				return;
1137			}
1138		}
1139	}
1140
1141	/* If clock signal quality is unknown, revert to default PRECISION...*/
1142	if(up->quality == QUALITY_UNKNOWN) { peer->precision = PRECISION; }
1143	/* ...else improve precision if flag3 is set... */
1144	else {
1145		peer->precision = ((pp->sloppyclockflag & CLK_FLAG3) ?
1146				   HIGHPRECISION : PRECISION);
1147	}
1148
1149	/* Notice and log any change (eg from initial defaults) for flags. */
1150	if(up->saved_flags != pp->sloppyclockflag) {
1151#ifdef ARCRON_DEBUG
1152		msyslog(LOG_NOTICE, "ARCRON: flags enabled: %s%s%s%s",
1153		       ((pp->sloppyclockflag & CLK_FLAG1) ? "1" : "."),
1154		       ((pp->sloppyclockflag & CLK_FLAG2) ? "2" : "."),
1155		       ((pp->sloppyclockflag & CLK_FLAG3) ? "3" : "."),
1156		       ((pp->sloppyclockflag & CLK_FLAG4) ? "4" : "."));
1157		/* Note effects of flags changing... */
1158		if(debug) {
1159			printf("arc: CHOSENSAMPLES(pp) = %d.\n", CHOSENSAMPLES(pp));
1160			printf("arc: NKEEP(pp) = %d.\n", NKEEP(pp));
1161			printf("arc: PRECISION = %d.\n", peer->precision);
1162		}
1163#endif
1164		up->saved_flags = pp->sloppyclockflag;
1165	}
1166
1167	/* Note time of last believable timestamp. */
1168	pp->lastrec = up->lastrec;
1169
1170#ifdef ARCRON_LEAPSECOND_KEEN
1171	/* Find out if a leap-second might just have happened...
1172	   (ie is this the first hour of the first day of Jan or Jul?)
1173	*/
1174	if((pp->hour == 0) &&
1175	   (pp->day == 1) &&
1176	   ((month == 1) || (month == 7))) {
1177		if(possible_leap >= 0) {
1178			/* A leap may have happened, and no resync has started yet...*/
1179			possible_leap = 1;
1180		}
1181	} else {
1182		/* Definitely not leap-second territory... */
1183		possible_leap = 0;
1184	}
1185#endif
1186
1187	if (!refclock_process(pp)) {
1188		refclock_report(peer, CEVNT_BADTIME);
1189		return;
1190	}
1191	refclock_receive(peer);
1192}
1193
1194
1195/* request_time() sends a time request to the clock with given peer. */
1196/* This automatically reports a fault if necessary. */
1197/* No data should be sent after this until arc_poll() returns. */
1198static  void    request_time    P((int, struct peer *));
1199static void
1200request_time(
1201	int unit,
1202	struct peer *peer
1203	)
1204{
1205	struct refclockproc *pp = peer->procptr;
1206	register struct arcunit *up = (struct arcunit *)pp->unitptr;
1207#ifdef DEBUG
1208	if(debug) { printf("arc: unit %d: requesting time.\n", unit); }
1209#endif
1210	if (!send_slow(up, pp->io.fd, "o\r")) {
1211#ifdef ARCRON_DEBUG
1212		msyslog(LOG_NOTICE, "ARCRON: unit %d: problem sending", unit);
1213#endif
1214		refclock_report(peer, CEVNT_FAULT);
1215		return;
1216	}
1217	pp->polls++;
1218}
1219
1220/*
1221 * arc_poll - called by the transmit procedure
1222 */
1223static void
1224arc_poll(
1225	int unit,
1226	struct peer *peer
1227	)
1228{
1229	register struct arcunit *up;
1230	struct refclockproc *pp;
1231	int resync_needed;              /* Should we start a resync? */
1232
1233	pp = peer->procptr;
1234	up = (struct arcunit *)pp->unitptr;
1235	pp->lencode = 0;
1236	memset(pp->a_lastcode, 0, sizeof(pp->a_lastcode));
1237
1238#if 0
1239	/* Flush input. */
1240	tcflush(pp->io.fd, TCIFLUSH);
1241#endif
1242
1243	/* Resync if our next scheduled resync time is here or has passed. */
1244	resync_needed = (up->next_resync <= current_time);
1245
1246#ifdef ARCRON_LEAPSECOND_KEEN
1247	/*
1248	  Try to catch a potential leap-second insertion or deletion quickly.
1249
1250	  In addition to the normal NTP fun of clocks that don't report
1251	  leap-seconds spooking their hosts, this clock does not even
1252	  sample the radio sugnal the whole time, so may miss a
1253	  leap-second insertion or deletion for up to a whole sample
1254	  time.
1255
1256	  To try to minimise this effect, if in the first few minutes of
1257	  the day immediately following a leap-second-insertion point
1258	  (ie in the first hour of the first day of the first and sixth
1259	  months), and if the last resync was in the previous day, and a
1260	  resync is not already in progress, resync the clock
1261	  immediately.
1262
1263	*/
1264	if((possible_leap > 0) &&       /* Must be 00:XX 01/0{1,7}/XXXX. */
1265	   (!up->resyncing)) {          /* No resync in progress yet. */
1266		resync_needed = 1;
1267		possible_leap = -1;          /* Prevent multiple resyncs. */
1268		msyslog(LOG_NOTICE,"ARCRON: unit %d: checking for leap second",unit);
1269	}
1270#endif
1271
1272	/* Do a resync if required... */
1273	if(resync_needed) {
1274		/* First, reset quality value to `unknown' so we can detect */
1275		/* when a quality message has been responded to by this     */
1276		/* being set to some other value.                           */
1277		up->quality = QUALITY_UNKNOWN;
1278
1279		/* Note that we are resyncing... */
1280		up->resyncing = 1;
1281
1282		/* Now actually send the resync command and an immediate poll. */
1283#ifdef DEBUG
1284		if(debug) { printf("arc: sending resync command (h\\r).\n"); }
1285#endif
1286		msyslog(LOG_NOTICE, "ARCRON: unit %d: sending resync command", unit);
1287		send_slow(up, pp->io.fd, "h\r");
1288
1289		/* Schedule our next resync... */
1290		up->next_resync = current_time + DEFAULT_RESYNC_TIME;
1291
1292		/* Drop through to request time if appropriate. */
1293	}
1294
1295	/* If clock quality is too poor to trust, indicate a fault. */
1296	/* If quality is QUALITY_UNKNOWN and ARCRON_KEEN is defined,*/
1297	/* we'll cross our fingers and just hope that the thing     */
1298	/* synced so quickly we did not catch it---we'll            */
1299	/* double-check the clock is OK elsewhere.                  */
1300	if(
1301#ifdef ARCRON_KEEN
1302		(up->quality != QUALITY_UNKNOWN) &&
1303#else
1304		(up->quality == QUALITY_UNKNOWN) ||
1305#endif
1306		(up->quality < MIN_CLOCK_QUALITY_OK)) {
1307#ifdef DEBUG
1308		if(debug) {
1309			printf("arc: clock quality %d too poor.\n", up->quality);
1310		}
1311#endif
1312		refclock_report(peer, CEVNT_FAULT);
1313		return;
1314	}
1315	/* This is the normal case: request a timestamp. */
1316	request_time(unit, peer);
1317}
1318
1319#else
1320int refclock_arc_bs;
1321#endif
1322