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