1 /* 2 ** refclock_datum - clock driver for the Datum Programmable Time Server 3 ** 4 ** Important note: This driver assumes that you have termios. If you have 5 ** a system that does not have termios, you will have to modify this driver. 6 ** 7 ** Sorry, I have only tested this driver on SUN and HP platforms. 8 */ 9 10 #ifdef HAVE_CONFIG_H 11 # include <config.h> 12 #endif 13 14 #if defined(REFCLOCK) && defined(CLOCK_DATUM) 15 16 /* 17 ** Include Files 18 */ 19 20 #include "ntpd.h" 21 #include "ntp_io.h" 22 #include "ntp_refclock.h" 23 #include "ntp_unixtime.h" 24 #include "ntp_stdlib.h" 25 26 #include <stdio.h> 27 #include <ctype.h> 28 29 #if defined(HAVE_BSD_TTYS) 30 #include <sgtty.h> 31 #endif /* HAVE_BSD_TTYS */ 32 33 #if defined(HAVE_SYSV_TTYS) 34 #include <termio.h> 35 #endif /* HAVE_SYSV_TTYS */ 36 37 #if defined(HAVE_TERMIOS) 38 #include <termios.h> 39 #endif 40 #if defined(STREAM) 41 #include <stropts.h> 42 #if defined(WWVBCLK) 43 #include <sys/clkdefs.h> 44 #endif /* WWVBCLK */ 45 #endif /* STREAM */ 46 47 #include "ntp_stdlib.h" 48 49 /* 50 ** This driver supports the Datum Programmable Time System (PTS) clock. 51 ** The clock works in very straight forward manner. When it receives a 52 ** time code request (e.g., the ascii string "//k/mn"), it responds with 53 ** a seven byte BCD time code. This clock only responds with a 54 ** time code after it first receives the "//k/mn" message. It does not 55 ** periodically send time codes back at some rate once it is started. 56 ** the returned time code can be broken down into the following fields. 57 ** 58 ** _______________________________ 59 ** Bit Index | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | 60 ** =============================== 61 ** byte 0: | - - - - | H D | 62 ** =============================== 63 ** byte 1: | T D | U D | 64 ** =============================== 65 ** byte 2: | - - | T H | U H | 66 ** =============================== 67 ** byte 3: | - | T M | U M | 68 ** =============================== 69 ** byte 4: | - | T S | U S | 70 ** =============================== 71 ** byte 5: | t S | h S | 72 ** =============================== 73 ** byte 6: | m S | - - - - | 74 ** =============================== 75 ** 76 ** In the table above: 77 ** 78 ** "-" means don't care 79 ** "H D", "T D", and "U D" means Hundreds, Tens, and Units of Days 80 ** "T H", and "UH" means Tens and Units of Hours 81 ** "T M", and "U M" means Tens and Units of Minutes 82 ** "T S", and "U S" means Tens and Units of Seconds 83 ** "t S", "h S", and "m S" means tenths, hundredths, and thousandths 84 ** of seconds 85 ** 86 ** The Datum PTS communicates throught the RS232 port on your machine. 87 ** Right now, it assumes that you have termios. This driver has been tested 88 ** on SUN and HP workstations. The Datum PTS supports various IRIG and 89 ** NASA input codes. This driver assumes that the name of the device is 90 ** /dev/datum. You will need to make a soft link to your RS232 device or 91 ** create a new driver to use this refclock. 92 */ 93 94 /* 95 ** Datum PTS defines 96 */ 97 98 /* 99 ** Note that if GMT is defined, then the Datum PTS must use Greenwich 100 ** time. Otherwise, this driver allows the Datum PTS to use the current 101 ** wall clock for its time. It determines the time zone offset by minimizing 102 ** the error after trying several time zone offsets. If the Datum PTS 103 ** time is Greenwich time and GMT is not defined, everything should still 104 ** work since the time zone will be found to be 0. What this really means 105 ** is that your system time (at least to start with) must be within the 106 ** correct time by less than +- 30 minutes. The default is for GMT to not 107 ** defined. If you really want to force GMT without the funny +- 30 minute 108 ** stuff then you must define (uncomment) GMT below. 109 */ 110 111 /* 112 #define GMT 113 #define DEBUG_DATUM_PTC 114 #define LOG_TIME_ERRORS 115 */ 116 117 118 #define PRECISION (-10) /* precision assumed 1/1024 ms */ 119 #define REFID "DATM" /* reference id */ 120 #define DATUM_DISPERSION 0 /* fixed dispersion = 0 ms */ 121 #define DATUM_MAX_ERROR 0.100 /* limits on sigma squared */ 122 #define DATUM_DEV "/dev/datum" /* device name */ 123 124 #define DATUM_MAX_ERROR2 (DATUM_MAX_ERROR*DATUM_MAX_ERROR) 125 126 /* 127 ** The Datum PTS structure 128 */ 129 130 /* 131 ** I don't use a fixed array of MAXUNITS like everyone else just because 132 ** I don't like to program that way. Sorry if this bothers anyone. I assume 133 ** that you can use any id for your unit and I will search for it in a 134 ** dynamic array of units until I find it. I was worried that users might 135 ** enter a bad id in their configuration file (larger than MAXUNITS) and 136 ** besides, it is just cleaner not to have to assume that you have a fixed 137 ** number of anything in a program. 138 */ 139 140 struct datum_pts_unit { 141 struct peer *peer; /* peer used by ntp */ 142 struct refclockio io; /* io structure used by ntp */ 143 int PTS_fd; /* file descriptor for PTS */ 144 u_int unit; /* id for unit */ 145 u_long timestarted; /* time started */ 146 l_fp lastrec; /* time tag for the receive time (system) */ 147 l_fp lastref; /* reference time (Datum time) */ 148 u_long yearstart; /* the year that this clock started */ 149 int coderecv; /* number of time codes received */ 150 int day; /* day */ 151 int hour; /* hour */ 152 int minute; /* minutes */ 153 int second; /* seconds */ 154 int msec; /* miliseconds */ 155 int usec; /* miliseconds */ 156 u_char leap; /* funny leap character code */ 157 char retbuf[8]; /* returned time from the datum pts */ 158 char nbytes; /* number of bytes received from datum pts */ 159 double sigma2; /* average squared error (roughly) */ 160 int tzoff; /* time zone offest from GMT */ 161 }; 162 163 /* 164 ** PTS static constant variables for internal use 165 */ 166 167 static char TIME_REQUEST[6]; /* request message sent to datum for time */ 168 static int nunits; /* number of active units */ 169 static struct datum_pts_unit 170 **datum_pts_unit; /* dynamic array of datum PTS structures */ 171 172 /* 173 ** Callback function prototypes that ntpd needs to know about. 174 */ 175 176 static int datum_pts_start P((int, struct peer *)); 177 static void datum_pts_shutdown P((int, struct peer *)); 178 static void datum_pts_poll P((int, struct peer *)); 179 static void datum_pts_control P((int, struct refclockstat *, 180 struct refclockstat *, struct peer *)); 181 static void datum_pts_init P((void)); 182 static void datum_pts_buginfo P((int, struct refclockbug *, struct peer *)); 183 184 /* 185 ** This is the call back function structure that ntpd actually uses for 186 ** this refclock. 187 */ 188 189 struct refclock refclock_datum = { 190 datum_pts_start, /* start up a new Datum refclock */ 191 datum_pts_shutdown, /* shutdown a Datum refclock */ 192 datum_pts_poll, /* sends out the time request */ 193 datum_pts_control, /* not used */ 194 datum_pts_init, /* initialization (called first) */ 195 datum_pts_buginfo, /* not used */ 196 NOFLAGS /* we are not setting any special flags */ 197 }; 198 199 /* 200 ** The datum_pts_receive callback function is handled differently from the 201 ** rest. It is passed to the ntpd io data structure. Basically, every 202 ** 64 seconds, the datum_pts_poll() routine is called. It sends out the time 203 ** request message to the Datum Programmable Time System. Then, ntpd 204 ** waits on a select() call to receive data back. The datum_pts_receive() 205 ** function is called as data comes back. We expect a seven byte time 206 ** code to be returned but the datum_pts_receive() function may only get 207 ** a few bytes passed to it at a time. In other words, this routine may 208 ** get called by the io stuff in ntpd a few times before we get all seven 209 ** bytes. Once the last byte is received, we process it and then pass the 210 ** new time measurement to ntpd for updating the system time. For now, 211 ** there is no 3 state filtering done on the time measurements. The 212 ** jitter may be a little high but at least for its current use, it is not 213 ** a problem. We have tried to keep things as simple as possible. This 214 ** clock should not jitter more than 1 or 2 mseconds at the most once 215 ** things settle down. It is important to get the right drift calibrated 216 ** in the ntpd.drift file as well as getting the right tick set up right 217 ** using tickadj for SUNs. Tickadj is not used for the HP but you need to 218 ** remember to bring up the adjtime daemon because HP does not support 219 ** the adjtime() call. 220 */ 221 222 static void datum_pts_receive P((struct recvbuf *)); 223 224 /*......................................................................*/ 225 /* datum_pts_start - start up the datum PTS. This means open the */ 226 /* RS232 device and set up the data structure for my unit. */ 227 /*......................................................................*/ 228 229 static int 230 datum_pts_start( 231 int unit, 232 struct peer *peer 233 ) 234 { 235 struct datum_pts_unit **temp_datum_pts_unit; 236 struct datum_pts_unit *datum_pts; 237 int fd; 238 #ifdef HAVE_TERMIOS 239 struct termios arg; 240 #endif 241 242 #ifdef DEBUG_DATUM_PTC 243 if (debug) 244 printf("Starting Datum PTS unit %d\n", unit); 245 #endif 246 247 /* 248 ** Open the Datum PTS device 249 */ 250 fd = open(DATUM_DEV, O_RDWR); 251 252 if (fd < 0) { 253 msyslog(LOG_ERR, "Datum_PTS: open(\"%s\", O_RDWR) failed: %m", DATUM_DEV); 254 return 0; 255 } 256 257 /* 258 ** Create the memory for the new unit 259 */ 260 261 temp_datum_pts_unit = (struct datum_pts_unit **) 262 malloc((nunits+1)*sizeof(struct datum_pts_unit *)); 263 if (nunits > 0) memcpy(temp_datum_pts_unit, datum_pts_unit, 264 nunits*sizeof(struct datum_pts_unit *)); 265 free(datum_pts_unit); 266 datum_pts_unit = temp_datum_pts_unit; 267 datum_pts_unit[nunits] = (struct datum_pts_unit *) 268 malloc(sizeof(struct datum_pts_unit)); 269 datum_pts = datum_pts_unit[nunits]; 270 271 datum_pts->unit = unit; /* set my unit id */ 272 datum_pts->yearstart = 0; /* initialize the yearstart to 0 */ 273 datum_pts->sigma2 = 0.0; /* initialize the sigma2 to 0 */ 274 275 datum_pts->PTS_fd = fd; 276 277 fcntl(datum_pts->PTS_fd, F_SETFL, 0); /* clear the descriptor flags */ 278 279 #ifdef DEBUG_DATUM_PTC 280 if (debug) 281 printf("Opening RS232 port with file descriptor %d\n", 282 datum_pts->PTS_fd); 283 #endif 284 285 /* 286 ** Set up the RS232 terminal device information. Note that we assume that 287 ** we have termios. This code has only been tested on SUNs and HPs. If your 288 ** machine does not have termios this driver cannot be initialized. You can change this 289 ** if you want by editing this source. Please give the changes back to the 290 ** ntp folks so that it can become part of their regular distribution. 291 */ 292 293 #ifdef HAVE_TERMIOS 294 295 arg.c_iflag = IGNBRK; 296 arg.c_oflag = 0; 297 arg.c_cflag = B9600 | CS8 | CREAD | PARENB | CLOCAL; 298 arg.c_lflag = 0; 299 arg.c_cc[VMIN] = 0; /* start timeout timer right away (not used) */ 300 arg.c_cc[VTIME] = 30; /* 3 second timout on reads (not used) */ 301 302 tcsetattr(datum_pts->PTS_fd, TCSANOW, &arg); 303 304 #else 305 306 msyslog(LOG_ERR, "Datum_PTS: Termios not supported in this driver"); 307 (void)close(datum_pts->PTS_fd); 308 309 peer->precision = PRECISION; 310 pp->clockdesc = DESCRIPTION; 311 memcpy((char *)&pp->refid, REFID, 4); 312 313 return 0; 314 315 #endif 316 317 /* 318 ** Initialize the ntpd IO structure 319 */ 320 321 datum_pts->peer = peer; 322 datum_pts->io.clock_recv = datum_pts_receive; 323 datum_pts->io.srcclock = (caddr_t)datum_pts; 324 datum_pts->io.datalen = 0; 325 datum_pts->io.fd = datum_pts->PTS_fd; 326 327 if (!io_addclock(&(datum_pts->io))) { 328 329 #ifdef DEBUG_DATUM_PTC 330 if (debug) 331 printf("Problem adding clock\n"); 332 #endif 333 334 msyslog(LOG_ERR, "Datum_PTS: Problem adding clock"); 335 (void)close(datum_pts->PTS_fd); 336 337 return 0; 338 } 339 340 /* 341 ** Now add one to the number of units and return a successful code 342 */ 343 344 nunits++; 345 return 1; 346 347 } 348 349 350 /*......................................................................*/ 351 /* datum_pts_shutdown - this routine shuts doen the device and */ 352 /* removes the memory for the unit. */ 353 /*......................................................................*/ 354 355 static void 356 datum_pts_shutdown( 357 int unit, 358 struct peer *peer 359 ) 360 { 361 int i,j; 362 struct datum_pts_unit **temp_datum_pts_unit; 363 364 #ifdef DEBUG_DATUM_PTC 365 if (debug) 366 printf("Shutdown Datum PTS\n"); 367 #endif 368 369 msyslog(LOG_ERR, "Datum_PTS: Shutdown Datum PTS"); 370 371 /* 372 ** First we have to find the right unit (i.e., the one with the same id). 373 ** We do this by looping through the dynamic array of units intil we find 374 ** it. Note, that I don't simply use an array with a maximimum number of 375 ** Datum PTS units. Everything is completely dynamic. 376 */ 377 378 for (i=0; i<nunits; i++) { 379 if (datum_pts_unit[i]->unit == unit) { 380 381 /* 382 ** We found the unit so close the file descriptor and free up the memory used 383 ** by the structure. 384 */ 385 386 io_closeclock(&datum_pts_unit[i]->io); 387 close(datum_pts_unit[i]->PTS_fd); 388 free(datum_pts_unit[i]); 389 390 /* 391 ** Now clean up the datum_pts_unit dynamic array so that there are no holes. 392 ** This may mean moving pointers around, etc., to keep things compact. 393 */ 394 395 if (nunits > 1) { 396 397 temp_datum_pts_unit = (struct datum_pts_unit **) 398 malloc((nunits-1)*sizeof(struct datum_pts_unit *)); 399 if (i!= 0) memcpy(temp_datum_pts_unit, datum_pts_unit, 400 i*sizeof(struct datum_pts_unit *)); 401 402 for (j=i+1; j<nunits; j++) { 403 temp_datum_pts_unit[j-1] = datum_pts_unit[j]; 404 } 405 406 free(datum_pts_unit); 407 datum_pts_unit = temp_datum_pts_unit; 408 409 }else{ 410 411 free(datum_pts_unit); 412 datum_pts_unit = NULL; 413 414 } 415 416 return; 417 418 } 419 } 420 421 #ifdef DEBUG_DATUM_PTC 422 if (debug) 423 printf("Error, could not shut down unit %d\n",unit); 424 #endif 425 426 msyslog(LOG_ERR, "Datum_PTS: Could not shut down Datum PTS unit %d",unit); 427 428 } 429 430 /*......................................................................*/ 431 /* datum_pts_poll - this routine sends out the time request to the */ 432 /* Datum PTS device. The time will be passed back in the */ 433 /* datum_pts_receive() routine. */ 434 /*......................................................................*/ 435 436 static void 437 datum_pts_poll( 438 int unit, 439 struct peer *peer 440 ) 441 { 442 int i; 443 int unit_index; 444 int error_code; 445 struct datum_pts_unit *datum_pts; 446 447 #ifdef DEBUG_DATUM_PTC 448 if (debug) 449 printf("Poll Datum PTS\n"); 450 #endif 451 452 /* 453 ** Find the right unit and send out a time request once it is found. 454 */ 455 456 unit_index = -1; 457 for (i=0; i<nunits; i++) { 458 if (datum_pts_unit[i]->unit == unit) { 459 unit_index = i; 460 datum_pts = datum_pts_unit[i]; 461 error_code = write(datum_pts->PTS_fd, TIME_REQUEST, 6); 462 if (error_code != 6) perror("TIME_REQUEST"); 463 datum_pts->nbytes = 0; 464 break; 465 } 466 } 467 468 /* 469 ** Print out an error message if we could not find the right unit. 470 */ 471 472 if (unit_index == -1) { 473 474 #ifdef DEBUG_DATUM_PTC 475 if (debug) 476 printf("Error, could not poll unit %d\n",unit); 477 #endif 478 479 msyslog(LOG_ERR, "Datum_PTS: Could not poll unit %d",unit); 480 return; 481 482 } 483 484 } 485 486 487 /*......................................................................*/ 488 /* datum_pts_control - not used */ 489 /*......................................................................*/ 490 491 static void 492 datum_pts_control( 493 int unit, 494 struct refclockstat *in, 495 struct refclockstat *out, 496 struct peer *peer 497 ) 498 { 499 500 #ifdef DEBUG_DATUM_PTC 501 if (debug) 502 printf("Control Datum PTS\n"); 503 #endif 504 505 } 506 507 508 /*......................................................................*/ 509 /* datum_pts_init - initializes things for all possible Datum */ 510 /* time code generators that might be used. In practice, this is */ 511 /* only called once at the beginning before anything else is */ 512 /* called. */ 513 /*......................................................................*/ 514 515 static void 516 datum_pts_init(void) 517 { 518 519 /* */ 520 /*...... open up the log file if we are debugging ......................*/ 521 /* */ 522 523 /* 524 ** Open up the log file if we are debugging. For now, send data out to the 525 ** screen (stdout). 526 */ 527 528 #ifdef DEBUG_DATUM_PTC 529 if (debug) 530 printf("Init Datum PTS\n"); 531 #endif 532 533 /* 534 ** Initialize the time request command string. This is the only message 535 ** that we ever have to send to the Datum PTS (although others are defined). 536 */ 537 538 memcpy(TIME_REQUEST, "//k/mn",6); 539 540 /* 541 ** Initialize the number of units to 0 and set the dynamic array of units to 542 ** NULL since there are no units defined yet. 543 */ 544 545 datum_pts_unit = NULL; 546 nunits = 0; 547 548 } 549 550 551 /*......................................................................*/ 552 /* datum_pts_buginfo - not used */ 553 /*......................................................................*/ 554 555 static void 556 datum_pts_buginfo( 557 int unit, 558 register struct refclockbug *bug, 559 register struct peer *peer 560 ) 561 { 562 563 #ifdef DEBUG_DATUM_PTC 564 if (debug) 565 printf("Buginfo Datum PTS\n"); 566 #endif 567 568 } 569 570 571 /*......................................................................*/ 572 /* datum_pts_receive - receive the time buffer that was read in */ 573 /* by the ntpd io handling routines. When 7 bytes have been */ 574 /* received (it may take several tries before all 7 bytes are */ 575 /* received), then the time code must be unpacked and sent to */ 576 /* the ntpd clock_receive() routine which causes the systems */ 577 /* clock to be updated (several layers down). */ 578 /*......................................................................*/ 579 580 static void 581 datum_pts_receive( 582 struct recvbuf *rbufp 583 ) 584 { 585 int i; 586 l_fp tstmp; 587 struct datum_pts_unit *datum_pts; 588 char *dpt; 589 int dpend; 590 int tzoff; 591 int timerr; 592 double ftimerr, abserr; 593 #ifdef DEBUG_DATUM_PTC 594 double dispersion; 595 #endif 596 int goodtime; 597 /*double doffset;*/ 598 599 /* 600 ** Get the time code (maybe partial) message out of the rbufp buffer. 601 */ 602 603 datum_pts = (struct datum_pts_unit *)rbufp->recv_srcclock; 604 dpt = (char *)&rbufp->recv_space; 605 dpend = rbufp->recv_length; 606 607 #ifdef DEBUG_DATUM_PTC 608 if (debug) 609 printf("Receive Datum PTS: %d bytes\n", dpend); 610 #endif 611 612 /* */ 613 /*...... save the ntp system time when the first byte is received ......*/ 614 /* */ 615 616 /* 617 ** Save the ntp system time when the first byte is received. Note that 618 ** because it may take several calls to this routine before all seven 619 ** bytes of our return message are finally received by the io handlers in 620 ** ntpd, we really do want to use the time tag when the first byte is 621 ** received to reduce the jitter. 622 */ 623 624 if (datum_pts->nbytes == 0) { 625 datum_pts->lastrec = rbufp->recv_time; 626 } 627 628 /* 629 ** Increment our count to the number of bytes received so far. Return if we 630 ** haven't gotten all seven bytes yet. 631 */ 632 633 for (i=0; i<dpend; i++) { 634 datum_pts->retbuf[datum_pts->nbytes+i] = dpt[i]; 635 } 636 637 datum_pts->nbytes += dpend; 638 639 if (datum_pts->nbytes != 7) { 640 return; 641 } 642 643 /* 644 ** Convert the seven bytes received in our time buffer to day, hour, minute, 645 ** second, and msecond values. The usec value is not used for anything 646 ** currently. It is just the fractional part of the time stored in units 647 ** of microseconds. 648 */ 649 650 datum_pts->day = 100*(datum_pts->retbuf[0] & 0x0f) + 651 10*((datum_pts->retbuf[1] & 0xf0)>>4) + 652 (datum_pts->retbuf[1] & 0x0f); 653 654 datum_pts->hour = 10*((datum_pts->retbuf[2] & 0x30)>>4) + 655 (datum_pts->retbuf[2] & 0x0f); 656 657 datum_pts->minute = 10*((datum_pts->retbuf[3] & 0x70)>>4) + 658 (datum_pts->retbuf[3] & 0x0f); 659 660 datum_pts->second = 10*((datum_pts->retbuf[4] & 0x70)>>4) + 661 (datum_pts->retbuf[4] & 0x0f); 662 663 datum_pts->msec = 100*((datum_pts->retbuf[5] & 0xf0) >> 4) + 664 10*(datum_pts->retbuf[5] & 0x0f) + 665 ((datum_pts->retbuf[6] & 0xf0)>>4); 666 667 datum_pts->usec = 1000*datum_pts->msec; 668 669 #ifdef DEBUG_DATUM_PTC 670 if (debug) 671 printf("day %d, hour %d, minute %d, second %d, msec %d\n", 672 datum_pts->day, 673 datum_pts->hour, 674 datum_pts->minute, 675 datum_pts->second, 676 datum_pts->msec); 677 #endif 678 679 /* 680 ** Get the GMT time zone offset. Note that GMT should be zero if the Datum 681 ** reference time is using GMT as its time base. Otherwise we have to 682 ** determine the offset if the Datum PTS is using time of day as its time 683 ** base. 684 */ 685 686 goodtime = 0; /* We are not sure about the time and offset yet */ 687 688 #ifdef GMT 689 690 /* 691 ** This is the case where the Datum PTS is using GMT so there is no time 692 ** zone offset. 693 */ 694 695 tzoff = 0; /* set time zone offset to 0 */ 696 697 #else 698 699 /* 700 ** This is the case where the Datum PTS is using regular time of day for its 701 ** time so we must compute the time zone offset. The way we do it is kind of 702 ** funny but it works. We loop through different time zones (0 to 24) and 703 ** pick the one that gives the smallest error (+- one half hour). The time 704 ** zone offset is stored in the datum_pts structure for future use. Normally, 705 ** the clocktime() routine is only called once (unless the time zone offset 706 ** changes due to daylight savings) since the goodtime flag is set when a 707 ** good time is found (with a good offset). Note that even if the Datum 708 ** PTS is using GMT, this mechanism will still work since it should come up 709 ** with a value for tzoff = 0 (assuming that your system clock is within 710 ** a half hour of the Datum time (even with time zone differences). 711 */ 712 713 for (tzoff=0; tzoff<24; tzoff++) { 714 if (clocktime( datum_pts->day, 715 datum_pts->hour, 716 datum_pts->minute, 717 datum_pts->second, 718 (tzoff + datum_pts->tzoff) % 24, 719 datum_pts->lastrec.l_ui, 720 &datum_pts->yearstart, 721 &datum_pts->lastref.l_ui) ) { 722 723 datum_pts->lastref.l_uf = 0; 724 error = datum_pts->lastref.l_ui - datum_pts->lastrec.l_ui; 725 726 #ifdef DEBUG_DATUM_PTC 727 printf("Time Zone (clocktime method) = %d, error = %d\n", tzoff, error); 728 #endif 729 730 if ((error < 1799) && (error > -1799)) { 731 tzoff = (tzoff + datum_pts->tzoff) % 24; 732 datum_pts->tzoff = tzoff; 733 goodtime = 1; 734 735 #ifdef DEBUG_DATUM_PTC 736 printf("Time Zone found (clocktime method) = %d\n",tzoff); 737 #endif 738 739 break; 740 } 741 742 } 743 } 744 745 #endif 746 747 /* 748 ** Make sure that we have a good time from the Datum PTS. Clocktime() also 749 ** sets yearstart and lastref.l_ui. We will have to set astref.l_uf (i.e., 750 ** the fraction of a second) stuff later. 751 */ 752 753 if (!goodtime) { 754 755 if (!clocktime( datum_pts->day, 756 datum_pts->hour, 757 datum_pts->minute, 758 datum_pts->second, 759 tzoff, 760 datum_pts->lastrec.l_ui, 761 &datum_pts->yearstart, 762 &datum_pts->lastref.l_ui) ) { 763 764 #ifdef DEBUG_DATUM_PTC 765 if (debug) 766 { 767 printf("Error: bad clocktime\n"); 768 printf("GMT %d, lastrec %d, yearstart %d, lastref %d\n", 769 tzoff, 770 datum_pts->lastrec.l_ui, 771 datum_pts->yearstart, 772 datum_pts->lastref.l_ui); 773 } 774 #endif 775 776 msyslog(LOG_ERR, "Datum_PTS: Bad clocktime"); 777 778 return; 779 780 }else{ 781 782 #ifdef DEBUG_DATUM_PTC 783 if (debug) 784 printf("Good clocktime\n"); 785 #endif 786 787 } 788 789 } 790 791 /* 792 ** We have datum_pts->lastref.l_ui set (which is the integer part of the 793 ** time. Now set the microseconds field. 794 */ 795 796 TVUTOTSF(datum_pts->usec, datum_pts->lastref.l_uf); 797 798 /* 799 ** Compute the time correction as the difference between the reference 800 ** time (i.e., the Datum time) minus the receive time (system time). 801 */ 802 803 tstmp = datum_pts->lastref; /* tstmp is the datum ntp time */ 804 L_SUB(&tstmp, &datum_pts->lastrec); /* tstmp is now the correction */ 805 datum_pts->coderecv++; /* increment a counter */ 806 807 #ifdef DEBUG_DATUM_PTC 808 dispersion = DATUM_DISPERSION; /* set the dispersion to 0 */ 809 ftimerr = dispersion; 810 ftimerr /= (1024.0 * 64.0); 811 if (debug) 812 printf("dispersion = %d, %f\n", dispersion, ftimerr); 813 #endif 814 815 /* 816 ** Pass the new time to ntpd through the refclock_receive function. Note 817 ** that we are not trying to make any corrections due to the time it takes 818 ** for the Datum PTS to send the message back. I am (erroneously) assuming 819 ** that the time for the Datum PTS to send the time back to us is negligable. 820 ** I suspect that this time delay may be as much as 15 ms or so (but probably 821 ** less). For our needs at JPL, this kind of error is ok so it is not 822 ** necessary to use fudge factors in the ntp.conf file. Maybe later we will. 823 */ 824 /*LFPTOD(&tstmp, doffset);*/ 825 datum_pts->lastref = datum_pts->lastrec; 826 refclock_receive(datum_pts->peer); 827 828 /* 829 ** Compute sigma squared (not used currently). Maybe later, this could be 830 ** used for the dispersion estimate. The problem is that ntpd does not link 831 ** in the math library so sqrt() is not available. Anyway, this is useful 832 ** for debugging. Maybe later I will just use absolute values for the time 833 ** error to come up with my dispersion estimate. Anyway, for now my dispersion 834 ** is set to 0. 835 */ 836 837 timerr = tstmp.l_ui<<20; 838 timerr |= (tstmp.l_uf>>12) & 0x000fffff; 839 ftimerr = timerr; 840 ftimerr /= 1024*1024; 841 abserr = ftimerr; 842 if (ftimerr < 0.0) abserr = -ftimerr; 843 844 if (datum_pts->sigma2 == 0.0) { 845 if (abserr < DATUM_MAX_ERROR) { 846 datum_pts->sigma2 = abserr*abserr; 847 }else{ 848 datum_pts->sigma2 = DATUM_MAX_ERROR2; 849 } 850 }else{ 851 if (abserr < DATUM_MAX_ERROR) { 852 datum_pts->sigma2 = 0.95*datum_pts->sigma2 + 0.05*abserr*abserr; 853 }else{ 854 datum_pts->sigma2 = 0.95*datum_pts->sigma2 + 0.05*DATUM_MAX_ERROR2; 855 } 856 } 857 858 #ifdef DEBUG_DATUM_PTC 859 if (debug) 860 printf("Time error = %f seconds\n", ftimerr); 861 #endif 862 863 #if defined(DEBUG_DATUM_PTC) || defined(LOG_TIME_ERRORS) 864 if (debug) 865 printf("PTS: day %d, hour %d, minute %d, second %d, msec %d, Time Error %f\n", 866 datum_pts->day, 867 datum_pts->hour, 868 datum_pts->minute, 869 datum_pts->second, 870 datum_pts->msec, 871 ftimerr); 872 #endif 873 874 } 875 #else 876 int refclock_datum_bs; 877 #endif /* REFCLOCK */ 878