source: trunk/third/xntp/xntpd/refclock_arc.c @ 10832

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