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