예제 #1
0
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);
}
예제 #2
0
/******************************************************************************
 *
 * 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, &ltemp);
    L_ADD(&offset, &ltemp);
    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() */