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