#include "../ptpd.h" void initClock(PtpClock *ptpClock) { DBG("initClock\n"); /* Clear vars */ ptpClock->Tms.seconds = ptpClock->Tms.nanoseconds = 0; ptpClock->observedDrift = 0; /* clears clock servo accumulator (the I term) */ /* One way delay */ ptpClock->owd_filt.n = 0; ptpClock->owd_filt.s = ptpClock->servo.sDelay; /* Offset from master */ ptpClock->ofm_filt.n = 0; ptpClock->ofm_filt.s = ptpClock->servo.sOffset; /* Scaled log variance */ if (DEFAULT_PARENTS_STATS) { ptpClock->slv_filt.n = 0; ptpClock->slv_filt.s = 6; ptpClock->offsetHistory[0] = 0; ptpClock->offsetHistory[1] = 0; } ptpClock->waitingForFollowUp = FALSE; ptpClock->waitingForPDelayRespFollowUp = FALSE; ptpClock->pdelay_t1.seconds = ptpClock->pdelay_t1.nanoseconds = 0; ptpClock->pdelay_t2.seconds = ptpClock->pdelay_t2.nanoseconds = 0; ptpClock->pdelay_t3.seconds = ptpClock->pdelay_t3.nanoseconds = 0; ptpClock->pdelay_t4.seconds = ptpClock->pdelay_t4.nanoseconds = 0; /* Reset parent statistics */ ptpClock->parentDS.parentStats = FALSE; ptpClock->parentDS.observedParentClockPhaseChangeRate = 0; ptpClock->parentDS.observedParentOffsetScaledLogVariance = 0; /* Level clock */ if (!ptpClock->servo.noAdjust) adjFreq(0); netEmptyEventQ(&ptpClock->netPath); } static int32_t order(int32_t n) { if (n < 0) { n = -n; } if (n == 0) { return 0; } return floorLog2(n); } /* Exponencial smoothing */ static void filter(int32_t * nsec_current, Filter * filt) { int32_t s, s2; /* using floatingpoint math alpha = 1/2^s y[1] = x[0] y[n] = alpha * x[n-1] + (1-alpha) * y[n-1] or equivalent with integer math y[1] = x[0] y_sum[1] = y[1] * 2^s y_sum[n] = y_sum[n-1] + x[n-1] - y[n-1] y[n] = y_sum[n] / 2^s */ /* Increment number of samples */ filt->n++; /* If it is first time, we are running filter, initialize it */ if (filt->n == 1) { filt->y_prev = *nsec_current; filt->y_sum = *nsec_current; filt->s_prev = 0; } s = filt->s; /* Speedup filter, if not 2^s > n */ if ((1< filt->n) { /* Lower the filter order */ s = order(filt->n); } else { /* Avoid overflowing of n */ filt->n = 1<y_prev, *nsec_current)); /* Use the lower filter order, higher will overflow */ s = min(s, s2); /* If the order of the filter changed, change also y_sum value */ if (filt->s_prev > s) { filt->y_sum >>= (filt->s_prev - s); } else if (filt->s_prev < s) { filt->y_sum <<= (s - filt->s_prev); } /* Compute the filter itself */ filt->y_sum += *nsec_current - filt->y_prev; filt->y_prev = filt->y_sum >> s; /* Save previous order of the filter */ filt->s_prev = s; DBGV("filter: %d -> %d (%d)\n", *nsec_current, filt->y_prev, s); /* Actualize target value */ *nsec_current = filt->y_prev; } /* 11.2 */ void updateOffset(PtpClock *ptpClock, const TimeInternal *syncEventIngressTimestamp, const TimeInternal *preciseOriginTimestamp, const TimeInternal *correctionField) { DBGV("updateOffset\n"); /* = - - - correctionField of Sync message - correctionField of Follow_Up message. */ /* Compute offsetFromMaster */ subTime(&ptpClock->Tms, syncEventIngressTimestamp, preciseOriginTimestamp); subTime(&ptpClock->Tms, &ptpClock->Tms, correctionField); ptpClock->currentDS.offsetFromMaster = ptpClock->Tms; switch (ptpClock->portDS.delayMechanism) { case E2E: subTime(&ptpClock->currentDS.offsetFromMaster, &ptpClock->currentDS.offsetFromMaster, &ptpClock->currentDS.meanPathDelay); break; case P2P: subTime(&ptpClock->currentDS.offsetFromMaster, &ptpClock->currentDS.offsetFromMaster, &ptpClock->portDS.peerMeanPathDelay); break; default: break; } if (ptpClock->currentDS.offsetFromMaster.seconds != 0) { if (ptpClock->portDS.portState == PTP_SLAVE) { setFlag(ptpClock->events, SYNCHRONIZATION_FAULT); } DBGV("updateOffset: cannot filter seconds\n"); return; } /* Filter offsetFromMaster */ filter(&ptpClock->currentDS.offsetFromMaster.nanoseconds, &ptpClock->ofm_filt); /* Check results */ if (abs(ptpClock->currentDS.offsetFromMaster.nanoseconds) < DEFAULT_CALIBRATED_OFFSET_NS) { if (ptpClock->portDS.portState == PTP_UNCALIBRATED) { setFlag(ptpClock->events, MASTER_CLOCK_SELECTED); } } else if (abs(ptpClock->currentDS.offsetFromMaster.nanoseconds) > DEFAULT_UNCALIBRATED_OFFSET_NS) { if (ptpClock->portDS.portState == PTP_SLAVE) { setFlag(ptpClock->events, SYNCHRONIZATION_FAULT); } } } /* 11.3 */ void updateDelay(PtpClock * ptpClock, const TimeInternal *delayEventEgressTimestamp, const TimeInternal *recieveTimestamp, const TimeInternal *correctionField) { /* Tms valid ? */ if (0 == ptpClock->ofm_filt.n) { DBGV("updateDelay: Tms is not valid"); return; } subTime(&ptpClock->Tsm, recieveTimestamp, delayEventEgressTimestamp); subTime(&ptpClock->Tsm, &ptpClock->Tsm, correctionField); addTime(&ptpClock->currentDS.meanPathDelay, &ptpClock->Tms, &ptpClock->Tsm); div2Time(&ptpClock->currentDS.meanPathDelay); /* Filter delay */ if (0 != ptpClock->currentDS.meanPathDelay.seconds) { DBGV("updateDelay: cannot filter with seconds"); } else { filter(&ptpClock->currentDS.meanPathDelay.nanoseconds, &ptpClock->owd_filt); } } void updatePeerDelay(PtpClock *ptpClock, const TimeInternal *correctionField, bool twoStep) { DBGV("updatePeerDelay\n"); if (twoStep) { TimeInternal Tab, Tba; subTime(&Tab, &ptpClock->pdelay_t2 , &ptpClock->pdelay_t1); subTime(&Tba, &ptpClock->pdelay_t4, &ptpClock->pdelay_t3); addTime(&ptpClock->portDS.peerMeanPathDelay, &Tab, &Tba); } else /* One step clock */ { subTime(&ptpClock->portDS.peerMeanPathDelay, &ptpClock->pdelay_t4, &ptpClock->pdelay_t1); } subTime(&ptpClock->portDS.peerMeanPathDelay, &ptpClock->portDS.peerMeanPathDelay, correctionField); div2Time(&ptpClock->portDS.peerMeanPathDelay); /* Filter delay */ if (ptpClock->portDS.peerMeanPathDelay.seconds != 0) { DBGV("updatePeerDelay: cannot filter with seconds"); return; } else { filter(&ptpClock->portDS.peerMeanPathDelay.nanoseconds, &ptpClock->owd_filt); } } void updateClock(PtpClock *ptpClock) { int32_t adj; TimeInternal timeTmp; int32_t offsetNorm; DBGV("updateClock\n"); if (ptpClock->currentDS.offsetFromMaster.seconds != 0 || abs(ptpClock->currentDS.offsetFromMaster.nanoseconds) > MAX_ADJ_OFFSET_NS) { /* if secs, reset clock or set freq adjustment to max */ if (!ptpClock->servo.noAdjust) { if (!ptpClock->servo.noResetClock) { getTime(&timeTmp); subTime(&timeTmp, &timeTmp, &ptpClock->currentDS.offsetFromMaster); setTime(&timeTmp); initClock(ptpClock); } else { adj = ptpClock->currentDS.offsetFromMaster.nanoseconds > 0 ? ADJ_FREQ_MAX : -ADJ_FREQ_MAX; adjFreq(-adj); } } } else { /* the PI controller */ /* normalize offset to 1s sync interval -> response of the servo will * be same for all sync interval values, but faster/slower * (possible lost of precision/overflow but much more stable) */ offsetNorm = ptpClock->currentDS.offsetFromMaster.nanoseconds; if (ptpClock->portDS.logSyncInterval > 0) offsetNorm >>= ptpClock->portDS.logSyncInterval; else if (ptpClock->portDS.logSyncInterval < 0) offsetNorm <<= -ptpClock->portDS.logSyncInterval; /* the accumulator for the I component */ ptpClock->observedDrift += offsetNorm / ptpClock->servo.ai; /* clamp the accumulator to ADJ_FREQ_MAX for sanity */ if (ptpClock->observedDrift > ADJ_FREQ_MAX) ptpClock->observedDrift = ADJ_FREQ_MAX; else if (ptpClock->observedDrift < -ADJ_FREQ_MAX) ptpClock->observedDrift = -ADJ_FREQ_MAX; /* apply controller output as a clock tick rate adjustment */ if (!ptpClock->servo.noAdjust) { adj = offsetNorm / ptpClock->servo.ap + ptpClock->observedDrift; adjFreq(-adj); } if (DEFAULT_PARENTS_STATS) { int a, scaledLogVariance; ptpClock->parentDS.parentStats = TRUE; ptpClock->parentDS.observedParentClockPhaseChangeRate = 1100 * ptpClock->observedDrift; a = (ptpClock->offsetHistory[1] - 2 * ptpClock->offsetHistory[0] + ptpClock->currentDS.offsetFromMaster.nanoseconds); ptpClock->offsetHistory[1] = ptpClock->offsetHistory[0]; ptpClock->offsetHistory[0] = ptpClock->currentDS.offsetFromMaster.nanoseconds; scaledLogVariance = order(a * a) << 8; filter(&scaledLogVariance, &ptpClock->slv_filt); ptpClock->parentDS.observedParentOffsetScaledLogVariance = 17000 + scaledLogVariance; DBGV("updateClock: observed scalled log variance: 0x%x\n", ptpClock->parentDS.observedParentOffsetScaledLogVariance); } } switch (ptpClock->portDS.delayMechanism) { case E2E: DBG("updateClock: one-way delay averaged (E2E): %d sec %d nsec\n", ptpClock->currentDS.meanPathDelay.seconds, ptpClock->currentDS.meanPathDelay.nanoseconds); break; case P2P: DBG("updateClock: one-way delay averaged (P2P): %d sec %d nsec\n", ptpClock->portDS.peerMeanPathDelay.seconds, ptpClock->portDS.peerMeanPathDelay.nanoseconds); break; default: DBG("updateClock: one-way delay not computed\n"); } DBG("updateClock: offset from master: %d sec %d nsec\n", ptpClock->currentDS.offsetFromMaster.seconds, ptpClock->currentDS.offsetFromMaster.nanoseconds); DBG("updateClock: observed drift: %d\n", ptpClock->observedDrift); }