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