u_long calyearstart(u_long ntp_time) { struct calendar jt; caljulian(ntp_time,&jt); jt.yearday = 1; jt.monthday = 1; jt.month = 1; jt.hour = jt.minute = jt.second = 0; return caltontp(&jt); }
/****************************************************************************** * * Function: tsync_poll() * Description: Retrieve time from the TSYNC device. * * Parameters: * IN: unit - not used. * *peer - pointer to this reference clock's peer structure * Returns: none. * *******************************************************************************/ static void tsync_poll(int unit, struct peer *peer) { char device[32]; struct refclockproc *pp; struct calendar jt; TsyncUnit *up; unsigned char synch; double seconds; int err; int err1; int err2; int err3; int i; int j; unsigned int itAllocationLength; unsigned int itAllocationLength1; unsigned int itAllocationLength2; NtpTimeObj TimeContext; BoardObj hBoard; char timeRef[TSYNC_REF_LEN + 1]; char ppsRef [TSYNC_REF_LEN + 1]; TIME_SCALE tmscl = TIME_SCALE_UTC; LeapSecondObj leapSec; ioctl_trans_di *it; ioctl_trans_di *it1; ioctl_trans_di *it2; l_fp offset; l_fp ltemp; ReferenceObj * pRefObj; /* Construct the device name */ sprintf(device, "%s%d", DEVICE, (int)peer->refclkunit); printf("Polling device number %d...\n", (int)peer->refclkunit); /* Open the TSYNC device */ hBoard.file_descriptor = open(device, O_RDONLY | O_NDELAY, 0777); /* If error opening TSYNC device... */ if (hBoard.file_descriptor < 0) { msyslog(LOG_ERR, "Couldn't open device"); return; } /* If error while initializing the board... */ if (ioctl(hBoard.file_descriptor, IOCTL_TPRO_OPEN, &hBoard) < 0) { msyslog(LOG_ERR, "Couldn't initialize device"); close(hBoard.file_descriptor); return; } /* Allocate memory for ioctl message */ itAllocationLength = (sizeof(ioctl_trans_di) - DI_PAYLOADS_STARTER_LENGTH) + TSYNC_REF_IN_LEN + TSYNC_REF_MAX_OUT_LEN; it = (ioctl_trans_di*)alloca(itAllocationLength); if (it == NULL) { msyslog(LOG_ERR, "Couldn't allocate transaction memory - Reference"); return; } /* Build SS_GetRef ioctl message */ it->dest = TSYNC_REF_DEST_ID; it->iid = TSYNC_REF_IID; it->inPayloadOffset = TSYNC_REF_IN_PYLD_OFF; it->inLength = TSYNC_REF_IN_LEN; it->outPayloadOffset = TSYNC_REF_OUT_PYLD_OFF; it->maxOutLength = TSYNC_REF_MAX_OUT_LEN; it->actualOutLength = 0; it->status = 0; memset(it->payloads, 0, TSYNC_REF_MAX_OUT_LEN); /* Read the reference from the TSYNC-PCI device */ err = ioctl(hBoard.file_descriptor, IOCTL_TSYNC_GET, (char *)it); /* Allocate memory for ioctl message */ itAllocationLength1 = (sizeof(ioctl_trans_di) - DI_PAYLOADS_STARTER_LENGTH) + TSYNC_TMSCL_IN_LEN + TSYNC_TMSCL_MAX_OUT_LEN; it1 = (ioctl_trans_di*)alloca(itAllocationLength1); if (it1 == NULL) { msyslog(LOG_ERR, "Couldn't allocate transaction memory - Time Scale"); return; } /* Build CS_GetTimeScale ioctl message */ it1->dest = TSYNC_TMSCL_DEST_ID; it1->iid = TSYNC_TMSCL_IID; it1->inPayloadOffset = TSYNC_TMSCL_IN_PYLD_OFF; it1->inLength = TSYNC_TMSCL_IN_LEN; it1->outPayloadOffset = TSYNC_TMSCL_OUT_PYLD_OFF; it1->maxOutLength = TSYNC_TMSCL_MAX_OUT_LEN; it1->actualOutLength = 0; it1->status = 0; memset(it1->payloads, 0, TSYNC_TMSCL_MAX_OUT_LEN); /* Read the Time Scale info from the TSYNC-PCI device */ err1 = ioctl(hBoard.file_descriptor, IOCTL_TSYNC_GET, (char *)it1); /* Allocate memory for ioctl message */ itAllocationLength2 = (sizeof(ioctl_trans_di) - DI_PAYLOADS_STARTER_LENGTH) + TSYNC_LEAP_IN_LEN + TSYNC_LEAP_MAX_OUT_LEN; it2 = (ioctl_trans_di*)alloca(itAllocationLength2); if (it2 == NULL) { msyslog(LOG_ERR, "Couldn't allocate transaction memory - Leap Second"); return; } /* Build CS_GetLeapSec ioctl message */ it2->dest = TSYNC_LEAP_DEST_ID; it2->iid = TSYNC_LEAP_IID; it2->inPayloadOffset = TSYNC_LEAP_IN_PYLD_OFF; it2->inLength = TSYNC_LEAP_IN_LEN; it2->outPayloadOffset = TSYNC_LEAP_OUT_PYLD_OFF; it2->maxOutLength = TSYNC_LEAP_MAX_OUT_LEN; it2->actualOutLength = 0; it2->status = 0; memset(it2->payloads, 0, TSYNC_LEAP_MAX_OUT_LEN); /* Read the leap seconds info from the TSYNC-PCI device */ err2 = ioctl(hBoard.file_descriptor, IOCTL_TSYNC_GET, (char *)it2); pp = peer->procptr; up = (TsyncUnit*)pp->unitptr; /* Read the time from the TSYNC-PCI device */ err3 = ioctl(hBoard.file_descriptor, IOCTL_TPRO_GET_NTP_TIME, (char *)&TimeContext); /* Close the TSYNC device */ close(hBoard.file_descriptor); // Check for errors if ((err < 0) ||(err1 < 0) || (err2 < 0) || (err3 < 0) || (it->status != 0) || (it1->status != 0) || (it2->status != 0) || (it->actualOutLength != TSYNC_REF_OUT_LEN) || (it1->actualOutLength != TSYNC_TMSCL_OUT_LEN) || (it2->actualOutLength != TSYNC_LEAP_OUT_LEN)) { refclock_report(peer, CEVNT_FAULT); return; } // Extract reference identifiers from ioctl payload memset(timeRef, '\0', sizeof(timeRef)); memset(ppsRef, '\0', sizeof(ppsRef)); pRefObj = (void *)it->payloads; memcpy(timeRef, pRefObj->time, TSYNC_REF_LEN); memcpy(ppsRef, pRefObj->pps, TSYNC_REF_LEN); // Extract the Clock Service Time Scale and convert to correct byte order memcpy(&tmscl, ((TIME_SCALE*)(it1->payloads)), sizeof(tmscl)); tmscl = ntohl(tmscl); // Extract leap second info from ioctl payload and perform byte swapping for (i = 0; i < (sizeof(leapSec) / 4); i++) { for (j = 0; j < 4; j++) { ((unsigned char*)&leapSec)[(i * 4) + j] = ((unsigned char*)(it2->payloads))[(i * 4) + (3 - j)]; } } // Determine time reference ID from reference name for (i = 0; RefIdLookupTbl[i].pRef != NULL; i++) { // Search RefID table if (strstr(timeRef, RefIdLookupTbl[i].pRef) != NULL) { // Found the matching string break; } } // Determine pps reference ID from reference name for (j = 0; RefIdLookupTbl[j].pRef != NULL; j++) { // Search RefID table if (strstr(ppsRef, RefIdLookupTbl[j].pRef) != NULL) { // Found the matching string break; } } // Determine synchronization state from flags synch = (TimeContext.timeObj.flags == 0x4) ? 1 : 0; // Pull seconds information from time object seconds = (double) (TimeContext.timeObj.secsDouble); seconds /= (double) 1000000.0; /* ** Convert the number of microseconds to double and then place in the ** peer's last received long floating point format. */ DTOLFP(((double)TimeContext.tv.tv_usec / 1000000.0), &pp->lastrec); /* ** The specTimeStamp is the number of seconds since 1/1/1970, while the ** peer's lastrec time should be compatible with NTP which is seconds since ** 1/1/1900. So Add the number of seconds between 1900 and 1970 to the ** specTimeStamp and place in the peer's lastrec long floating point struct. */ pp->lastrec.Ul_i.Xl_ui += (unsigned int)TimeContext.tv.tv_sec + SECONDS_1900_TO_1970; pp->polls++; /* ** set the reference clock object */ sprintf(pp->a_lastcode, "%03d %02d:%02d:%02.6f", TimeContext.timeObj.days, TimeContext.timeObj.hours, TimeContext.timeObj.minutes, seconds); pp->lencode = strlen (pp->a_lastcode); pp->day = TimeContext.timeObj.days; pp->hour = TimeContext.timeObj.hours; pp->minute = TimeContext.timeObj.minutes; pp->second = (int) seconds; seconds = (seconds - (double) (pp->second / 1.0)) * 1000000000; pp->nsec = (long) seconds; /* ** calculate year start */ jt.year = TimeContext.timeObj.year; jt.yearday = 1; jt.monthday = 1; jt.month = 1; jt.hour = 0; jt.minute = 0; jt.second = 0; pp->yearstart = caltontp(&jt); // Calculate and report reference clock offset offset.l_ui = (long)(((pp->day - 1) * 24) + pp->hour + GMT); offset.l_ui = (offset.l_ui * 60) + (long)pp->minute; offset.l_ui = (offset.l_ui * 60) + (long)pp->second; offset.l_ui = offset.l_ui + (long)pp->yearstart; offset.l_uf = 0; DTOLFP(pp->nsec / 1e9, <emp); L_ADD(&offset, <emp); refclock_process_offset(pp, offset, pp->lastrec, pp->fudgetime1); // KTS in sync if (synch) { // Subtract leap second info by one second to determine effective day ApplyTimeOffset(&(leapSec.utcDate), -1); // If there is a leap second today and the KTS is using a time scale // which handles leap seconds then if ((tmscl != TIME_SCALE_GPS) && (tmscl != TIME_SCALE_TAI) && (leapSec.utcDate.year == (unsigned int)TimeContext.timeObj.year) && (leapSec.utcDate.doy == (unsigned int)TimeContext.timeObj.days)) { // If adding a second if (leapSec.offset == 1) { pp->leap = LEAP_ADDSECOND; } // Else if removing a second else if (leapSec.offset == -1) { pp->leap = LEAP_DELSECOND; } // Else report no leap second pending (no handling of offsets // other than +1 or -1) else { pp->leap = LEAP_NOWARNING; } } // Else report no leap second pending else { pp->leap = LEAP_NOWARNING; } peer->leap = pp->leap; refclock_report(peer, CEVNT_NOMINAL); // If reference name reported, then not in holdover if ((RefIdLookupTbl[i].pRef != NULL) && (RefIdLookupTbl[j].pRef != NULL)) { // Determine if KTS being synchronized by host (identified as // "LOCL") if ((strcmp(RefIdLookupTbl[i].pRefId, TSYNC_REF_LOCAL) == 0) || (strcmp(RefIdLookupTbl[j].pRefId, TSYNC_REF_LOCAL) == 0)) { // Clear prefer flag peer->flags &= ~FLAG_PREFER; // Set reference clock stratum level as unusable pp->stratum = STRATUM_UNSPEC; peer->stratum = pp->stratum; // If a valid peer is available if ((sys_peer != NULL) && (sys_peer != peer)) { // Store reference peer stratum level and ID up->refStratum = sys_peer->stratum; up->refId = addr2refid(&sys_peer->srcadr); } } else { // Restore prefer flag peer->flags |= up->refPrefer; // Store reference stratum as local clock up->refStratum = TSYNC_LCL_STRATUM; strncpy((char *)&up->refId, RefIdLookupTbl[j].pRefId, TSYNC_REF_LEN); // Set reference clock stratum level as local clock pp->stratum = TSYNC_LCL_STRATUM; peer->stratum = pp->stratum; } // Update reference name strncpy((char *)&pp->refid, RefIdLookupTbl[j].pRefId, TSYNC_REF_LEN); peer->refid = pp->refid; } // Else in holdover else { // Restore prefer flag peer->flags |= up->refPrefer; // Update reference ID to saved ID pp->refid = up->refId; peer->refid = pp->refid; // Update stratum level to saved stratum level pp->stratum = up->refStratum; peer->stratum = pp->stratum; } } // Else KTS not in sync else { // Place local identifier in peer RefID strncpy((char *)&pp->refid, TSYNC_REF_LOCAL, TSYNC_REF_LEN); peer->refid = pp->refid; // Report not in sync pp->leap = LEAP_NOTINSYNC; peer->leap = pp->leap; } if (pp->coderecv == pp->codeproc) { refclock_report(peer, CEVNT_TIMEOUT); return; } record_clock_stats(&peer->srcadr, pp->a_lastcode); refclock_receive(peer); /* Increment the number of times the reference has been polled */ pp->polls++; } /* End - tsync_poll() */