xref: /freebsd/contrib/ntp/ntpd/refclock_arc.c (revision 1669d8afc64812c8d2d1d147ae1fd42ff441e1b1)
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
1530