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