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