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