Beispiel #1
0
void
updateClock(RunTimeOpts * rtOpts, PtpClock * ptpClock)
{

	/* updates paused, leap second pending - do nothing */
        if(ptpClock->leapSecondInProgress)
            return;
	DBGV("==> updateClock\n");

	if(ptpClock->panicMode) {
	    DBG("Panic mode - skipping updateClock");
	}



/*
if(rtOpts->delayMSOutlierFilterEnabled && rtOpts->delayMSOutlierFilterDiscard && ptpClock->delayMSoutlier)
	    goto display;
*/
	if (rtOpts->maxReset) { /* If maxReset is 0 then it's OFF */
		if (ptpClock->offsetFromMaster.seconds && rtOpts->maxReset) {
			INFO("updateClock aborted, offset greater than 1"
			     " second.");
			if (rtOpts->displayPackets)
				msgDump(ptpClock);
			goto display;
		}

		if (ptpClock->offsetFromMaster.nanoseconds > rtOpts->maxReset) {
			INFO("updateClock aborted, offset %d greater than "
			     "administratively set maximum %d\n",
			     ptpClock->offsetFromMaster.nanoseconds, 
			     rtOpts->maxReset);
			if (rtOpts->displayPackets)
				msgDump(ptpClock);
			goto display;
		}
	}

	if (ptpClock->offsetFromMaster.seconds) {
		/* if secs, reset clock or set freq adjustment to max */
		
		/* 
		  if offset from master seconds is non-zero, then this is a "big jump:
		  in time.  Check Run Time options to see if we will reset the clock or
		  set frequency adjustment to max to adjust the time
		*/

		/*
		 * noAdjust     = cannot do any change to clock
		 * noResetClock = if can change the clock, can we also step it?
		 */
		if (!rtOpts->noAdjust) {


	if(rtOpts->enablePanicMode && !ptpClock->panicOver) {

		if(ptpClock->panicMode)
		    goto display;

		if(ptpClock->panicOver) {
		    ptpClock->panicMode = FALSE;
		    ptpClock->panicOver = FALSE;
#ifdef PTPD_STATISTICS
		    ptpClock->isCalibrated = FALSE;
#endif /* PTPD_STATISTICS */
		    goto display;
		}

		CRITICAL("Offset above 1 second - entering panic mode\n");

		ptpClock->panicMode = TRUE;
		ptpClock->panicModeTimeLeft = 2 * rtOpts->panicModeDuration;
		timerStart(PANIC_MODE_TIMER, 30, ptpClock->itimer);

#ifdef PTPD_NTPDC

/* Trigger NTP failover as part of panic mode */

if(rtOpts->ntpOptions.enableEngine && rtOpts->panicModeNtp) {

				/* Make sure we log ntp control errors now */
				ptpClock->ntpControl.requestFailed = FALSE;
                                /* We have a timeout defined */
                                if(rtOpts->ntpOptions.failoverTimeout) {
                                        DBG("NTP failover timer started - panic mode\n");
                                        timerStart(NTPD_FAILOVER_TIMER,
                                                    rtOpts->ntpOptions.failoverTimeout,
                                                    ptpClock->itimer);
                                /* Fail over to NTP straight away */
                                } else {
                                        DBG("Initiating NTP failover\n");
                                        ptpClock->ntpControl.isRequired = TRUE;
                                        ptpClock->ntpControl.isFailOver = TRUE;
                                        if(!ntpdControl(&rtOpts->ntpOptions, &ptpClock->ntpControl, FALSE))
                                                DBG("PANIC MODE instant NTP failover - could not fail over\n");
                                }

}

#endif /* PTPD_NTPDC */
		goto display;

	}

			if(rtOpts->enablePanicMode) {
				if(ptpClock->panicOver)
					CRITICAL("Panic mode timeout - accepting current offset. Clock will jump\n");
				ptpClock->panicOver = FALSE;
				timerStop(PANIC_MODE_TIMER, ptpClock->itimer);

#ifdef PTPD_NTPDC
/* Exiting ntp failover - getting out of panic mode */
	if(rtOpts->ntpOptions.enableEngine && rtOpts->panicModeNtp) {
                            timerStop(NTPD_FAILOVER_TIMER, ptpClock->itimer);
			    ptpClock->ntpControl.isRequired = FALSE;
			    ptpClock->ntpControl.isFailOver = FALSE;
                            if(!ntpdControl(&rtOpts->ntpOptions, &ptpClock->ntpControl, FALSE))
                                DBG("NTPdcontrol - could not return from NTP panic mode\n");
	}
#endif /* PTPD_NTPDC */

			}
			if (!rtOpts->noResetClock) {
				servo_perform_clock_step(rtOpts, ptpClock);
			} else {
#ifdef HAVE_SYS_TIMEX_H
				if(ptpClock->offsetFromMaster.nanoseconds > 0)
				    ptpClock->servo.observedDrift = rtOpts->servoMaxPpb;
				else
				    ptpClock->servo.observedDrift = -rtOpts->servoMaxPpb;
				warn_operator_slow_slewing(rtOpts, ptpClock);
				adjFreq_wrapper(rtOpts, ptpClock, -ptpClock->servo.observedDrift);
				/* its not clear how the APPLE case works for large jumps */
#endif /* HAVE_SYS_TIMEX_H */
			}
		}
	} else {

	    /* If we're in panic mode, either exit if no threshold configured, or exit if we're outside the exit threshold */
	    if(rtOpts->enablePanicMode && 
		((ptpClock->panicMode && ( rtOpts->panicModeExitThreshold == 0 || ((rtOpts->panicModeExitThreshold > 0) &&  ((ptpClock->offsetFromMaster.seconds == 0) && (ptpClock->offsetFromMaster.nanoseconds < rtOpts->panicModeExitThreshold))))   ) || ptpClock->panicOver)) {
		    ptpClock->panicMode = FALSE;
		    ptpClock->panicOver = FALSE;
		    timerStop(PANIC_MODE_TIMER, ptpClock->itimer);
		    NOTICE("Offset below 1 second again: exiting panic mode\n");
#ifdef PTPD_NTPDC
/* exiting ntp failover - panic mode over */
	if(rtOpts->ntpOptions.enableEngine && rtOpts->panicModeNtp) {
                            timerStop(NTPD_FAILOVER_TIMER, ptpClock->itimer);
			    ptpClock->ntpControl.isRequired = FALSE;
			    ptpClock->ntpControl.isFailOver = FALSE;
                            if(!ntpdControl(&rtOpts->ntpOptions, &ptpClock->ntpControl, FALSE))
                                DBG("NTPdcontrol - could not return from NTP panic mode\n");
	}
#endif /* PTPD_NTPDC */

	    }

	/* Servo dT is the log sync interval */
	/* TODO: if logsyincinterval is 127 [unicast], switch to measured */
	if(rtOpts->servoDtMethod == DT_CONSTANT)
		ptpClock->servo.logdT = ptpClock->logSyncInterval;

/* If the last delayMS was an outlier and filter action is discard, skip servo run */
#ifdef PTPD_STATISTICS
	if(rtOpts->delayMSOutlierFilterEnabled && rtOpts->delayMSOutlierFilterDiscard && ptpClock->delayMSoutlier)
		goto statistics;
#endif /* PTPD_STATISTICS */

#ifndef HAVE_SYS_TIMEX_H
			adjTime(ptpClock->offsetFromMaster.nanoseconds);
#else

#ifdef PTPD_STATISTICS
	/* if statistics are enabled, only run the servo if we are calibrted - if calibration delay configured */
	if(!rtOpts->calibrationDelay || ptpClock->isCalibrated)
#endif /*PTPD_STATISTICS */
		/* Adjust the clock first -> the PI controller runs here */
		adjFreq_wrapper(rtOpts, ptpClock, runPIservo(&ptpClock->servo, ptpClock->offsetFromMaster.nanoseconds));
		/* Unset STA_UNSYNC */
		unsetTimexFlags(STA_UNSYNC, TRUE);
		/* "Tell" the clock about maxerror, esterror etc. */
		informClockSource(ptpClock);
#endif /* HAVE_SYS_TIMEX_H */
	}

/* Update relevant statistics containers, feed outlier filter thresholds etc. */
#ifdef PTPD_STATISTICS
statistics:
                        if (rtOpts->delayMSOutlierFilterEnabled) {
                        	double dDelayMS = timeInternalToDouble(&ptpClock->rawDelayMS);
                        	if(ptpClock->delayMSoutlier) {
				/* Allow [weight] * [deviation from mean] to influence std dev in the next outlier checks */
                        		DBG("DelayMS Outlier: %.09f\n", dDelayMS);
                        		dDelayMS = ptpClock->delayMSRawStats->meanContainer->mean + 
						    rtOpts->delayMSOutlierWeight * ( dDelayMS - ptpClock->delayMSRawStats->meanContainer->mean);
                        	}
                                feedDoubleMovingStdDev(ptpClock->delayMSRawStats, dDelayMS);
                                feedDoubleMovingMean(ptpClock->delayMSFiltered, timeInternalToDouble(&ptpClock->delayMS));
                        }
                        feedDoublePermanentStdDev(&ptpClock->slaveStats.ofmStats, timeInternalToDouble(&ptpClock->offsetFromMaster));
                        feedDoublePermanentStdDev(&ptpClock->servo.driftStats, ptpClock->servo.observedDrift);
#endif /* PTPD_STATISTICS */

display:
		logStatistics(rtOpts, ptpClock);

	DBGV("\n--Offset Correction-- \n");
	DBGV("Raw offset from master:  %10ds %11dns\n",
	    ptpClock->delayMS.seconds,
	    ptpClock->delayMS.nanoseconds);

	DBGV("\n--Offset and Delay filtered-- \n");

	if (ptpClock->delayMechanism == P2P) {
		DBGV("one-way delay averaged (P2P):  %10ds %11dns\n",
		    ptpClock->peerMeanPathDelay.seconds, 
		    ptpClock->peerMeanPathDelay.nanoseconds);
	} else if (ptpClock->delayMechanism == E2E) {
		DBGV("one-way delay averaged (E2E):  %10ds %11dns\n",
		    ptpClock->meanPathDelay.seconds, 
		    ptpClock->meanPathDelay.nanoseconds);
	}

	DBGV("offset from master:      %10ds %11dns\n",
	    ptpClock->offsetFromMaster.seconds, 
	    ptpClock->offsetFromMaster.nanoseconds);
	DBGV("observed drift:          %10d\n", ptpClock->servo.observedDrift);
}
Beispiel #2
0
void
updateDelay(one_way_delay_filter * owd_filt, const RunTimeOpts * rtOpts, PtpClock * ptpClock, TimeInternal * correctionField)
{

	/* updates paused, leap second pending - do nothing */
	if(ptpClock->leapSecondInProgress)
		return;

	DBGV("updateDelay\n");

	/* todo: do all intermediate calculations on temp vars */
	TimeInternal prev_meanPathDelay = ptpClock->meanPathDelay;

	ptpClock->char_last_msg = 'D';

	Boolean maxDelayHit = FALSE;

	{

#ifdef PTPD_STATISTICS
		/* if maxDelayStableOnly configured, only check once servo is stable */
		Boolean checkThreshold = rtOpts-> maxDelayStableOnly ?
		    (ptpClock->servo.isStable && rtOpts->maxDelay) :
		    (rtOpts->maxDelay);
#else
		Boolean checkThreshold = rtOpts->maxDelay;
#endif
		//perform basic checks, using local variables only
		TimeInternal slave_to_master_delay;


		/* calc 'slave_to_master_delay' */
		subTime(&slave_to_master_delay, &ptpClock->delay_req_receive_time,
			&ptpClock->delay_req_send_time);

		if (checkThreshold && /* If maxDelay is 0 then it's OFF */
		    ptpClock->offsetFirstUpdated) {

			if ((slave_to_master_delay.nanoseconds < 0) &&
			    (abs(slave_to_master_delay.nanoseconds) > rtOpts->maxDelay)) {
				INFO("updateDelay aborted, "
				     "delay (sec: %d ns: %d) is negative\n",
				     slave_to_master_delay.seconds,
				     slave_to_master_delay.nanoseconds);
				INFO("send (sec: %d ns: %d)\n",
				     ptpClock->delay_req_send_time.seconds,
				     ptpClock->delay_req_send_time.nanoseconds);
				INFO("recv (sec: %d n	s: %d)\n",
				     ptpClock->delay_req_receive_time.seconds,
				     ptpClock->delay_req_receive_time.nanoseconds);
				goto finish;
			}

			if (slave_to_master_delay.seconds && checkThreshold) {
				INFO("updateDelay aborted, slave to master delay %d.%d greater than 1 second\n",
				     slave_to_master_delay.seconds,
				     slave_to_master_delay.nanoseconds);
				if (rtOpts->displayPackets)
					msgDump(ptpClock);
				goto finish;
			}

			if (slave_to_master_delay.nanoseconds > rtOpts->maxDelay) {
				ptpClock->counters.maxDelayDrops++;
				DBG("updateDelay aborted, slave to master delay %d greater than "
				     "administratively set maximum %d\n",
				     slave_to_master_delay.nanoseconds, 
				     rtOpts->maxDelay);
				if(rtOpts->maxDelayMaxRejected) {
                                    maxDelayHit = TRUE;
				    /* if we blocked maxDelayMaxRejected samples, reset the slave to unblock the filter */
				    if(++ptpClock->maxDelayRejected > rtOpts->maxDelayMaxRejected) {
					    WARNING("%d consecutive measurements above %d threshold - resetting slave\n",
							rtOpts->maxDelayMaxRejected, slave_to_master_delay.nanoseconds);
					    toState(PTP_LISTENING, rtOpts, ptpClock);
				    }
				}

				if (rtOpts->displayPackets)
					msgDump(ptpClock);
				goto finish;
			} else {
				ptpClock->maxDelayRejected=0;
			}
		}
	}

	/*
	 * The packet has passed basic checks, so we'll:
	 *   - update the global delaySM variable
	 *   - calculate a new filtered MPD
	 */
	if (ptpClock->offsetFirstUpdated) {
		Integer16 s;

		/*
		 * calc 'slave_to_master_delay' (Master to Slave delay is
		 * already computed in updateOffset )
		 */

		DBG("==> UpdateDelay():   %s\n",
			dump_TimeInternal2("Req_RECV:", &ptpClock->delay_req_receive_time,
			"Req_SENT:", &ptpClock->delay_req_send_time));

	/* raw value before filtering */
	subTime(&ptpClock->rawDelaySM, &ptpClock->delay_req_receive_time,
		&ptpClock->delay_req_send_time);

#ifdef PTPD_STATISTICS

/* testing only: step detection */
#if 0
	TimeInternal bob;
	bob.nanoseconds = -1000000;
	bob.seconds = 0;
	if(ptpClock->addOffset) {
	    	addTime(&ptpClock->rawDelaySM, &ptpClock->rawDelaySM, &bob);
	}
#endif

	/* run the delayMS stats filter */
	if(rtOpts->filterSMOpts.enabled) {
	    if(!feedDoubleMovingStatFilter(ptpClock->filterSM, timeInternalToDouble(&ptpClock->rawDelaySM))) {
		    return;
	    }
	    ptpClock->rawDelaySM = doubleToTimeInternal(ptpClock->filterSM->output);
	}

	/* run the delaySM outlier filter */
	if(!rtOpts->noAdjust && ptpClock->oFilterSM.config.enabled && (ptpClock->oFilterSM.config.alwaysFilter || !ptpClock->servo.runningMaxOutput) ) {
		if(ptpClock->oFilterSM.filter(&ptpClock->oFilterSM, timeInternalToDouble(&ptpClock->rawDelaySM))) {
			ptpClock->delaySM = doubleToTimeInternal(ptpClock->oFilterSM.output);
		} else {
			ptpClock->counters.delaySMOutliersFound++;
			/* If the outlier filter has blocked the sample, "reverse" the last maxDelay action */
			if (maxDelayHit) {
				    ptpClock->maxDelayRejected--;
			}
			goto finish;
		}
	} else {
		ptpClock->delaySM = ptpClock->rawDelaySM;
	}



#else
		subTime(&ptpClock->delaySM, &ptpClock->delay_req_receive_time, 
			&ptpClock->delay_req_send_time);
#endif

		/* update MeanPathDelay */
		addTime(&ptpClock->meanPathDelay, &ptpClock->delaySM, 
			&ptpClock->delayMS);

		/* Subtract correctionField */
		subTime(&ptpClock->meanPathDelay, &ptpClock->meanPathDelay, 
			correctionField);

		/* Compute one-way delay */
		div2Time(&ptpClock->meanPathDelay);
		
		if (ptpClock->meanPathDelay.seconds) {
			DBG("update delay: cannot filter with large OFM, "
				"clearing filter\n");
			INFO("Servo: Ignoring delayResp because of large OFM\n");
			
			owd_filt->s_exp = owd_filt->nsec_prev = 0;
			/* revert back to previous value */
			ptpClock->meanPathDelay = prev_meanPathDelay;
			goto finish;
		}

		if(ptpClock->meanPathDelay.nanoseconds < 0){
			DBG("update delay: found negative value for OWD, "
			    "so ignoring this value: %d\n",
				ptpClock->meanPathDelay.nanoseconds);
			/* revert back to previous value */
			ptpClock->meanPathDelay = prev_meanPathDelay;
			goto finish;
		}

		/* avoid overflowing filter */
		s = rtOpts->s;
		while (abs(owd_filt->y) >> (31 - s))
			--s;

		/* crank down filter cutoff by increasing 's_exp' */
		if (owd_filt->s_exp < 1)
			owd_filt->s_exp = 1;
		else if (owd_filt->s_exp < 1 << s)
			++owd_filt->s_exp;
		else if (owd_filt->s_exp > 1 << s)
			owd_filt->s_exp = 1 << s;

		/* filter 'meanPathDelay' */
		double fy =
			(double)((owd_filt->s_exp - 1.0) *
			owd_filt->y / (owd_filt->s_exp + 0.0) +
			(ptpClock->meanPathDelay.nanoseconds / 2.0 + 
			 owd_filt->nsec_prev / 2.0) / (owd_filt->s_exp + 0.0));

		owd_filt->nsec_prev = ptpClock->meanPathDelay.nanoseconds;

		owd_filt->y = round(fy);

		ptpClock->meanPathDelay.nanoseconds = owd_filt->y;

		DBGV("delay filter %d, %d\n", owd_filt->y, owd_filt->s_exp);
	} else {
Beispiel #3
0
void
updateDelay(Filter * owd_filt, RunTimeOpts * rtOpts, PtpClock * ptpClock, TimeInternal * correctionField)
{

	/* updates paused, leap second pending - do nothing */
	if(ptpClock->leapSecondInProgress)
		return;

	DBGV("updateDelay\n");



	/* todo: do all intermediate calculations on temp vars */
	TimeInternal prev_meanPathDelay = ptpClock->meanPathDelay;

	ptpClock->char_last_msg = 'D';

	{
		//perform basic checks, using local variables only
		TimeInternal slave_to_master_delay;
	
		/* calc 'slave_to_master_delay' */
		subTime(&slave_to_master_delay, &ptpClock->delay_req_receive_time,
			&ptpClock->delay_req_send_time);

		if (rtOpts->maxDelay && /* If maxDelay is 0 then it's OFF */
		    rtOpts->offset_first_updated) {

			if ((slave_to_master_delay.nanoseconds < 0) &&
			    (abs(slave_to_master_delay.nanoseconds) > rtOpts->maxDelay)) {
				INFO("updateDelay aborted, "
				     "delay (sec: %d ns: %d) is negative\n",
				     slave_to_master_delay.seconds,
				     slave_to_master_delay.nanoseconds);
				INFO("send (sec: %d ns: %d)\n",
				     ptpClock->delay_req_send_time.seconds,
				     ptpClock->delay_req_send_time.nanoseconds);
				INFO("recv (sec: %d n	s: %d)\n",
				     ptpClock->delay_req_receive_time.seconds,
				     ptpClock->delay_req_receive_time.nanoseconds);
				goto display;
			}

			if (slave_to_master_delay.seconds && rtOpts->maxDelay) {
				INFO("updateDelay aborted, delay %d.%d greater than 1 second\n",
				     slave_to_master_delay.seconds,
				     slave_to_master_delay.nanoseconds);
				if (rtOpts->displayPackets)
					msgDump(ptpClock);
				goto display;
			}

			if (slave_to_master_delay.nanoseconds > rtOpts->maxDelay) {
				INFO("updateDelay aborted, delay %d greater than "
				     "administratively set maximum %d\n",
				     slave_to_master_delay.nanoseconds, 
				     rtOpts->maxDelay);
				if (rtOpts->displayPackets)
					msgDump(ptpClock);
				goto display;
			}
		}
	}

	/*
	 * The packet has passed basic checks, so we'll:
	 *   - update the global delaySM variable
	 *   - calculate a new filtered MPD
	 */
	if (rtOpts->offset_first_updated) {
		/*
		 * calc 'slave_to_master_delay' (Master to Slave delay is
		 * already computed in updateOffset )
		 */

		DBG("==> UpdateDelay():   %s\n",
			dump_TimeInternal2("Req_RECV:", &ptpClock->delay_req_receive_time,
			"Req_SENT:", &ptpClock->delay_req_send_time));
		
#ifdef PTPD_STATISTICS
	if (rtOpts->delaySMOutlierFilterEnabled) {
		subTime(&ptpClock->rawDelaySM, &ptpClock->delay_req_receive_time, 
			&ptpClock->delay_req_send_time);
		if(!isDoublePeircesOutlier(ptpClock->delaySMRawStats, timeInternalToDouble(&ptpClock->rawDelaySM), rtOpts->delaySMOutlierFilterThreshold)) {
			ptpClock->delaySM = ptpClock->rawDelaySM;
			ptpClock->delaySMoutlier = FALSE;
		} else {
			ptpClock->delaySMoutlier = TRUE;
			ptpClock->counters.delaySMOutliersFound++;
			if (!rtOpts->delaySMOutlierFilterDiscard)  {
				ptpClock->delaySM = doubleToTimeInternal(ptpClock->delaySMFiltered->mean);
			} else {
				    goto statistics;
			}
		}
	} else {
		subTime(&ptpClock->delaySM, &ptpClock->delay_req_receive_time, 
			&ptpClock->delay_req_send_time);
	}
#else
		subTime(&ptpClock->delaySM, &ptpClock->delay_req_receive_time, 
			&ptpClock->delay_req_send_time);
#endif
		/* update 'one_way_delay' */
		addTime(&ptpClock->meanPathDelay, &ptpClock->delaySM, 
			&ptpClock->delayMS);

		/* Substract correctionField */
		subTime(&ptpClock->meanPathDelay, &ptpClock->meanPathDelay, 
			correctionField);

		/* Compute one-way delay */
		div2Time(&ptpClock->meanPathDelay);
		
		if (ptpClock->meanPathDelay.seconds) {
			DBG("update delay: cannot filter with large OFM, "
				"clearing filter\n");
			INFO("Servo: Ignoring delayResp because of large OFM\n");
			
			FilterClear(owd_filt);
			/* revert back to previous value */
			ptpClock->meanPathDelay = prev_meanPathDelay;

			goto display;
		}


		if(ptpClock->meanPathDelay.nanoseconds < 0){
			DBG("update delay: found negative value for OWD, "
			    "so ignoring this value: %d\n",
				ptpClock->meanPathDelay.nanoseconds);
			/* revert back to previous value */
			ptpClock->meanPathDelay = prev_meanPathDelay;
#ifdef PTPD_STATISTICS
			goto statistics;
#else
			goto display;
#endif /* PTPD_STATISTICS */
		}

		{
			// TODO: remove hack
			char s_text[32];
			sprintf(s_text, "%d", rtOpts->s);
			FilterConfigure(owd_filt, "stiffness", s_text);
		}
		FilterFeed(owd_filt, &ptpClock->meanPathDelay.nanoseconds);

/* Update relevant statistics containers, feed outlier filter thresholds etc. */
#ifdef PTPD_STATISTICS
statistics:
                        if (rtOpts->delaySMOutlierFilterEnabled) {
                            double dDelaySM = timeInternalToDouble(&ptpClock->rawDelaySM);
                            /* If this is an outlier, bring it by a factor closer to mean before allowing to influence stdDev */
                            if(ptpClock->delaySMoutlier) {
				/* Allow [weight] * [deviation from mean] to influence std dev in the next outlier checks */
                            DBG("DelaySM outlier: %.09f\n", dDelaySM);
			    if((rtOpts->calibrationDelay<1) || ptpClock->isCalibrated)
                            dDelaySM = ptpClock->delaySMRawStats->meanContainer->mean + rtOpts->delaySMOutlierWeight * ( dDelaySM - ptpClock->delaySMRawStats->meanContainer->mean);
                            } 
                                        feedDoubleMovingStdDev(ptpClock->delaySMRawStats, dDelaySM);
                                        feedDoubleMovingMean(ptpClock->delaySMFiltered, timeInternalToDouble(&ptpClock->delaySM));
                                }
                        feedDoublePermanentStdDev(&ptpClock->slaveStats.owdStats, timeInternalToDouble(&ptpClock->meanPathDelay));
#endif


		DBGV("delay filter %d\n", ptpClock->meanPathDelay.nanoseconds);
	} else {
		INFO("Ignoring delayResp because we didn't receive any sync yet\n");
	}


display:
	logStatistics(rtOpts, ptpClock);

}
Beispiel #4
0
/* check and handle received messages */
void
handle(RunTimeOpts *rtOpts, PtpClock *ptpClock)
{
	int ret;
	ssize_t length;
	Boolean isFromSelf;
	TimeInternal time = { 0, 0 };

	if (!ptpClock->message_activity) {
		ret = netSelect(0, &ptpClock->netPath);
		if (ret < 0) {
			PERROR("failed to poll sockets");
			toState(PTP_FAULTY, rtOpts, ptpClock);
			return;
		} else if (!ret) {
			/* DBGV("handle: nothing\n"); */
			return;
		}
		/* else length > 0 */
	}

	DBGV("handle: something\n");

	/* TODO: this should be based on the select actual FDs (if(FD_ISSET(...)) */
	length = netRecvEvent(ptpClock->msgIbuf, &time, &ptpClock->netPath);


	if (length < 0) {
		PERROR("failed to receive on the event socket");
		toState(PTP_FAULTY, rtOpts, ptpClock);
		return;
	} else if (!length) {
		length = netRecvGeneral(ptpClock->msgIbuf, &time,
					&ptpClock->netPath);
		if (length < 0) {
			PERROR("failed to receive on the general socket");
			toState(PTP_FAULTY, rtOpts, ptpClock);
			return;
		} else if (!length)
			return;
	}

	/*
	 * make sure we use the TAI to UTC offset specified, if the master is sending the UTC_VALID bit
	 *
	 *
	 * On the slave, all timestamps that we handle here have been collected by our local clock (loopback+kernel-level timestamp)
	 * This includes delayReq just send, and delayResp, when it arrives.
	 *
	 * these are then adjusted to the same timebase of the Master (+34 leap seconds, as of 2011)
	 *
	 */
	DBGV("__UTC_offset: %d %d \n", ptpClock->currentUtcOffsetValid, ptpClock->currentUtcOffset);
	if (ptpClock->currentUtcOffsetValid) {
		time.seconds += ptpClock->currentUtcOffset;
	}

	ptpClock->message_activity = TRUE;

	if (length < HEADER_LENGTH) {
		ERROR("message shorter than header length\n");
		toState(PTP_FAULTY, rtOpts, ptpClock);
		return;
	}

	msgUnpackHeader(ptpClock->msgIbuf, &ptpClock->msgTmpHeader);

	if (ptpClock->msgTmpHeader.versionPTP != ptpClock->versionNumber) {
		DBG2("ignore version %d message\n", ptpClock->msgTmpHeader.versionPTP);
		return;
	}

	if(ptpClock->msgTmpHeader.domainNumber != ptpClock->domainNumber) {
		DBG2("ignore message from domainNumber %d\n", ptpClock->msgTmpHeader.domainNumber);
		return;
	}

	/*Spec 9.5.2.2*/	
	isFromSelf = (ptpClock->portIdentity.portNumber == ptpClock->msgTmpHeader.sourcePortIdentity.portNumber
		      && !memcmp(ptpClock->msgTmpHeader.sourcePortIdentity.clockIdentity, ptpClock->portIdentity.clockIdentity, CLOCK_IDENTITY_LENGTH));

	/*
	 * subtract the inbound latency adjustment if it is not a loop
	 *  back and the time stamp seems reasonable 
	 */
	if (!isFromSelf && time.seconds > 0)
		subTime(&time, &time, &rtOpts->inboundLatency);


#ifdef PTPD_DBG
	/* easy display of received messages */
	char *st;

	switch(ptpClock->msgTmpHeader.messageType)
	{
	case ANNOUNCE:
		st = "Announce";
		break;
	case SYNC:
		st = "Sync";
		break;
	case FOLLOW_UP:
		st = "FollowUp";
		break;
	case DELAY_REQ:
		st = "DelayReq";
		break;
	case DELAY_RESP:
		st = "DelayResp";
		break;
	default:
		st = "Unk";
		break;
	}
	DBG("      ==> %s received\n", st);
#endif

	/*
	 *  on the table below, note that only the event messsages are passed the local time,
	 *  (collected by us by loopback+kernel TS, and adjusted with UTC seconds
	 *
	 *  (SYNC / DELAY_REQ / PDELAY_REQ / PDELAY_RESP)
	 */
	switch (ptpClock->msgTmpHeader.messageType)
	{
	case ANNOUNCE:
		handleAnnounce(&ptpClock->msgTmpHeader, ptpClock->msgIbuf, 
			       length, isFromSelf, rtOpts, ptpClock);
		break;
	case SYNC:
		handleSync(&ptpClock->msgTmpHeader, ptpClock->msgIbuf, 
			   length, &time, isFromSelf, rtOpts, ptpClock);
		break;
	case FOLLOW_UP:
		handleFollowUp(&ptpClock->msgTmpHeader, ptpClock->msgIbuf, 
			       length, isFromSelf, rtOpts, ptpClock);
		break;
	case DELAY_REQ:
		handleDelayReq(&ptpClock->msgTmpHeader, ptpClock->msgIbuf, 
			       length, &time, isFromSelf, rtOpts, ptpClock);
		break;
	case PDELAY_REQ:
		handlePDelayReq(&ptpClock->msgTmpHeader, ptpClock->msgIbuf, 
				length, &time, isFromSelf, rtOpts, ptpClock);
		break;  
	case DELAY_RESP:
		handleDelayResp(&ptpClock->msgTmpHeader, ptpClock->msgIbuf, 
				length, isFromSelf, rtOpts, ptpClock);
		break;
	case PDELAY_RESP:
		handlePDelayResp(&ptpClock->msgTmpHeader, ptpClock->msgIbuf,
				 &time, length, isFromSelf, rtOpts, ptpClock);
		break;
	case PDELAY_RESP_FOLLOW_UP:
		handlePDelayRespFollowUp(&ptpClock->msgTmpHeader, 
					 ptpClock->msgIbuf, length, 
					 isFromSelf, rtOpts, ptpClock);
		break;
	case MANAGEMENT:
		handleManagement(&ptpClock->msgTmpHeader, ptpClock->msgIbuf, 
				 length, isFromSelf, rtOpts, ptpClock);
		break;
	case SIGNALING:
		handleSignaling(&ptpClock->msgTmpHeader, ptpClock->msgIbuf, 
				length, isFromSelf, rtOpts, ptpClock);
		break;
	default:
		DBG("handle: unrecognized message\n");
		break;
	}

	if (rtOpts->displayPackets)
		msgDump(ptpClock);

}