1 /******************************************************************************* 2 * 3 * Module : refclock_tsyncpci.c 4 * Date : 09/08/08 5 * Purpose : Implements a reference clock driver for the NTP daemon. This 6 * reference clock driver provides a means to communicate with 7 * the Spectracom TSYNC PCI timing devices and use them as a time 8 * source. 9 * 10 * (C) Copyright 2008 Spectracom Corporation 11 * 12 * This software is provided by Spectracom Corporation 'as is' and 13 * any express or implied warranties, including, but not limited to, the 14 * implied warranties of merchantability and fitness for a particular purpose 15 * are disclaimed. In no event shall Spectracom Corporation be liable 16 * for any direct, indirect, incidental, special, exemplary, or consequential 17 * damages (including, but not limited to, procurement of substitute goods 18 * or services; loss of use, data, or profits; or business interruption) 19 * however caused and on any theory of liability, whether in contract, strict 20 * liability, or tort (including negligence or otherwise) arising in any way 21 * out of the use of this software, even if advised of the possibility of 22 * such damage. 23 * 24 * This software is released for distribution according to the NTP copyright 25 * and license contained in html/copyright.html of NTP source. 26 * 27 *******************************************************************************/ 28 #ifdef HAVE_CONFIG_H 29 #include <config.h> 30 #endif 31 32 #if defined(REFCLOCK) && defined(CLOCK_TSYNCPCI) 33 34 #include <asm/ioctl.h> 35 #ifdef HAVE_SYS_IOCTL_H 36 # include <sys/ioctl.h> 37 #endif 38 39 #include <stdio.h> 40 #include <ctype.h> 41 #include <netinet/in.h> 42 43 44 #include "ntpd.h" 45 #include "ntp_io.h" 46 #include "ntp_refclock.h" 47 #include "ntp_unixtime.h" 48 #include "ntp_stdlib.h" 49 #include "ntp_calendar.h" 50 51 52 /******************************************************************************* 53 ** 54 ** This driver supports the Spectracom TSYNC PCI GPS receiver. It requires 55 ** that the tsyncpci.o device driver be installed and loaded. 56 ** 57 *******************************************************************************/ 58 59 #define TSYNC_PCI_REVISION "1.11" 60 61 /* 62 ** TPRO interface definitions 63 */ 64 #define DEVICE "/dev/tsyncpci" /* device name */ 65 #define PRECISION (-20) /* precision assumed (1 us) */ 66 #define DESCRIPTION "Spectracom TSYNC-PCI" /* WRU */ 67 68 #define SECONDS_1900_TO_1970 (2208988800U) 69 70 #define TSYNC_REF_IID (0x2500) // SS CAI, REF IID 71 #define TSYNC_REF_DEST_ID (0x0001) // KTS Firmware 72 #define TSYNC_REF_IN_PYLD_OFF (0) 73 #define TSYNC_REF_IN_LEN (0) 74 #define TSYNC_REF_OUT_PYLD_OFF (0) 75 #define TSYNC_REF_OUT_LEN (8) 76 #define TSYNC_REF_MAX_OUT_LEN (16) 77 #define TSYNC_REF_PYLD_LEN (TSYNC_REF_IN_LEN + \ 78 TSYNC_REF_MAX_OUT_LEN) 79 #define TSYNC_REF_LEN (4) 80 #define TSYNC_REF_LOCAL ("LOCL") 81 82 #define TSYNC_TMSCL_IID (0x2301) // CS CAI, TIMESCALE IID 83 #define TSYNC_TMSCL_DEST_ID (0x0001) // KTS Firmware 84 #define TSYNC_TMSCL_IN_PYLD_OFF (0) 85 #define TSYNC_TMSCL_IN_LEN (0) 86 #define TSYNC_TMSCL_OUT_PYLD_OFF (0) 87 #define TSYNC_TMSCL_OUT_LEN (4) 88 #define TSYNC_TMSCL_MAX_OUT_LEN (12) 89 #define TSYNC_TMSCL_PYLD_LEN (TSYNC_TMSCL_IN_LEN + \ 90 TSYNC_TMSCL_MAX_OUT_LEN) 91 92 #define TSYNC_LEAP_IID (0x2307) // CS CAI, LEAP SEC IID 93 #define TSYNC_LEAP_DEST_ID (0x0001) // KTS Firmware 94 #define TSYNC_LEAP_IN_PYLD_OFF (0) 95 #define TSYNC_LEAP_IN_LEN (0) 96 #define TSYNC_LEAP_OUT_PYLD_OFF (0) 97 #define TSYNC_LEAP_OUT_LEN (28) 98 #define TSYNC_LEAP_MAX_OUT_LEN (36) 99 #define TSYNC_LEAP_PYLD_LEN (TSYNC_LEAP_IN_LEN + \ 100 TSYNC_LEAP_MAX_OUT_LEN) 101 102 // These define the base date/time of the system clock. The system time will 103 // be tracked as the number of seconds from this date/time. 104 #define TSYNC_TIME_BASE_YEAR (1970) // earliest acceptable year 105 106 #define TSYNC_LCL_STRATUM (0) 107 108 /* 109 ** TSYNC Time Scales type 110 */ 111 typedef enum 112 { 113 TIME_SCALE_UTC = 0, // Universal Coordinated Time 114 TIME_SCALE_TAI = 1, // International Atomic Time 115 TIME_SCALE_GPS = 2, // Global Positioning System 116 TIME_SCALE_LOCAL = 3, // UTC w/local rules for time zone and DST 117 NUM_TIME_SCALES = 4, // Number of time scales 118 119 TIME_SCALE_MAX = 15 // Maximum number of timescales 120 121 } TIME_SCALE; 122 123 /* 124 ** TSYNC Board Object 125 */ 126 typedef struct BoardObj { 127 128 int file_descriptor; 129 unsigned short devid; 130 unsigned short options; 131 unsigned char firmware[5]; 132 unsigned char FPGA[5]; 133 unsigned char driver[7]; 134 135 } BoardObj; 136 137 /* 138 ** TSYNC Time Object 139 */ 140 typedef struct TimeObj { 141 142 unsigned char syncOption; /* -M option */ 143 unsigned int secsDouble; /* seconds floating pt */ 144 unsigned char seconds; /* seconds whole num */ 145 unsigned char minutes; 146 unsigned char hours; 147 unsigned short days; 148 unsigned short year; 149 unsigned short flags; /* bit 2 SYNC, bit 1 TCODE; all others 0 */ 150 151 } TimeObj; 152 153 /* 154 ** NTP Time Object 155 */ 156 typedef struct NtpTimeObj { 157 158 TimeObj timeObj; 159 struct timeval tv; 160 unsigned int refId; 161 162 } NtpTimeObj; 163 /* 164 ** TSYNC Supervisor Reference Object 165 */ 166 typedef struct ReferenceObj { 167 168 char time[TSYNC_REF_LEN]; 169 char pps[TSYNC_REF_LEN]; 170 171 } ReferenceObj; 172 173 /* 174 ** TSYNC Seconds Time Object 175 */ 176 typedef struct SecTimeObj 177 { 178 unsigned int seconds; 179 unsigned int ns; 180 } 181 SecTimeObj; 182 183 /* 184 ** TSYNC DOY Time Object 185 */ 186 typedef struct DoyTimeObj 187 { 188 unsigned int year; 189 unsigned int doy; 190 unsigned int hour; 191 unsigned int minute; 192 unsigned int second; 193 unsigned int ns; 194 } 195 DoyTimeObj; 196 197 /* 198 ** TSYNC Leap Second Object 199 */ 200 typedef struct LeapSecondObj 201 { 202 int offset; 203 DoyTimeObj utcDate; 204 } 205 LeapSecondObj; 206 207 /* 208 * structures for ioctl interactions with driver 209 */ 210 #define DI_PAYLOADS_STARTER_LENGTH 4 211 typedef struct ioctl_trans_di { 212 213 // input parameters 214 uint16_t dest; 215 uint16_t iid; 216 217 uint32_t inPayloadOffset; 218 uint32_t inLength; 219 uint32_t outPayloadOffset; 220 uint32_t maxOutLength; 221 222 // output parameters 223 uint32_t actualOutLength; 224 int32_t status; 225 226 // Input and output 227 228 // The payloads field MUST be last in ioctl_trans_di. 229 uint8_t payloads[DI_PAYLOADS_STARTER_LENGTH]; 230 231 }ioctl_trans_di; 232 233 /* 234 * structure for looking up a reference ID from a reference name 235 */ 236 typedef struct 237 { 238 const char* pRef; // KTS Reference Name 239 const char* pRefId; // NTP Reference ID 240 241 } RefIdLookup; 242 243 /* 244 * unit control structure 245 */ 246 typedef struct { 247 uint32_t refPrefer; // Reference prefer flag 248 uint32_t refId; // Host peer reference ID 249 uint8_t refStratum; // Host peer reference stratum 250 251 } TsyncUnit; 252 253 /* 254 ** Function prototypes 255 */ 256 static void tsync_poll (int unit, struct peer *); 257 static void tsync_shutdown (int, struct peer *); 258 static int tsync_start (int, struct peer *); 259 260 /* 261 ** Helper functions 262 */ 263 static void ApplyTimeOffset (DoyTimeObj* pDt, int off); 264 static void SecTimeFromDoyTime (SecTimeObj* pSt, DoyTimeObj* pDt); 265 static void DoyTimeFromSecTime (DoyTimeObj* pDt, SecTimeObj* pSt); 266 267 /* 268 ** Transfer vector 269 */ 270 struct refclock refclock_tsyncpci = { 271 tsync_start, /* start up driver */ 272 tsync_shutdown, /* shut down driver */ 273 tsync_poll, /* transmit poll message */ 274 noentry, /* not used (old tsync_control) */ 275 noentry, /* initialize driver (not used) */ 276 noentry, /* not used (old tsync_buginfo) */ 277 NOFLAGS /* not used */ 278 }; 279 280 /* 281 * Reference ID lookup table 282 */ 283 static RefIdLookup RefIdLookupTbl[] = 284 { 285 {"gps", "GPS"}, 286 {"ir", "IRIG"}, 287 {"hvq", "HVQ"}, 288 {"frq", "FREQ"}, 289 {"mdm", "ACTS"}, 290 {"epp", "PPS"}, 291 {"ptp", "PTP"}, 292 {"asc", "ATC"}, 293 {"hst0", "USER"}, 294 {"hst", TSYNC_REF_LOCAL}, 295 {"self", TSYNC_REF_LOCAL}, 296 {NULL, NULL} 297 }; 298 299 /******************************************************************************* 300 ** IOCTL DEFINITIONS 301 *******************************************************************************/ 302 #define IOCTL_TPRO_ID 't' 303 #define IOCTL_TPRO_OPEN _IOWR(IOCTL_TPRO_ID, 0, BoardObj) 304 #define IOCTL_TPRO_GET_NTP_TIME _IOWR(IOCTL_TPRO_ID, 25, NtpTimeObj) 305 #define IOCTL_TSYNC_GET _IOWR(IOCTL_TPRO_ID, 26, ioctl_trans_di) 306 307 /****************************************************************************** 308 * 309 * Function: tsync_start() 310 * Description: Used to intialize the Spectracom TSYNC reference driver. 311 * 312 * Parameters: 313 * IN: unit - not used. 314 * *peer - pointer to this reference clock's peer structure 315 * Returns: 0 - unsuccessful 316 * 1 - successful 317 * 318 *******************************************************************************/ 319 static int tsync_start(int unit, struct peer *peer) 320 { 321 struct refclockproc *pp; 322 TsyncUnit *up; 323 324 325 /* 326 ** initialize reference clock and peer parameters 327 */ 328 pp = peer->procptr; 329 pp->clockdesc = DESCRIPTION; 330 pp->io.clock_recv = noentry; 331 pp->io.srcclock = peer; 332 pp->io.datalen = 0; 333 peer->precision = PRECISION; 334 335 // Allocate and initialize unit structure 336 if (!(up = (TsyncUnit*)emalloc(sizeof(TsyncUnit)))) 337 { 338 return (0); 339 } 340 341 // Store reference preference 342 up->refPrefer = peer->flags & FLAG_PREFER; 343 344 // Initialize reference stratum level and ID 345 up->refStratum = STRATUM_UNSPEC; 346 strncpy((char *)&up->refId, TSYNC_REF_LOCAL, TSYNC_REF_LEN); 347 348 // Attach unit structure 349 pp->unitptr = (caddr_t)up; 350 351 /* Declare our refId as local in the beginning because we do not know 352 * what our actual refid is yet. 353 */ 354 strncpy((char *)&pp->refid, TSYNC_REF_LOCAL, TSYNC_REF_LEN); 355 356 return (1); 357 358 } /* End - tsync_start() */ 359 360 /******************************************************************************* 361 ** 362 ** Function: tsync_shutdown() 363 ** Description: Handles anything related to shutting down the reference clock 364 ** driver. Nothing at this point in time. 365 ** 366 ** Parameters: 367 ** IN: unit - not used. 368 ** *peer - pointer to this reference clock's peer structure 369 ** Returns: none. 370 ** 371 *******************************************************************************/ 372 static void tsync_shutdown(int unit, struct peer *peer) 373 { 374 375 } /* End - tsync_shutdown() */ 376 377 /****************************************************************************** 378 * 379 * Function: tsync_poll() 380 * Description: Retrieve time from the TSYNC device. 381 * 382 * Parameters: 383 * IN: unit - not used. 384 * *peer - pointer to this reference clock's peer structure 385 * Returns: none. 386 * 387 *******************************************************************************/ 388 static void tsync_poll(int unit, struct peer *peer) 389 { 390 char device[32]; 391 struct refclockproc *pp; 392 struct calendar jt; 393 TsyncUnit *up; 394 unsigned char synch; 395 double seconds; 396 int err; 397 int err1; 398 int err2; 399 int err3; 400 int i; 401 int j; 402 unsigned int itAllocationLength; 403 unsigned int itAllocationLength1; 404 unsigned int itAllocationLength2; 405 NtpTimeObj TimeContext; 406 BoardObj hBoard; 407 char timeRef[TSYNC_REF_LEN + 1]; 408 char ppsRef [TSYNC_REF_LEN + 1]; 409 TIME_SCALE tmscl = TIME_SCALE_UTC; 410 LeapSecondObj leapSec; 411 ioctl_trans_di *it; 412 ioctl_trans_di *it1; 413 ioctl_trans_di *it2; 414 l_fp offset; 415 l_fp ltemp; 416 ReferenceObj * pRefObj; 417 418 419 /* Construct the device name */ 420 sprintf(device, "%s%d", DEVICE, (int)peer->refclkunit); 421 422 printf("Polling device number %d...\n", (int)peer->refclkunit); 423 424 /* Open the TSYNC device */ 425 hBoard.file_descriptor = open(device, O_RDONLY | O_NDELAY, 0777); 426 427 /* If error opening TSYNC device... */ 428 if (hBoard.file_descriptor < 0) 429 { 430 msyslog(LOG_ERR, "Couldn't open device"); 431 return; 432 } 433 434 /* If error while initializing the board... */ 435 if (ioctl(hBoard.file_descriptor, IOCTL_TPRO_OPEN, &hBoard) < 0) 436 { 437 msyslog(LOG_ERR, "Couldn't initialize device"); 438 close(hBoard.file_descriptor); 439 return; 440 } 441 442 /* Allocate memory for ioctl message */ 443 itAllocationLength = 444 (sizeof(ioctl_trans_di) - DI_PAYLOADS_STARTER_LENGTH) + 445 TSYNC_REF_IN_LEN + TSYNC_REF_MAX_OUT_LEN; 446 447 it = (ioctl_trans_di*)alloca(itAllocationLength); 448 if (it == NULL) { 449 msyslog(LOG_ERR, "Couldn't allocate transaction memory - Reference"); 450 return; 451 } 452 453 /* Build SS_GetRef ioctl message */ 454 it->dest = TSYNC_REF_DEST_ID; 455 it->iid = TSYNC_REF_IID; 456 it->inPayloadOffset = TSYNC_REF_IN_PYLD_OFF; 457 it->inLength = TSYNC_REF_IN_LEN; 458 it->outPayloadOffset = TSYNC_REF_OUT_PYLD_OFF; 459 it->maxOutLength = TSYNC_REF_MAX_OUT_LEN; 460 it->actualOutLength = 0; 461 it->status = 0; 462 memset(it->payloads, 0, TSYNC_REF_MAX_OUT_LEN); 463 464 /* Read the reference from the TSYNC-PCI device */ 465 err = ioctl(hBoard.file_descriptor, 466 IOCTL_TSYNC_GET, 467 (char *)it); 468 469 /* Allocate memory for ioctl message */ 470 itAllocationLength1 = 471 (sizeof(ioctl_trans_di) - DI_PAYLOADS_STARTER_LENGTH) + 472 TSYNC_TMSCL_IN_LEN + TSYNC_TMSCL_MAX_OUT_LEN; 473 474 it1 = (ioctl_trans_di*)alloca(itAllocationLength1); 475 if (it1 == NULL) { 476 msyslog(LOG_ERR, "Couldn't allocate transaction memory - Time Scale"); 477 return; 478 } 479 480 /* Build CS_GetTimeScale ioctl message */ 481 it1->dest = TSYNC_TMSCL_DEST_ID; 482 it1->iid = TSYNC_TMSCL_IID; 483 it1->inPayloadOffset = TSYNC_TMSCL_IN_PYLD_OFF; 484 it1->inLength = TSYNC_TMSCL_IN_LEN; 485 it1->outPayloadOffset = TSYNC_TMSCL_OUT_PYLD_OFF; 486 it1->maxOutLength = TSYNC_TMSCL_MAX_OUT_LEN; 487 it1->actualOutLength = 0; 488 it1->status = 0; 489 memset(it1->payloads, 0, TSYNC_TMSCL_MAX_OUT_LEN); 490 491 /* Read the Time Scale info from the TSYNC-PCI device */ 492 err1 = ioctl(hBoard.file_descriptor, 493 IOCTL_TSYNC_GET, 494 (char *)it1); 495 496 /* Allocate memory for ioctl message */ 497 itAllocationLength2 = 498 (sizeof(ioctl_trans_di) - DI_PAYLOADS_STARTER_LENGTH) + 499 TSYNC_LEAP_IN_LEN + TSYNC_LEAP_MAX_OUT_LEN; 500 501 it2 = (ioctl_trans_di*)alloca(itAllocationLength2); 502 if (it2 == NULL) { 503 msyslog(LOG_ERR, "Couldn't allocate transaction memory - Leap Second"); 504 return; 505 } 506 507 /* Build CS_GetLeapSec ioctl message */ 508 it2->dest = TSYNC_LEAP_DEST_ID; 509 it2->iid = TSYNC_LEAP_IID; 510 it2->inPayloadOffset = TSYNC_LEAP_IN_PYLD_OFF; 511 it2->inLength = TSYNC_LEAP_IN_LEN; 512 it2->outPayloadOffset = TSYNC_LEAP_OUT_PYLD_OFF; 513 it2->maxOutLength = TSYNC_LEAP_MAX_OUT_LEN; 514 it2->actualOutLength = 0; 515 it2->status = 0; 516 memset(it2->payloads, 0, TSYNC_LEAP_MAX_OUT_LEN); 517 518 /* Read the leap seconds info from the TSYNC-PCI device */ 519 err2 = ioctl(hBoard.file_descriptor, 520 IOCTL_TSYNC_GET, 521 (char *)it2); 522 523 pp = peer->procptr; 524 up = (TsyncUnit*)pp->unitptr; 525 526 /* Read the time from the TSYNC-PCI device */ 527 err3 = ioctl(hBoard.file_descriptor, 528 IOCTL_TPRO_GET_NTP_TIME, 529 (char *)&TimeContext); 530 531 /* Close the TSYNC device */ 532 close(hBoard.file_descriptor); 533 534 // Check for errors 535 if ((err < 0) ||(err1 < 0) || (err2 < 0) || (err3 < 0) || 536 (it->status != 0) || (it1->status != 0) || (it2->status != 0) || 537 (it->actualOutLength != TSYNC_REF_OUT_LEN) || 538 (it1->actualOutLength != TSYNC_TMSCL_OUT_LEN) || 539 (it2->actualOutLength != TSYNC_LEAP_OUT_LEN)) { 540 refclock_report(peer, CEVNT_FAULT); 541 return; 542 } 543 544 // Extract reference identifiers from ioctl payload 545 memset(timeRef, '\0', sizeof(timeRef)); 546 memset(ppsRef, '\0', sizeof(ppsRef)); 547 pRefObj = (void *)it->payloads; 548 memcpy(timeRef, pRefObj->time, TSYNC_REF_LEN); 549 memcpy(ppsRef, pRefObj->pps, TSYNC_REF_LEN); 550 551 // Extract the Clock Service Time Scale and convert to correct byte order 552 memcpy(&tmscl, it1->payloads, sizeof(tmscl)); 553 tmscl = ntohl(tmscl); 554 555 // Extract leap second info from ioctl payload and perform byte swapping 556 for (i = 0; i < (sizeof(leapSec) / 4); i++) 557 { 558 for (j = 0; j < 4; j++) 559 { 560 ((unsigned char*)&leapSec)[(i * 4) + j] = 561 ((unsigned char*)(it2->payloads))[(i * 4) + (3 - j)]; 562 } 563 } 564 565 // Determine time reference ID from reference name 566 for (i = 0; RefIdLookupTbl[i].pRef != NULL; i++) 567 { 568 // Search RefID table 569 if (strstr(timeRef, RefIdLookupTbl[i].pRef) != NULL) 570 { 571 // Found the matching string 572 break; 573 } 574 } 575 576 // Determine pps reference ID from reference name 577 for (j = 0; RefIdLookupTbl[j].pRef != NULL; j++) 578 { 579 // Search RefID table 580 if (strstr(ppsRef, RefIdLookupTbl[j].pRef) != NULL) 581 { 582 // Found the matching string 583 break; 584 } 585 } 586 587 // Determine synchronization state from flags 588 synch = (TimeContext.timeObj.flags == 0x4) ? 1 : 0; 589 590 // Pull seconds information from time object 591 seconds = (double) (TimeContext.timeObj.secsDouble); 592 seconds /= (double) 1000000.0; 593 594 /* 595 ** Convert the number of microseconds to double and then place in the 596 ** peer's last received long floating point format. 597 */ 598 DTOLFP(((double)TimeContext.tv.tv_usec / 1000000.0), &pp->lastrec); 599 600 /* 601 ** The specTimeStamp is the number of seconds since 1/1/1970, while the 602 ** peer's lastrec time should be compatible with NTP which is seconds since 603 ** 1/1/1900. So Add the number of seconds between 1900 and 1970 to the 604 ** specTimeStamp and place in the peer's lastrec long floating point struct. 605 */ 606 pp->lastrec.Ul_i.Xl_ui += (unsigned int)TimeContext.tv.tv_sec + 607 SECONDS_1900_TO_1970; 608 609 pp->polls++; 610 611 /* 612 ** set the reference clock object 613 */ 614 sprintf(pp->a_lastcode, "%03d %02d:%02d:%02.6f", 615 TimeContext.timeObj.days, TimeContext.timeObj.hours, 616 TimeContext.timeObj.minutes, seconds); 617 618 pp->lencode = strlen (pp->a_lastcode); 619 pp->day = TimeContext.timeObj.days; 620 pp->hour = TimeContext.timeObj.hours; 621 pp->minute = TimeContext.timeObj.minutes; 622 pp->second = (int) seconds; 623 seconds = (seconds - (double) (pp->second / 1.0)) * 1000000000; 624 pp->nsec = (long) seconds; 625 626 /* 627 ** calculate year start 628 */ 629 jt.year = TimeContext.timeObj.year; 630 jt.yearday = 1; 631 jt.monthday = 1; 632 jt.month = 1; 633 jt.hour = 0; 634 jt.minute = 0; 635 jt.second = 0; 636 pp->yearstart = caltontp(&jt); 637 638 // Calculate and report reference clock offset 639 offset.l_ui = (long)(((pp->day - 1) * 24) + pp->hour + GMT); 640 offset.l_ui = (offset.l_ui * 60) + (long)pp->minute; 641 offset.l_ui = (offset.l_ui * 60) + (long)pp->second; 642 offset.l_ui = offset.l_ui + (long)pp->yearstart; 643 offset.l_uf = 0; 644 DTOLFP(pp->nsec / 1e9, <emp); 645 L_ADD(&offset, <emp); 646 refclock_process_offset(pp, offset, pp->lastrec, 647 pp->fudgetime1); 648 649 // KTS in sync 650 if (synch) { 651 // Subtract leap second info by one second to determine effective day 652 ApplyTimeOffset(&(leapSec.utcDate), -1); 653 654 // If there is a leap second today and the KTS is using a time scale 655 // which handles leap seconds then 656 if ((tmscl != TIME_SCALE_GPS) && (tmscl != TIME_SCALE_TAI) && 657 (leapSec.utcDate.year == (unsigned int)TimeContext.timeObj.year) && 658 (leapSec.utcDate.doy == (unsigned int)TimeContext.timeObj.days)) 659 { 660 // If adding a second 661 if (leapSec.offset == 1) 662 { 663 pp->leap = LEAP_ADDSECOND; 664 } 665 // Else if removing a second 666 else if (leapSec.offset == -1) 667 { 668 pp->leap = LEAP_DELSECOND; 669 } 670 // Else report no leap second pending (no handling of offsets 671 // other than +1 or -1) 672 else 673 { 674 pp->leap = LEAP_NOWARNING; 675 } 676 } 677 // Else report no leap second pending 678 else 679 { 680 pp->leap = LEAP_NOWARNING; 681 } 682 683 peer->leap = pp->leap; 684 refclock_report(peer, CEVNT_NOMINAL); 685 686 // If reference name reported, then not in holdover 687 if ((RefIdLookupTbl[i].pRef != NULL) && 688 (RefIdLookupTbl[j].pRef != NULL)) 689 { 690 // Determine if KTS being synchronized by host (identified as 691 // "LOCL") 692 if ((strcmp(RefIdLookupTbl[i].pRefId, TSYNC_REF_LOCAL) == 0) || 693 (strcmp(RefIdLookupTbl[j].pRefId, TSYNC_REF_LOCAL) == 0)) 694 { 695 // Clear prefer flag 696 peer->flags &= ~FLAG_PREFER; 697 698 // Set reference clock stratum level as unusable 699 pp->stratum = STRATUM_UNSPEC; 700 peer->stratum = pp->stratum; 701 702 // If a valid peer is available 703 if ((sys_peer != NULL) && (sys_peer != peer)) 704 { 705 // Store reference peer stratum level and ID 706 up->refStratum = sys_peer->stratum; 707 up->refId = addr2refid(&sys_peer->srcadr); 708 } 709 } 710 else 711 { 712 // Restore prefer flag 713 peer->flags |= up->refPrefer; 714 715 // Store reference stratum as local clock 716 up->refStratum = TSYNC_LCL_STRATUM; 717 strncpy((char *)&up->refId, RefIdLookupTbl[j].pRefId, 718 TSYNC_REF_LEN); 719 720 // Set reference clock stratum level as local clock 721 pp->stratum = TSYNC_LCL_STRATUM; 722 peer->stratum = pp->stratum; 723 } 724 725 // Update reference name 726 strncpy((char *)&pp->refid, RefIdLookupTbl[j].pRefId, 727 TSYNC_REF_LEN); 728 peer->refid = pp->refid; 729 } 730 // Else in holdover 731 else 732 { 733 // Restore prefer flag 734 peer->flags |= up->refPrefer; 735 736 // Update reference ID to saved ID 737 pp->refid = up->refId; 738 peer->refid = pp->refid; 739 740 // Update stratum level to saved stratum level 741 pp->stratum = up->refStratum; 742 peer->stratum = pp->stratum; 743 } 744 } 745 // Else KTS not in sync 746 else { 747 // Place local identifier in peer RefID 748 strncpy((char *)&pp->refid, TSYNC_REF_LOCAL, TSYNC_REF_LEN); 749 peer->refid = pp->refid; 750 751 // Report not in sync 752 pp->leap = LEAP_NOTINSYNC; 753 peer->leap = pp->leap; 754 } 755 756 if (pp->coderecv == pp->codeproc) { 757 refclock_report(peer, CEVNT_TIMEOUT); 758 return; 759 } 760 761 record_clock_stats(&peer->srcadr, pp->a_lastcode); 762 refclock_receive(peer); 763 764 /* Increment the number of times the reference has been polled */ 765 pp->polls++; 766 767 } /* End - tsync_poll() */ 768 769 770 //////////////////////////////////////////////////////////////////////////////// 771 // Function: ApplyTimeOffset 772 // Description: The ApplyTimeOffset function adds an offset (in seconds) to a 773 // specified date and time. The specified date and time is passed 774 // back after being modified. 775 // 776 // Assumptions: 1. Every fourth year is a leap year. Therefore, this function 777 // is only accurate through Feb 28, 2100. 778 //////////////////////////////////////////////////////////////////////////////// 779 void ApplyTimeOffset(DoyTimeObj* pDt, int off) 780 { 781 SecTimeObj st; // Time, in seconds 782 783 784 // Convert date and time to seconds 785 SecTimeFromDoyTime(&st, pDt); 786 787 // Apply offset 788 st.seconds = (int)((signed long long)st.seconds + (signed long long)off); 789 790 // Convert seconds to date and time 791 DoyTimeFromSecTime(pDt, &st); 792 793 } // End ApplyTimeOffset 794 795 796 //////////////////////////////////////////////////////////////////////////////// 797 // Function: SecTimeFromDoyTime 798 // Description: The SecTimeFromDoyTime function converts a specified date 799 // and time into a count of seconds since the base time. This 800 // function operates across the range Base Time to Max Time for 801 // the system. 802 // 803 // Assumptions: 1. A leap year is any year evenly divisible by 4. Therefore, 804 // this function is only accurate through Feb 28, 2100. 805 // 2. Conversion does not account for leap seconds. 806 //////////////////////////////////////////////////////////////////////////////// 807 void SecTimeFromDoyTime(SecTimeObj* pSt, DoyTimeObj* pDt) 808 { 809 unsigned int yrs; // Years 810 unsigned int lyrs; // Leap years 811 812 813 // Start with accumulated time of 0 814 pSt->seconds = 0; 815 816 // Calculate the number of years and leap years 817 yrs = pDt->year - TSYNC_TIME_BASE_YEAR; 818 lyrs = (yrs + 1) / 4; 819 820 // Convert leap years and years 821 pSt->seconds += lyrs * SECSPERLEAPYEAR; 822 pSt->seconds += (yrs - lyrs) * SECSPERYEAR; 823 824 // Convert days, hours, minutes and seconds 825 pSt->seconds += (pDt->doy - 1) * SECSPERDAY; 826 pSt->seconds += pDt->hour * SECSPERHR; 827 pSt->seconds += pDt->minute * SECSPERMIN; 828 pSt->seconds += pDt->second; 829 830 // Copy the subseconds count 831 pSt->ns = pDt->ns; 832 833 } // End SecTimeFromDoyTime 834 835 836 //////////////////////////////////////////////////////////////////////////////// 837 // Function: DoyTimeFromSecTime 838 // Description: The DoyTimeFromSecTime function converts a specified count 839 // of seconds since the start of our base time into a SecTimeObj 840 // structure. 841 // 842 // Assumptions: 1. A leap year is any year evenly divisible by 4. Therefore, 843 // this function is only accurate through Feb 28, 2100. 844 // 2. Conversion does not account for leap seconds. 845 //////////////////////////////////////////////////////////////////////////////// 846 void DoyTimeFromSecTime(DoyTimeObj* pDt, SecTimeObj* pSt) 847 { 848 signed long long secs; // Seconds accumulator variable 849 unsigned int yrs; // Years accumulator variable 850 unsigned int doys; // Days accumulator variable 851 unsigned int hrs; // Hours accumulator variable 852 unsigned int mins; // Minutes accumulator variable 853 854 855 // Convert the seconds count into a signed 64-bit number for calculations 856 secs = (signed long long)(pSt->seconds); 857 858 // Calculate the number of 4 year chunks 859 yrs = (unsigned int)((secs / 860 ((SECSPERYEAR * 3) + SECSPERLEAPYEAR)) * 4); 861 secs %= ((SECSPERYEAR * 3) + SECSPERLEAPYEAR); 862 863 // If there is at least a normal year worth of time left 864 if (secs >= SECSPERYEAR) 865 { 866 // Increment the number of years and subtract a normal year of time 867 yrs++; 868 secs -= SECSPERYEAR; 869 } 870 871 // If there is still at least a normal year worth of time left 872 if (secs >= SECSPERYEAR) 873 { 874 // Increment the number of years and subtract a normal year of time 875 yrs++; 876 secs -= SECSPERYEAR; 877 } 878 879 // If there is still at least a leap year worth of time left 880 if (secs >= SECSPERLEAPYEAR) 881 { 882 // Increment the number of years and subtract a leap year of time 883 yrs++; 884 secs -= SECSPERLEAPYEAR; 885 } 886 887 // Calculate the day of year as the number of days left, then add 1 888 // because months start on the 1st. 889 doys = (unsigned int)((secs / SECSPERDAY) + 1); 890 secs %= SECSPERDAY; 891 892 // Calculate the hour 893 hrs = (unsigned int)(secs / SECSPERHR); 894 secs %= SECSPERHR; 895 896 // Calculate the minute 897 mins = (unsigned int)(secs / SECSPERMIN); 898 secs %= SECSPERMIN; 899 900 // Fill in the doytime structure 901 pDt->year = yrs + TSYNC_TIME_BASE_YEAR; 902 pDt->doy = doys; 903 pDt->hour = hrs; 904 pDt->minute = mins; 905 pDt->second = (unsigned int)secs; 906 pDt->ns = pSt->ns; 907 908 } // End DoyTimeFromSecTime 909 910 #else 911 int refclock_tsyncpci_bs; 912 #endif /* REFCLOCK */ 913