/contrib/ntp/ntpd/refclock_datum.c
C | 877 lines | 425 code | 168 blank | 284 comment | 51 complexity | 9e0de6bb2668e65794a9722f23533ea2 MD5 | raw file
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 140struct 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 167static char TIME_REQUEST[6]; /* request message sent to datum for time */ 168static int nunits; /* number of active units */ 169static 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 176static int datum_pts_start P((int, struct peer *)); 177static void datum_pts_shutdown P((int, struct peer *)); 178static void datum_pts_poll P((int, struct peer *)); 179static void datum_pts_control P((int, struct refclockstat *, 180 struct refclockstat *, struct peer *)); 181static void datum_pts_init P((void)); 182static 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 189struct 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 222static 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 229static int 230datum_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 355static void 356datum_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 436static void 437datum_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 491static void 492datum_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 515static void 516datum_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 555static void 556datum_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 580static void 581datum_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 876int refclock_datum_bs; 877#endif /* REFCLOCK */