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