refclock_tsyncpci.c revision 293893
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*/ 111typedef 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*/ 126typedef 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*/ 140typedef 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*/ 156typedef struct NtpTimeObj { 157 158 TimeObj timeObj; 159 struct timeval tv; 160 unsigned int refId; 161 162} NtpTimeObj; 163/* 164** TSYNC Supervisor Reference Object 165*/ 166typedef 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*/ 176typedef struct SecTimeObj 177{ 178 unsigned int seconds; 179 unsigned int ns; 180} 181SecTimeObj; 182 183/* 184** TSYNC DOY Time Object 185*/ 186typedef 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} 195DoyTimeObj; 196 197/* 198** TSYNC Leap Second Object 199*/ 200typedef struct LeapSecondObj 201{ 202 int offset; 203 DoyTimeObj utcDate; 204} 205LeapSecondObj; 206 207/* 208 * structures for ioctl interactions with driver 209 */ 210#define DI_PAYLOADS_STARTER_LENGTH 4 211typedef 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 */ 236typedef 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 */ 246typedef 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*/ 256static void tsync_poll (int unit, struct peer *); 257static void tsync_shutdown (int, struct peer *); 258static int tsync_start (int, struct peer *); 259 260/* 261** Helper functions 262*/ 263static void ApplyTimeOffset (DoyTimeObj* pDt, int off); 264static void SecTimeFromDoyTime (SecTimeObj* pSt, DoyTimeObj* pDt); 265static void DoyTimeFromSecTime (DoyTimeObj* pDt, SecTimeObj* pSt); 266 267/* 268** Transfer vector 269*/ 270struct 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 */ 283static 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*******************************************************************************/ 319static 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*******************************************************************************/ 372static 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*******************************************************************************/ 388static 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//////////////////////////////////////////////////////////////////////////////// 779void 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//////////////////////////////////////////////////////////////////////////////// 807void 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//////////////////////////////////////////////////////////////////////////////// 846void 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 911int refclock_tsyncpci_bs; 912#endif /* REFCLOCK */ 913