Commit ea6412b8 authored by Alessandro Rubini's avatar Alessandro Rubini
Browse files

addd PTPWRd, from svn release 916

parents
This diff is collapsed.
# Makefile for ptpd
ifeq ($(TARGET),ARM)
include ../../Makedefs
CC=$(CROSS_COMPILE_ARM)gcc
else
CC=gcc
endif
RM = rm -f
CFLAGS = -I. -O2 -I../include -DDEBUG -I../../kernel/include -I../wrsw_hal \
-I../libptpnetif -I../libwripc
CPPFLAGS = -DPTPD_NO_DAEMON -DNEW_SINGLE_WRFSM #-DPTPD_DBG
#### use new single state machine (new wrspec) #####
#CPPFLAGS += -DNEW_SINGLE_WRFSM
###################################################
#### show message content ####
CPPFLAGS += #-DPTPD_DBGMSG
#### this one shows function names ####
CPPFLAGS += #-DPTPD_DBG_S_FUN
####detailed debugging: ####
#CPPFLAGS +=-DPTPD_DBGV
#####old flags: ######
#CPPFLAGS +=-DWR_NETIF
#CPPLFAGS +=-DCONFIG_WRPTP
#CPPFLAGS += -DWR_IN_HEADER_AND_ANNBODY
LDFLAGS = -lm
ifeq ($(TARGET),ARM)
LDFLAGS +=-L../libwripc -lwripc # -L../libptpnetif -lptpnetif
endif
PROG = wr_ptpd
OBJ = ptpd.o arith.o bmc.o wr_protocol.o protocol.o display.o\
dep/msg.o dep/net.o dep/servo.o dep/startup.o dep/sys.o dep/timer.o dep/wr_servo.o ptpd_exports.o
ifeq ($(TARGET),ARM)
OBJ += ../libptpnetif/hal_client.o ../libptpnetif/ptpd_netif.o
else
OBJ += dep/ptpd_netif/ptpd_netif_mch.o
endif
HDR = ptpd.h constants.h datatypes.h \
dep/ptpd_dep.h dep/constants_dep.h dep/datatypes_dep.h \
.c.o:
$(CC) -c $(CFLAGS) $(CPPFLAGS) -o $@ $<
all: $(PROG)
$(PROG): $(OBJ)
$(CC) $(LDFLAGS) -o $@ $(OBJ)
$(OBJ): $(HDR)
pc: all
run: all
scp $(PROG) root@192.168.1.16:/tmp
scp $(PROG) root@192.168.1.6:/tmp
clean:
$(RM) $(PROG) $(OBJ)
deploy:
cp $(PROG) $(WR_INSTALL_ROOT)/bin
\ No newline at end of file
Author: Maciej Lipinski
email : maciej.lipinski@cern.ch
info : implementatin of White Rabbit extension
1)defines:
- IRQ_LESS_TIMER
if this defined, WR uses new implementation of timeouts (not using interrupt)
2)compilation flags:
- DPTPD_NO_DAEMON - original PTPd flag, for WR not tested yet without this
- DPTPD_DBGMSG - debugging of messages, it prints msgPack*() and msgUnpack*() functions
- DPTPD_DBG - most of debugging added by ML
- DPTPD_DBG_S_FUN - if defined along with DPTPD_DBG, info about calling function displayed
- DPTPD_DBGV - original detailed debugging, to detailed to be redeable
- DPTPD_DBGWR - meant to be White Rabbit debugging, but not really used :(
2) compilation
./build_t.sh run T=192.168.1.5 // this builds and runs ptpwrd on target, but without params, useless, kill it, ptpwrd will automaticly build for PC
3) runnig
- WR slave with one port on interface eth2
./ptpv2d -b eth2 -S
- WR master with one port on interface wru1
./ptpv2d -b wru1 -M
- WR multi-node, with slave port on wru1, master ports on wrd0 & wrd1
(when run with -S, WR slave is always port 1, the other ports are WR masters)
./ptpv2d -1 wru1 -2 wrd0 -3 wrd1 -S
4)Files:
PTPWRd
|-- arith.c --------------------- no WR changes
|-- bmc.c ----------------------- WR changed: a lot of WR here:
|
|-- build_p.sh ------------------ WR only:this builds PTPWR for standard PC
|-- build_t.sh ------------------ WR only:this builds PTPWR for the target and standard PC
| (just for convenience, I always need both :)
|-- clean.sh -------------------- ML: I used it for cleaning before commiting, I use Kate
| and it produces tmp files ~
|-- constants.h ----------------- WR changed: constants and enums used in WR are here
|-- datatypes.h ----------------- WR changed: here we have defined PtpClock, so all the WRPTP
| variables that are added to it + FixedDelta typedef
|-- dep
| |-- constants_dep.h --------- WR changed: no significant WR-related changes here
| |-- datatypes_dep.h --------- WR changed: here is NetPath typedef defined, and all the types
| | used in the daemon
| |-- msg.c ------------------- WR changed: White Rabbit management facilities + announce suffix +
| | other method of flipping bits (original one did not work for
| | 32 bits, aligment problems)
| |-- net.c ------------------- WR changed: Absolutelly, thoroughly changed by White Rabbit to
| | adapt to ptpd_netif interface
| |-- ptpd_dep.h -------------- WR changed: some custiom WR DBG facilities are defined here +
| | definitions of functions in /dep folder
| |-- ptpd_netif
| | |-- ptpd_netif.h -------- WR only: does what header should
| | |-- ptpd_netif_mch.c ---- WR only: network interface implemented here + interface to
| | HAL (calibration, locking) + HW timestamps
| |-- PTPWR_INFO
| |-- servo.c ----------------- WR changed: to be implemetned !!!!!!!!!
| |-- startup.c --------------- WR changed: defined new startup parametrs, implementation of multi-port
| | [allocate/free memory for many ports, done here in ptpdStartup()/ptpShutDown()]
| |-- sys.c ------------------- WR changed: here adjtimex() is commented not to mess around with the clock,
| we do it differently
| `-- timer.c ----------------- WR changed: Here WR implements interrupt-less timing (in original ptp daemon irq was used)
|-- display.c ------------------- not used in WR
|-- Doxyfile
|-- Makefile
|-- protocol.c ------------------ WR changed: WR does here a lot:
| 1) modifies UNCALIBRATED state
| 2) adds HW timestamping
| 3) messge issue/handle WR management (see handleManagement() and issueWRManagement())
| 4) implement multi-port
|-- ptpd.8
|-- ptpd.c ---------------------- WR changed: here we set some default WR params and decide if we want single- or multi-port mode
|-- ptpd.h ---------------------- no significant WR-related changes here
|-- TODO ------------------------ :)
|-- wr_protocol.c --------------- WR only: WR FSMs, HW timestamping, and other WR magic is implemented
`-- wr_protocol.h --------------- WR only: just definitions of WR functions
\ No newline at end of file
TODO High Priority
TODO:
- flipping bits in msg.c !!!!!!!
- check that all values are passed properly (especially deltas, calibaration)
- test with standard PTP
- test multiport
- move writing time to netRecvMsg, protocol.c 619 line
- set calibration period as timeout in *_CALIBRATE state
- convert HW timestamps into SW
- test multiport
- implement synchronization of calibratin between different ports
date -s "2010-08-24 14:23" -u
\ No newline at end of file
/* arith.c */
#include "ptpd.h"
void integer64_to_internalTime(Integer64 bigint,TimeInternal *internal)
{
int s_msb;
double ns_msb;
double temp;
int entire;
char *p_lsb,*p_msb;
Boolean negative = FALSE;
p_lsb=&bigint.lsb;
p_msb=&bigint.msb;
/*Test if bigint is a negative number*/
negative = ((bigint.msb & 0x80000000) == 0x80000000);
if (!negative)
{
/*Positive case*/
/*fractional nanoseconds are excluded (see 5.3.2)*/
bigint.lsb = bigint.lsb>>16;
/*copy two least significant octet of msb to most significant octet of lsb*/
*(p_lsb+2)=*p_msb;
*(p_lsb+3)=*(p_msb+1);
bigint.msb = bigint.msb>>16;
internal->nanoseconds = bigint.lsb % 1000000000;
internal->seconds = bigint.lsb / 1000000000;
/*(2^32 / 10^9) = 4,294967296*/
s_msb = 4*bigint.msb;
ns_msb = 0.294967296*(double)bigint.msb;
entire = (int)ns_msb;
s_msb += entire;
ns_msb -= entire;
ns_msb *= 1000000000;
internal->nanoseconds = (float)internal->nanoseconds + (float)ns_msb;
internal->seconds += s_msb;
normalizeTime(internal);
}
/*End of positive Case*/
else
{ /*Negative case*/
/*Take the two complement*/
bigint.lsb = ~bigint.lsb;
bigint.msb = ~bigint.msb;
if (bigint.lsb == 0xffffffff){
bigint.lsb = 0;
bigint.msb++;
}
else{
bigint.lsb++;
}
/*fractional nanoseconds are excluded (see 5.3.2)*/
bigint.lsb = bigint.lsb>>16;
/*copy two least significant octet of msb to most significant octet of lsb*/
*(p_lsb+2)=*p_msb;
*(p_lsb+3)=*(p_msb+1);
bigint.msb = bigint.msb>>16;
internal->nanoseconds = bigint.lsb % 1000000000;
internal->seconds = bigint.lsb / 1000000000;
/*(2^32 / 10^9) = 4,294967296*/
s_msb = 4*bigint.msb;
ns_msb = 0.294967296*(double)bigint.msb;
entire = (int)ns_msb;
s_msb += entire;
ns_msb -= entire;
ns_msb *= 1000000000;
internal->nanoseconds = (float)internal->nanoseconds + (float)ns_msb;
internal->seconds += s_msb;
normalizeTime(internal);
internal->nanoseconds = -internal->nanoseconds;
internal->seconds = -internal->seconds;
}
/*End of negative Case*/
}
void fromInternalTime(TimeInternal *internal, Timestamp *external)
{
/*fromInternalTime is only used to convert time given by the system to a timestamp
* As a consequence, no negative value can normally be found in (internal)
* Note that offsets are also represented with TimeInternal structure, and can be negative,
* but offset are never convert into Timestamp so there is no problem here.*/
if ((internal->seconds & ~INT_MAX) || (internal->nanoseconds & ~INT_MAX))
{
DBGNPI("Negative value canno't be converted into timestamp \n");
return;
}
else
{
external->secondsField.lsb = internal->seconds;
external->nanosecondsField = internal->nanoseconds;
external->secondsField.msb = 0;
}
}
void toInternalTime(TimeInternal *internal, Timestamp *external)
{
/*Program will not run after 2038...*/
if (external->secondsField.lsb < INT_MAX)
{
internal->seconds = external->secondsField.lsb;
internal->nanoseconds = external->nanosecondsField;
}
else
{
DBGNPI("Clock servo canno't be executed : seconds field is higher than signed integer (32bits) \n");
return;
}
}
void normalizeTime(TimeInternal *r)
{
r->seconds += r->nanoseconds/1000000000;
r->nanoseconds -= r->nanoseconds/1000000000*1000000000;
if(r->seconds > 0 && r->nanoseconds < 0)
{
r->seconds -= 1;
r->nanoseconds += 1000000000;
}
else if(r->seconds < 0 && r->nanoseconds > 0)
{
r->seconds += 1;
r->nanoseconds -= 1000000000;
}
}
void addTime(TimeInternal *r, TimeInternal *x, TimeInternal *y)
{
r->seconds = x->seconds + y->seconds;
r->nanoseconds = x->nanoseconds + y->nanoseconds;
normalizeTime(r);
}
void subTime(TimeInternal *r, TimeInternal *x, TimeInternal *y)
{
r->seconds = x->seconds - y->seconds;
r->nanoseconds = x->nanoseconds - y->nanoseconds;
normalizeTime(r);
}
/* bmc.c */
#include "ptpd.h"
/* Init ptpClock with run time values (initialization constants are in constants.h)*/
void initData(RunTimeOpts *rtOpts, PtpClock *ptpClock)
{
int i,j;
j=0;
DBG("initData\n");
/* Default data set */
ptpClock->twoStepFlag = TWO_STEP_FLAG;
/*init clockIdentity with MAC address and 0xFF and 0xFE. see spec 7.5.2.2.2*/
for (i=0;i<CLOCK_IDENTITY_LENGTH;i++)
{
if (i==3) ptpClock->clockIdentity[i]=0xFF;
else if (i==4) ptpClock->clockIdentity[i]=0xFE;
else if (i == 5 && rtOpts->overrideClockIdentity != 0x0)
/*
* temporary hack to run the daemon on lo (single interface)
*/
ptpClock->clockIdentity[i] = rtOpts->overrideClockIdentity;
else
{
ptpClock->clockIdentity[i]=ptpClock->port_uuid_field[j];
j++;
}
}
ptpClock->numberPorts = rtOpts->portNumber;
ptpClock->clockQuality.clockAccuracy = rtOpts->clockQuality.clockAccuracy;
ptpClock->clockQuality.offsetScaledLogVariance = rtOpts->clockQuality.offsetScaledLogVariance;
/* If priority not defined at the runtime, set it high for the WR master*/
if(rtOpts->priority1 == DEFAULT_PRIORITY1 && ptpClock->wrNodeMode == WR_MASTER)
ptpClock->priority1 = WR_MASTER_PRIORITY1;
else
ptpClock->priority1 = rtOpts->priority1;
ptpClock->priority2 = rtOpts->priority2;
ptpClock->domainNumber = rtOpts->domainNumber;
ptpClock->slaveOnly = rtOpts->slaveOnly;
if(rtOpts->slaveOnly)
rtOpts->clockQuality.clockClass = 255;
ptpClock->clockQuality.clockClass = rtOpts->clockQuality.clockClass;
/*Port configuration data set */
/*PortIdentity Init (portNumber = 1 for an ardinary clock spec 7.5.2.3)*/
memcpy(ptpClock->portIdentity.clockIdentity,ptpClock->clockIdentity,CLOCK_IDENTITY_LENGTH);
ptpClock->logMinDelayReqInterval = DEFAULT_DELAYREQ_INTERVAL;
ptpClock->peerMeanPathDelay.seconds = 0;
ptpClock->peerMeanPathDelay.nanoseconds = 0;
ptpClock->logAnnounceInterval = rtOpts->announceInterval;
ptpClock->announceReceiptTimeout = DEFAULT_ANNOUNCE_RECEIPT_TIMEOUT;
ptpClock->logSyncInterval = rtOpts->syncInterval;
ptpClock->delayMechanism = DEFAULT_DELAY_MECHANISM;
ptpClock->logMinPdelayReqInterval = DEFAULT_PDELAYREQ_INTERVAL;
ptpClock->versionNumber = VERSION_PTP;
/*Initialize seed for random number used with Announce Timeout (spec 9.2.6.11)*/
srand(time(NULL));
ptpClock->R = getRand();
/*Init other stuff*/
ptpClock->number_foreign_records = 0;
ptpClock->max_foreign_records = rtOpts->max_foreign_records;
if(ptpClock->wrNodeMode != NON_WR)
{
/* we want White Rabbit daemon, so here we are */
/* setting appropriate clock class for WR node
* if the class was not set by the user (is default)*/
if(rtOpts->clockQuality.clockClass == DEFAULT_CLOCK_CLASS)
{
if( ptpClock->wrNodeMode == WR_MASTER)
ptpClock->clockQuality.clockClass = WR_MASTER_CLOCK_CLASS;
else if(ptpClock->wrNodeMode == WR_SLAVE)
ptpClock->clockQuality.clockClass = WR_SLAVE_CLOCK_CLASS;
}
else
ptpClock->clockQuality.clockClass = rtOpts->clockQuality.clockClass;
// if(ptpClock->portIdentity.portNumber == 1 )
// {
// /* there can be only one slave (not entirely
// * true for WR, but must be enough for the time being)
// * so the first port is the one which can be WR Slave
// */
// ptpClock->wrNodeMode = rtOpts->wrNodeMode;
// }
// else
// {
// /* All the other ports except port = 1 are
// * WR Masters and no discussion about that
// */
// ptpClock->wrNodeMode = WR_MASTER;
// }
}
else
{
/* normal PTP daemon on all ports */
//ptpClock->wrNodeMode = NON_WR;
}
ptpClock->isWRmode = FALSE;
/*this one should be set at runtime*/
ptpClock->isCalibrated = FALSE;
ptpClock->deltaTx.scaledPicoseconds.lsb = 0;
ptpClock->deltaTx.scaledPicoseconds.msb = 0;
ptpClock->deltaRx.scaledPicoseconds.lsb = 0;
ptpClock->deltaRx.scaledPicoseconds.msb = 0;
/**/
//ptpClock->tx_tag = 0;
//ptpClock->new_tx_tag_read = FALSE;
ptpClock->pending_tx_ts = FALSE;
ptpClock->pending_Synch_tx_ts = 0;
ptpClock->pending_DelayReq_tx_ts = 0;
ptpClock->pending_PDelayReq_tx_ts = 0;
ptpClock->pending_PDelayResp_tx_ts = 0;
#ifdef NEW_SINGLE_WRFSM
ptpClock->wrPortState = WRS_IDLE;
#else
ptpClock->wrPortState = PTPWR_IDLE;
#endif
ptpClock->calibrationPeriod = rtOpts->calibrationPeriod;
ptpClock->calibrationPattern = rtOpts->calibrationPattern;
ptpClock->calibrationPatternLen = rtOpts->calibrationPatternLen;
for(i = 0; i < WR_TIMER_ARRAY_SIZE;i++)
{
ptpClock->wrTimeouts[i] = WR_DEFAULT_STATE_TIMEOUT_MS;
}
// fixme: locking timeout should be bigger
ptpClock->wrTimeouts[WRS_S_LOCK] = 10000;
ptpClock->wrTimeouts[WRS_S_LOCK_1] = 10000;
ptpClock->wrTimeouts[WRS_S_LOCK_2] = 10000;
}
/*Local clock is becoming Master. Table 13 (9.3.5) of the spec.*/
void m1(PtpClock *ptpClock)
{
DBG("[%s]\n",__func__);
/*Current data set update*/
ptpClock->stepsRemoved = 0;
ptpClock->offsetFromMaster.nanoseconds = 0;
ptpClock->offsetFromMaster.seconds = 0;
ptpClock->meanPathDelay.nanoseconds = 0;
ptpClock->meanPathDelay.seconds = 0;
/*Parent data set*/
memcpy(ptpClock->parentPortIdentity.clockIdentity,ptpClock->clockIdentity,CLOCK_IDENTITY_LENGTH);
ptpClock->parentPortIdentity.portNumber = 0;
ptpClock->parentStats = DEFAULT_PARENTS_STATS;
ptpClock->observedParentClockPhaseChangeRate = 0;
ptpClock->observedParentOffsetScaledLogVariance = 0;
memcpy(ptpClock->grandmasterIdentity,ptpClock->clockIdentity,CLOCK_IDENTITY_LENGTH);
ptpClock->grandmasterClockQuality.clockAccuracy = ptpClock->clockQuality.clockAccuracy;
ptpClock->grandmasterClockQuality.clockClass = ptpClock->clockQuality.clockClass;
ptpClock->grandmasterClockQuality.offsetScaledLogVariance = ptpClock->clockQuality.offsetScaledLogVariance;
ptpClock->grandmasterPriority1 = ptpClock->priority1;
ptpClock->grandmasterPriority2 = ptpClock->priority2;
/*White Rabbit*/
ptpClock->grandmasterWrNodeMode = ptpClock->wrNodeMode;
ptpClock->grandmasterIsWRnode = (ptpClock->wrNodeMode != NON_WR) ;
ptpClock->grandmasterIsWRmode = ptpClock->isWRmode;
ptpClock->grandmasterIsCalibrated = ptpClock->isCalibrated;
/*Time Properties data set*/
ptpClock->timeSource = INTERNAL_OSCILLATOR;
}
/*Local clock is synchronized to Ebest Table 16 (9.3.5) of the spec*/
void s1(MsgHeader *header,MsgAnnounce *announce,PtpClock *ptpClock)
{
/*Current DS*/
ptpClock->stepsRemoved = announce->stepsRemoved + 1;
/*Parent DS*/
memcpy(ptpClock->parentPortIdentity.clockIdentity,header->sourcePortIdentity.clockIdentity,CLOCK_IDENTITY_LENGTH);
ptpClock->parentPortIdentity.portNumber = header->sourcePortIdentity.portNumber;
memcpy(ptpClock->grandmasterIdentity,announce->grandmasterIdentity,CLOCK_IDENTITY_LENGTH);
ptpClock->grandmasterClockQuality.clockAccuracy = announce->grandmasterClockQuality.clockAccuracy;
ptpClock->grandmasterClockQuality.clockClass = announce->grandmasterClockQuality.clockClass;
ptpClock->grandmasterClockQuality.offsetScaledLogVariance = announce->grandmasterClockQuality.offsetScaledLogVariance;
ptpClock->grandmasterPriority1 = announce->grandmasterPriority1;
ptpClock->grandmasterPriority2 = announce->grandmasterPriority2;
/*White Rabbit*/
ptpClock->grandmasterIsWRnode = ((announce->wr_flags & WR_NODE_MODE) != NON_WR);
ptpClock->grandmasterIsWRmode = ((announce->wr_flags & WR_IS_WR_MODE) == WR_IS_WR_MODE);
ptpClock->grandmasterIsCalibrated = ((announce->wr_flags & WR_IS_CALIBRATED) == WR_IS_CALIBRATED);
ptpClock->grandmasterWrNodeMode = announce->wr_flags & WR_NODE_MODE;
/*Timeproperties DS*/
ptpClock->currentUtcOffset = announce->currentUtcOffset;
ptpClock->currentUtcOffsetValid = ((header->flagField[1] & 0x04) == 0x04); //"Valid" is bit 2 in second octet of flagfield
ptpClock->leap59 = ((header->flagField[1] & 0x02) == 0x02);
ptpClock->leap61 = ((header->flagField[1] & 0x01) == 0x01);
ptpClock->timeTraceable = ((header->flagField[1] & 0x10) == 0x10);
ptpClock->frequencyTraceable = ((header->flagField[1] & 0x20) == 0x20);
ptpClock->ptpTimescale = ((header->flagField[1] & 0x08) == 0x08);
ptpClock->timeSource = announce->timeSource;
}
/*Copy local data set into header and announce message. 9.3.4 table 12*/
void copyD0(MsgHeader *header, MsgAnnounce *announce, PtpClock *ptpClock)
{
announce->grandmasterPriority1 = ptpClock->priority1;
memcpy(announce->grandmasterIdentity,ptpClock->clockIdentity,CLOCK_IDENTITY_LENGTH);
announce->grandmasterClockQuality.clockClass = ptpClock->clockQuality.clockClass;
announce->grandmasterClockQuality.clockAccuracy = ptpClock->clockQuality.clockAccuracy;
announce->grandmasterClockQuality.offsetScaledLogVariance = ptpClock->clockQuality.offsetScaledLogVariance;
announce->grandmasterPriority2 = ptpClock->priority2;
announce->stepsRemoved = 0;
memcpy(header->sourcePortIdentity.clockIdentity,ptpClock->clockIdentity,CLOCK_IDENTITY_LENGTH);
/*White Rabbit*/
announce->wr_flags = (announce->wr_flags | ptpClock->wrNodeMode) & WR_NODE_MODE ;
announce->wr_flags = announce->wr_flags | ptpClock->isCalibrated << 2;
announce->wr_flags = announce->wr_flags | ptpClock->isWRmode << 3;
}
/*Data set comparison bewteen two foreign masters (9.3.4 fig 27)
* return similar to memcmp() */
Integer8 bmcDataSetComparison(MsgHeader *headerA, MsgAnnounce *announceA,
MsgHeader *headerB,MsgAnnounce *announceB,PtpClock *ptpClock)
{
DBGV("Data set comparison \n");
short comp = 0;
if(announceA->wr_flags & WR_MASTER)
DBG("A is WR_MASTER\n");
else if(announceA->wr_flags & WR_SLAVE)
DBG("A is WR_SLAVE\n");
else
DBG("A is not WR\n");
if(announceB->wr_flags & WR_MASTER)
DBG("B is WR_MASTER\n");
else if(announceB->wr_flags & WR_SLAVE)
DBG("B is WR_SLAVE\n");
else
DBG("B is not WR\n");
/*white rabbit staff*/
if(announceA->wr_flags & WR_MASTER && !(announceB->wr_flags & WR_MASTER))
{
DBG("A better B [White Rabbit]\n");
return -1;
}
if(announceB->wr_flags & WR_MASTER && !(announceA->wr_flags & WR_MASTER))
{
DBG("B better A [White Rabbit]\n");
return 1;
}
/*Identity comparison*/
if (!memcmp(announceA->grandmasterIdentity,announceB->grandmasterIdentity,CLOCK_IDENTITY_LENGTH))
{
//Algorithm part2 Fig 28
if (announceA->stepsRemoved > announceB->stepsRemoved+1)
{
return 1;// B better than A
}
else if (announceB->stepsRemoved > announceA->stepsRemoved+1)
{
return -1;//A better than B
}
else //A within 1 of B
{
if (announceA->stepsRemoved > announceB->stepsRemoved)
{
if (!memcmp(headerA->sourcePortIdentity.clockIdentity,ptpClock->parentPortIdentity.clockIdentity,CLOCK_IDENTITY_LENGTH))
{
DBG("Sender=Receiver : Error -1");
return 0;
}
else
{
return 1;
}
}
else if (announceB->stepsRemoved > announceA->stepsRemoved)
{
if (!memcmp(headerB->sourcePortIdentity.clockIdentity,ptpClock->parentPortIdentity.clockIdentity,CLOCK_IDENTITY_LENGTH))
{
DBG("Sender=Receiver : Error -1");
return 0;
}
else
{
return -1;
}
}
else // steps removed A = steps removed B
{
if (!memcmp(headerA->sourcePortIdentity.clockIdentity,headerB->sourcePortIdentity.clockIdentity,CLOCK_IDENTITY_LENGTH))
{
DBG("Sender=Receiver : Error -2");
return 0;
}
else if ((memcmp(headerA->sourcePortIdentity.clockIdentity,headerB->sourcePortIdentity.clockIdentity,CLOCK_IDENTITY_LENGTH))<0)
{
return -1;
}
else
{
return 1;
}
}
}
}
else //GrandMaster are not identical
{
if(announceA->grandmasterPriority1 == announceB->grandmasterPriority1)
{
if (announceA->grandmasterClockQuality.clockClass == announceB->grandmasterClockQuality.clockClass)
{
if (announceA->grandmasterClockQuality.clockAccuracy == announceB->grandmasterClockQuality.clockAccuracy)
{
if (announceA->grandmasterClockQuality.offsetScaledLogVariance == announceB->grandmasterClockQuality.offsetScaledLogVariance)
{
if (announceA->grandmasterPriority2 == announceB->grandmasterPriority2)
{
comp = memcmp(announceA->grandmasterIdentity,announceB->grandmasterIdentity,CLOCK_IDENTITY_LENGTH);
if (comp < 0)
{
return -1;
}
else if (comp > 0)
{
return 1;
}
else
{
return 0;
}
}
else //Priority2 are not identical
{
comp =memcmp(&announceA->grandmasterPriority2,&announceB->grandmasterPriority2,1);
if (comp < 0)
{
return -1;
}
else if (comp > 0)
{
return 1;
}
else
{
return 0;
}
}
}
else //offsetScaledLogVariance are not identical
{
comp= memcmp(&announceA->grandmasterClockQuality.clockClass,&announceB->grandmasterClockQuality.clockClass,1);
if (comp < 0)
{
return -1;
}
else if (comp > 0)
{
return 1;
}
else
{
return 0;
}
}
}
else // Accuracy are not identitcal
{
comp = memcmp(&announceA->grandmasterClockQuality.clockAccuracy,&announceB->grandmasterClockQuality.clockAccuracy,1);
if (comp < 0)
{
return -1;
}
else if (comp > 0)
{
return 1;
}
else
{
return 0;
}
}
}
else //ClockClass are not identical
{
comp = memcmp(&announceA->grandmasterClockQuality.clockClass,&announceB->grandmasterClockQuality.clockClass,1);
if (comp < 0)
{
return -1;
}
else if (comp > 0)
{
return 1;
}
else
{
return 0;
}
}
}
else // Priority1 are not identical
{
comp = memcmp(&announceA->grandmasterPriority1,&announceB->grandmasterPriority1,1);
if (comp < 0)
{
return -1;
}
else if (comp > 0)
{
return 1;
}
else
{
return 0;
}
}
}
}
/*State decision algorithm 9.3.3 Fig 26*/
UInteger8 bmcStateDecision (MsgHeader *header,MsgAnnounce *announce,RunTimeOpts *rtOpts,PtpClock *ptpClock)
{
if (rtOpts->slaveOnly)
{
s1(header,announce,ptpClock);
return PTP_SLAVE;
}
if ((!ptpClock->number_foreign_records) && (ptpClock->portState == PTP_LISTENING))
{
return PTP_LISTENING;
}
copyD0(&ptpClock->msgTmpHeader,&ptpClock->msgTmp.announce,ptpClock);
if (ptpClock->clockQuality.clockClass < 128)
{
if ((bmcDataSetComparison(&ptpClock->msgTmpHeader,&ptpClock->msgTmp.announce,header,announce,ptpClock)<0))
{
m1(ptpClock);
return PTP_MASTER;
}
else if ((bmcDataSetComparison(&ptpClock->msgTmpHeader,&ptpClock->msgTmp.announce,header,announce,ptpClock)>0))
{
s1(header,announce,ptpClock);
return PTP_PASSIVE;
}
else
{
DBG("Error in bmcDataSetComparison..\n");
}
}
else
{
if ((bmcDataSetComparison(&ptpClock->msgTmpHeader,&ptpClock->msgTmp.announce,header,announce,ptpClock))<0)
{
m1(ptpClock);
return PTP_MASTER;
}
else if ((bmcDataSetComparison(&ptpClock->msgTmpHeader,&ptpClock->msgTmp.announce,header,announce,ptpClock)>0))
{
s1(header,announce,ptpClock);
return PTP_SLAVE;
}
else
{
DBG("Error in bmcDataSetComparison..\n");
}
}
}
UInteger8 bmc(ForeignMasterRecord *foreignMaster,RunTimeOpts *rtOpts ,PtpClock *ptpClock )
{
DBG("Best Master Clock Algorithm @ working\n");
Integer16 i,best;
if (!ptpClock->number_foreign_records)
{
if (ptpClock->portState == PTP_MASTER)
{
m1(ptpClock);
return ptpClock->portState;
}
}
for (i=1,best = 0; i<ptpClock->number_foreign_records;i++)
{
if ((bmcDataSetComparison(&foreignMaster[i].header,&foreignMaster[i].announce,
&foreignMaster[best].header,&foreignMaster[best].announce,ptpClock)) < 0)
{
best = i;
}
}
DBG("Best record : %d \n",best);
ptpClock->foreign_record_best = best;
return bmcStateDecision(&foreignMaster[best].header,&foreignMaster[best].announce,rtOpts,ptpClock);
}
#!/bin/sh
make clean
make
#!/bin/sh
make clean
make TARGET=ARM $1 $2 $3 $4
#make clean
#make
#!/bin/sh
make TARGET=ARM clean
rm *~
rm */*~
rm */*/*~
echo 'cleaned to be committed'
#ifndef CONSTANTS_H_
#define CONSTANTS_H_
/**
*\file
* \brief Default values and constants used in ptpdv2
*
* This header file includes all default values used during initialization
* and enumeration defined in the spec
*/
#include "ptpd_netif.h"
#define MANUFACTURER_ID \
"MaceG VanKempen;2.0.0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
/* implementation specific constants */
#define DEFAULT_INBOUND_LATENCY 0 /* in nsec */
#define DEFAULT_OUTBOUND_LATENCY 0 /* in nsec */
#define DEFAULT_NO_RESET_CLOCK FALSE
#define DEFAULT_DOMAIN_NUMBER 0
#define DEFAULT_DELAY_MECHANISM E2E //P2P //Note that end to end mechanism is not implemented.
#define DEFAULT_AP 10
#define DEFAULT_AI 1000
#define DEFAULT_DELAY_S 6
#define DEFAULT_ANNOUNCE_INTERVAL 1 //0 in 802.1AS
#define DEFAULT_UTC_OFFSET 0
#define DEFAULT_UTC_VALID FALSE
#define DEFAULT_PDELAYREQ_INTERVAL 1 //-4 in 802.1AS
#define DEFAULT_DELAYREQ_INTERVAL 0
#define DEFAULT_SYNC_INTERVAL 0 //-7 in 802.1AS
#define DEFAULT_SYNC_RECEIPT_TIMEOUT 3
#define DEFAULT_ANNOUNCE_RECEIPT_TIMEOUT 2 //6 // 3 by default
#define DEFAULT_QUALIFICATION_TIMEOUT 2
#define DEFAULT_FOREIGN_MASTER_TIME_WINDOW 4
#define DEFAULT_FOREIGN_MASTER_THRESHOLD 2
#define DEFAULT_CLOCK_CLASS 100
#define DEFAULT_CLOCK_ACCURACY 0xFE
#define DEFAULT_PRIORITY1 100
#define DEFAULT_PRIORITY2 100
#define DEFAULT_CLOCK_VARIANCE -4000 //To be determined in 802.1AS...so same value of ptpdv1 is used
#define DEFAULT_MAX_FOREIGN_RECORDS 5
#define DEFAULT_PARENTS_STATS FALSE
/* features, only change to refelect changes in implementation */
#define NUMBER_PORTS 1
#define VERSION_PTP 2
#define TWO_STEP_FLAG 0x02
#define BOUNDARY_CLOCK FALSE
#define SLAVE_ONLY FALSE
#define NO_ADJUST FALSE
/** \name Packet length
Minimal length values for each message.
If TLV used length could be higher.*/
/**\{*/
#define HEADER_LENGTH 34
#define ANNOUNCE_LENGTH 64
#define SYNC_LENGTH 44
#define FOLLOW_UP_LENGTH 44
#define PDELAY_REQ_LENGTH 54
#define DELAY_REQ_LENGTH 44
#define DELAY_RESP_LENGTH 54
#define PDELAY_RESP_LENGTH 54
#define PDELAY_RESP_FOLLOW_UP_LENGTH 54
#define MANAGEMENT_LENGTH 48
/** \}*/
/** \name White Rabbit staff
Here comes all the constants needed in White Rabbit extension
.*/
/**\{*/
/*White Rabbit staff*/
/*
* if this defined, WR uses new implementation of timeouts (not using interrupt)
*/
#define IRQ_LESS_TIMER
#define WR_NODE 0x80
#define WR_IS_CALIBRATED 0x04
#define WR_IS_WR_MODE 0x08
#define WR_NODE_MODE 0x03
#define WR_TLV_TYPE 0x2004
#define WR_MASTER_PRIORITY1 6
#define WR_DEFAULT_CAL_PERIOD 3000 //[us]
#define WR_DEFAULT_CAL_PATTERN 0x3E0 //1111100000
#define WR_DEFAULT_CAL_PATTERN_LEN 0xA //10 bits
#define WR_DEFAULT_STATE_TIMEOUT_MS 500 //[ms]
#define WR_DEFAULT_STATE_REPEAT 3
#define WR_DEFAULT_INIT_REPEAT 3
/*White Rabbit package Size*/
#ifdef WR_IN_HEADER_AND_ANNBODY
# define WR_ANNOUNCE_TLV_LENGTH 0
#else
# define WR_ANNOUNCE_TLV_LENGTH 6
#endif
#define WR_ANNOUNCE_LENGTH (ANNOUNCE_LENGTH + WR_ANNOUNCE_TLV_LENGTH)
#define WR_MANAGEMENT_TLV_LENGTH 6
#define WR_MANAGEMENT_LENGTH (MANAGEMENT_LENGTH + WR_MANAGEMENT_TLV_LENGTH)
#define MAX_PORT_NUMBER 16
#define MIN_PORT_NUMBER 1
#define WR_PORT_NUMBER 10
#define WR_SLAVE_CLOCK_CLASS 248
#define WR_MASTER_CLOCK_CLASS 5
/** \}*/
/*Enumeration defined in tables of the spec*/
/**
* \brief Domain Number (Table 2 in the spec)*/
enum {
DFLT_DOMAIN_NUMBER = 0, ALT1_DOMAIN_NUMBER, ALT2_DOMAIN_NUMBER, ALT3_DOMAIN_NUMBER
};
/**
* \brief Network Protocol (Table 3 in the spec)*/
enum {
UDP_IPV4=1,UDP_IPV6,IEE_802_3,DeviceNet,ControlNet,PROFINET
};
/**
* \brief Time Source (Table 7 in the spec)*/
enum {
ATOMIC_CLOCK=0x10,GPS=0x20,TERRESTRIAL_RADIO=0x30,PTP=0x40,NTP=0x50,HAND_SET=0x60,OTHER=0x90,INTERNAL_OSCILLATOR=0xA0
};
/**
* \brief PTP State (Table 8 in the spec)*/
enum {
INITIALIZING=1, FAULTY,DISABLED,LISTENING,PRE_MASTER,MASTER,PASSIVE,UNCALIBRATED,SLAVE
};
/**
* \brief Delay mechanism (Table 9 in the spec)*/
enum {
E2E=1,P2P=2,DELAY_DISABLED=0xFE
};
/**
* \brief PTP timers
*/
enum {
PDELAYREQ_INTERVAL_TIMER=0,/**<\brief Timer handling the PdelayReq Interval*/
DELAYREQ_INTERVAL_TIMER,/**<\brief Timer handling the delayReq Interva*/
SYNC_INTERVAL_TIMER,/**<\brief Timer handling Interval between master sends two Syncs messages */
ANNOUNCE_RECEIPT_TIMER,/**<\brief Timer handling announce receipt timeout*/
ANNOUNCE_INTERVAL_TIMER, /**<\brief Timer handling interval before master sends two announce messages*/
TIMER_ARRAY_SIZE /* this one is non-spec */
};
/**
* \brief PTP states
*/
enum {
PTP_INITIALIZING=0, PTP_FAULTY, PTP_DISABLED,
PTP_LISTENING, PTP_PRE_MASTER, PTP_MASTER,
PTP_PASSIVE, PTP_UNCALIBRATED, PTP_SLAVE
};
/**
* \brief PTP Messages
*/
enum {
SYNC=0x0,
DELAY_REQ,
PDELAY_REQ,
PDELAY_RESP,
FOLLOW_UP=0x8,
DELAY_RESP,
PDELAY_RESP_FOLLOW_UP,
ANNOUNCE,
SIGNALING,
MANAGEMENT,
};
enum {
PTP_ETHER,PTP_DEFAULT
};
/**
* \brief Indicates if a node runs as White Rabbit, and what kind (master/slave) [White Rabbit]
*/
/*White Rabbit node */
enum{
NON_WR = 0x0,
WR_SLAVE = PTPD_NETIF_RX, // just for convenient useage with ptpd_netif interface
WR_MASTER = PTPD_NETIF_TX, // just for convenient useage with ptpd_netif interface
};
/**
* \brief Values of Management Actions (extended for WR), see table 38 [White Rabbit]
*/
enum{
GET,
SET,
RESPONSE,
COMMAND,
ACKNOWLEDGE,
WR_CMD, //White Rabbit
};
#ifdef NEW_SINGLE_WRFSM
/**
* \brief WR PTP states (new, single FSM) [White Rabbit]
*/
enum {
WRS_PRESENT = 0, WRS_S_LOCK, WRS_M_LOCK, WRS_LOCKED,
WRS_REQ_CALIBRATION, WRS_CALIBRATED, WRS_RESP_CALIB_REQ ,WRS_WR_LINK_ON,
/*
each WR main state (except IDLE) has an associated timetout
we use state names to manage timeouts as well
*/
WR_TIMER_ARRAY_SIZE, //number of states which has timeouts
WRS_IDLE,
/* here are substates*/
WRS_S_LOCK_1,
WRS_S_LOCK_2,
WRS_REQ_CALIBRATION_1,
WRS_REQ_CALIBRATION_2,
WRS_REQ_CALIBRATION_3,
WRS_RESP_CALIB_REQ_1,
WRS_RESP_CALIB_REQ_2,
WRS_RESP_CALIB_REQ_3,
};
/**
* \brief White Rabbit commands (for new implementation, single FSM), see table 38 [White Rabbit]
*/
enum{
NULL_MANAGEMENT = 0x0000,
SLAVE_PRESENT = 0x6000,
LOCK,
LOCKED,
CALIBRATE,
CALIBRATED,
WR_MODE_ON,
};
#define SEND_CALIBRATION_PATTERN 0X0001
#define NOT_SEND_CALIBRATION_PATTERN 0X0000
#else
/**
* \brief WR PTP states (old wr fsm, two separate FSMs) [White Rabbit]
*/
enum {
PTPWR_PRESENT = 0, PTPWR_LOCK, PTPWR_LOCKED,
PTPWR_M_CALIBRATE, PTPWR_S_CALIBRATE, PTPWR_CAL_COMPLETED,
/*
each WR main state (except IDLE) has an associated timetout
we use state names to manage timeouts as well
*/
WR_TIMER_ARRAY_SIZE, //number of states which has timeouts
PTPWR_IDLE,
/* here are substates*/
PTPWR_LOCK_1,
PTPWR_LOCK_2,
PTPWR_M_CALIBRATE_1,
PTPWR_M_CALIBRATE_2,
PTPWR_S_CALIBRATE_1,
PTPWR_S_CALIBRATE_2,
PTPWR_S_CALIBRATE_3,
};
/**
* \brief White Rabbit commands, see table 38 [White Rabbit]
*/
enum{
NULL_MANAGEMENT = 0x0000,
SLAVE_PRESENT = 0x6000,
LOCK,
LOCKED,
MASTER_CALIBRATE,
MASTER_CALIBRATED,
SLAVE_CALIBRATE,
SLAVE_CALIBRATED,
WR_MODE_ON,
};
#endif
#endif /*CONSTANTS_H_*/
#ifndef DATATYPES_H_
#define DATATYPES_H_
/*Struct defined in spec*/
/**
*\file
* \brief Main structures used in ptpdv2
*
* This header file defines structures defined by the spec,
main program data structure, and all messages structures
*/
/**
* \brief The TimeInterval type represents time intervals
*/
typedef struct {
Integer64 scaledNanoseconds;
} TimeInterval;
/**
* \brief The Fixed Delay type represents time intervals [White Rabbit]
*/
typedef struct {
UInteger64 scaledPicoseconds;
} FixedDelta;
/**
* \brief The Timestamp type represents a positive time with respect to the epoch
*/
typedef struct {
UInteger48 secondsField;
UInteger32 nanosecondsField;
} Timestamp;
/**
* \brief The ClockIdentity type identifies a clock
*/
typedef Octet ClockIdentity[CLOCK_IDENTITY_LENGTH];
/**
* \brief The PortIdentity identifies a PTP port.
*/
typedef struct {
ClockIdentity clockIdentity;
UInteger16 portNumber;
} PortIdentity;
/**
* \brief The PortAdress type represents the protocol address of a PTP port
*/
typedef struct {
Enumeration16 networkProtocol;
UInteger16 adressLength;
Octet* adressField;
} PortAdress;
/**
* \brief The ClockQuality represents the quality of a clock
*/
typedef struct {
UInteger8 clockClass;
Enumeration8 clockAccuracy;
UInteger16 offsetScaledLogVariance;
} ClockQuality;
/**
* \brief The TLV type represents TLV extension fields
*/
typedef struct {
Enumeration16 tlvType;
UInteger16 lengthField;
Octet* valueField;
} TLV;
/**
* \brief The PTPText data type is used to represent textual material in PTP messages
*/
typedef struct {
UInteger8 lengthField;
Octet* textField;
} PTPText;
/**
* \brief The FaultRecord type is used to construct fault logs
*/
typedef struct {
UInteger16 faultRecordLength;
Timestamp faultTime;
Enumeration8 severityCode;
PTPText faultName;
PTPText faultValue;
PTPText faultDescription;
} FaultRecord;
/**
* \brief The common header for all PTP messages (Table 18 of the spec)
*/
/* Message header */
typedef struct {
Nibble transportSpecific;
Enumeration4 messageType;
UInteger4 versionPTP;
UInteger16 messageLength;
UInteger8 domainNumber;
Octet flagField[2];
Integer64 correctionfield;
PortIdentity sourcePortIdentity;
UInteger16 sequenceId;
UInteger8 controlField;
Integer8 logMessageInterval;
} MsgHeader;
/**
* \brief TLV sufixed to Announce message for White Rabbit (WR extension)
*/
/*Announce Message */
typedef Octet AnnounceWRtlv[WR_ANNOUNCE_TLV_LENGTH];
/**
* \brief Announce message fields (Table 25 of the spec)[White Rabbit]
*/
/*Announce Message */
typedef struct {
Timestamp originTimestamp;
Integer16 currentUtcOffset;
UInteger8 grandmasterPriority1;
ClockQuality grandmasterClockQuality;
UInteger8 grandmasterPriority2;
ClockIdentity grandmasterIdentity;
UInteger16 stepsRemoved;
Enumeration8 timeSource;
//White Rabbit flags
UInteger8 wr_flags;
}MsgAnnounce;
/**
* \brief Sync message fields (Table 26 of the spec)
*/
/*Sync Message */
typedef struct {
Timestamp originTimestamp;
}MsgSync;
/**
* \brief DelayReq message fields (Table 26 of the spec)
*/
/*DelayReq Message */
typedef struct {
Timestamp originTimestamp;
}MsgDelayReq;
/**
* \brief DelayResp message fields (Table 30 of the spec)
*/
/*delayResp Message*/
typedef struct {
Timestamp receiveTimestamp;
PortIdentity requestingPortIdentity;
}MsgDelayResp;
/**
* \brief FollowUp message fields (Table 27 of the spec)
*/
/*Follow-up Message*/
typedef struct {
Timestamp preciseOriginTimestamp;
}MsgFollowUp;
/**
* \brief PDelayReq message fields (Table 29 of the spec)
*/
/*PdelayReq Message*/
typedef struct {
Timestamp originTimestamp;
}MsgPDelayReq;
/**
* \brief PDelayResp message fields (Table 30 of the spec)
*/
/*PdelayResp Message*/
typedef struct {
Timestamp requestReceiptTimestamp;
PortIdentity requestingPortIdentity;
}MsgPDelayResp;
/**
* \brief PDelayRespFollowUp message fields (Table 31 of the spec)
*/
/*PdelayRespFollowUp Message*/
typedef struct {
Timestamp responseOriginTimestamp;
PortIdentity requestingPortIdentity;
}MsgPDelayRespFollowUp;
/**
* \brief Signaling message fields (Table 33 of the spec)
*/
/*Signaling Message*/
typedef struct {
PortIdentity targetPortIdentity;
char* tlv;
}MsgSignaling;
/**
* \brief Management message fields (Table 37 of the spec)
*/
/*management Message*/
typedef struct {
PortIdentity targetPortIdentity;
UInteger8 startingBoundaryHops;
UInteger8 boundaryHops;
Enumeration4 actionField;
char* tlv;
}MsgManagement;
/**
* \brief Time structure to handle Linux time information. Fixed for WR compliance
*/
typedef struct {
Integer32 seconds;
Integer32 nanoseconds;
Integer32 phase;
} TimeInternal;
/**
* \brief Structure used as a timer
*/
typedef struct {
Integer32 interval;
Integer32 left;
Boolean expire;
} IntervalTimer;
/**
* \brief ForeignMasterRecord is used to manage foreign masters
*/
typedef struct
{
PortIdentity foreignMasterPortIdentity;
UInteger16 foreignMasterAnnounceMessages;
//This one is not in the spec
MsgAnnounce announce;
MsgHeader header;
} ForeignMasterRecord;
/**
* \struct PtpClock
* \brief Main program data structure
*/
/* main program data structure */
typedef struct {
/***** Default data set ******/
NetPath netPath;
/*Static members*/
Boolean twoStepFlag;
ClockIdentity clockIdentity;
UInteger16 numberPorts;
/*Dynamic members*/
ClockQuality clockQuality;
/*Configurable members*/
UInteger8 priority1;
UInteger8 priority2;
UInteger8 domainNumber;
Boolean slaveOnly;
/***** Current data set ******/
/*Dynamic members*/
UInteger16 stepsRemoved;
TimeInternal offsetFromMaster;
TimeInternal meanPathDelay;
/******* Parent data set *******/
/*Dynamic members*/
PortIdentity parentPortIdentity;
Boolean parentStats;
UInteger16 observedParentOffsetScaledLogVariance;
Integer32 observedParentClockPhaseChangeRate;
ClockIdentity grandmasterIdentity;
ClockQuality grandmasterClockQuality;
UInteger8 grandmasterPriority1;
UInteger8 grandmasterPriority2;
/*
******* White Rabbit *******
* (parentDS)
*/
Boolean grandmasterIsWRnode;
Boolean grandmasterIsWRmode;
Boolean grandmasterIsCalibrated;
Enumeration8 grandmasterWrNodeMode;
FixedDelta grandmasterDeltaTx;
FixedDelta grandmasterDeltaRx;
/******* Global time properties data set *********/
/*Dynamic members*/
Integer16 currentUtcOffset;
Boolean currentUtcOffsetValid;
Boolean leap59;
Boolean leap61;
Boolean timeTraceable;
Boolean frequencyTraceable;
Boolean ptpTimescale;
Enumeration8 timeSource;
/****** Port configuration data set ***********/
/*Static members*/
PortIdentity portIdentity;
/*Dynamic members*/
Enumeration8 portState;
Integer8 logMinDelayReqInterval;
TimeInternal peerMeanPathDelay;
/*Configurable members*/
Integer8 logAnnounceInterval;
UInteger8 announceReceiptTimeout;
Integer8 logSyncInterval;
Enumeration8 delayMechanism;
Integer8 logMinPdelayReqInterval;
UInteger4 versionNumber;
/* Foreign master data set */
ForeignMasterRecord *foreign;
/* Other things we need for the protocol */
UInteger16 number_foreign_records;
Integer16 max_foreign_records;
Integer16 foreign_record_i;
Integer16 foreign_record_best;
Boolean record_update;
MsgHeader msgTmpHeader;
union {
MsgSync sync;
MsgFollowUp follow;
MsgDelayReq req;
MsgDelayResp resp;
MsgPDelayReq preq;
MsgPDelayResp presp;
MsgPDelayRespFollowUp prespfollow;
MsgManagement manage;
MsgAnnounce announce;
MsgSignaling signaling;
} msgTmp;
Octet msgObuf[PACKET_SIZE];
Octet msgIbuf[PACKET_SIZE];
TimeInternal master_to_slave_delay;
TimeInternal slave_to_master_delay;
Integer32 observed_drift;
TimeInternal pdelay_req_receive_time;
TimeInternal pdelay_req_send_time;
TimeInternal pdelay_resp_receive_time;
TimeInternal pdelay_resp_send_time;
TimeInternal sync_receive_time;
TimeInternal delay_req_send_time;
TimeInternal delay_req_receive_time;
MsgHeader PdelayReqHeader;
MsgHeader delayReqHeader;
TimeInternal pdelayMS;
TimeInternal pdelaySM;
TimeInternal delayMS;
TimeInternal delaySM;
TimeInternal lastSyncCorrectionField;
TimeInternal lastPdelayRespCorrectionField;
double R;
Boolean sentPDelayReq;
UInteger16 sentPDelayReqSequenceId;
UInteger16 sentDelayReqSequenceId;
UInteger16 sentSyncSequenceId;
UInteger16 sentAnnounceSequenceId;
UInteger16 recvPDelayReqSequenceId;
UInteger16 recvSyncSequenceId;
Boolean waitingForFollow;
offset_from_master_filter ofm_filt;
one_way_delay_filter owd_filt;
Boolean message_activity;
IntervalTimer itimer[TIMER_ARRAY_SIZE];
/*Usefull to init network stuff*/
UInteger8 port_communication_technology;
Octet port_uuid_field[PTP_UUID_LENGTH];
wr_servo_state_t wr_servo;
/*
***********White Rabbit **************
*/
/*
* white rabbit FSM state
*/
Enumeration8 wrPortState;
/*
* stores current managementId
* it's set to null when used
*/
Enumeration16 msgTmpManagementId;
/*
* This says whether PTPd is run for:
* - non-WR node,
* - WR Slave
* - WR Master
*
* Its important that the node knows what it is,
* by default PTPd runs in NON_WR
*/
Enumeration8 wrNodeMode; //copied to new
/*
* tell us whether we work in WR
* mode at the moment
* starts with FALSE
*/
Boolean isWRmode;
/*
* If port is aware of it's
* fixed delays (they are measured and
* stored in deltaTx and deltaRx)
* it's TRUE
*/
Boolean isCalibrated;
/*
* Fixed elays
*/
FixedDelta deltaTx;
FixedDelta deltaRx;
/*
* Calibration parameters of the
* current port
*/
UInteger32 calibrationPeriod;//[us]
UInteger32 calibrationPattern;
UInteger16 calibrationPatternLen;
UInteger16 otherNodeCalibrationSendPattern;
UInteger32 otherNodeCalibrationPeriod;
UInteger32 otherNodeCalibrationPattern;
UInteger16 otherNodeCalibrationPatternLen;
/*
* used to implemetn two-step clock
* this is implemented in WR differently than
* in original deamon (in original they used errored
* self message to read timestam and know that
* follow up should be read)
*/
Enumeration8 pending_follow_up;
/*
* Alpha parameter, represents physical
* medium correlation
* used to obtan asymmetry
*/
UInteger32 scalled_alpha;
/******White rabbit HW timestamps *******/
/*
* if any Tx timestamps should
* be read (any pending) it's true
*/
Boolean pending_tx_ts;
/*
* pending flags for each kind
* of tx message (not needed for Rx
*/
Boolean pending_Synch_tx_ts;
Boolean pending_DelayReq_tx_ts;
Boolean pending_PDelayReq_tx_ts;
Boolean pending_PDelayResp_tx_ts;
/*
* for storing frame_tags which keep
* track of which timestamp is read from HW
* for each msg
*/
// wr_frame_tag_t synch_tx_tag;
// wr_frame_tag_t delayReq_tx_tag;
// wr_frame_tag_t pDelayReq_tx_tag;
// wr_frame_tag_t pDelayResp_tx_tag;
/*
* store timestamp for each msg
*/
wr_timestamp_t synch_tx_ts;
wr_timestamp_t delayReq_tx_ts;
wr_timestamp_t pDelayReq_tx_ts;
wr_timestamp_t pDelayResp_tx_ts;
/*
* stores current Rx timestamp
*/
wr_timestamp_t current_rx_ts;
wr_timestamp_t current_tx_ts;
/******White rabbit timers *******/
/*
* holds info how many times
* current WR state has been repeated
*/
UInteger8 currentWRstateCnt;
/*
* stores eclapsed time for each timer
*/
IntervalTimer wrtimer[WR_TIMER_ARRAY_SIZE];
/*
* stores timeout for each timer
*/
UInteger16 wrTimeouts[WR_TIMER_ARRAY_SIZE];
/*
* used to calculate eclapsed time,
* we don't use interrapts, but periodically
* call do_irq_less_timing()
* and check time since last it's call
*/
struct timeval last_update;
//wr_servo_state_t servo
} PtpClock;
/**
* \struct RunTimeOpts
* \brief Program options set at run-time
*/
/* program options set at run-time */
typedef struct {
Integer8 announceInterval;
Integer8 syncInterval;
ClockQuality clockQuality;
UInteger8 priority1;
UInteger8 priority2;
UInteger8 domainNumber;
Boolean slaveOnly;
Integer16 currentUtcOffset;
Octet ifaceName[MAX_PORT_NUMBER][IFACE_NAME_LENGTH];
Boolean noResetClock;
Boolean noAdjust;
Boolean displayStats;
Boolean csvStats;
Octet unicastAddress[NET_ADDRESS_LENGTH];
Integer16 ap, ai;
Integer16 s;
TimeInternal inboundLatency, outboundLatency;
Integer16 max_foreign_records;
Boolean ethernet_mode;
Boolean E2E_mode;
Boolean offset_first_updated;
/********* White Rabbit ********/
UInteger16 portNumber;
Enumeration8 wrNodeMode;
UInteger32 calibrationPeriod;
UInteger32 calibrationPattern;
UInteger16 calibrationPatternLen;
//tmp
UInteger8 overrideClockIdentity;
} RunTimeOpts;
#endif /*DATATYPES_H_*/
/* constants_dep.h */
#ifndef CONSTANTS_DEP_H
#define CONSTANTS_DEP_H
/**
*\file
* \brief Plateform-dependent constants definition
*
* This header defines all includes and constants which are plateform-dependent
*
* ptpdv2 is only implemented for linux, NetBSD and FreeBSD
*/
/* platform dependent */
#if !defined(linux) && !defined(__NetBSD__) && !defined(__FreeBSD__)
#error Not ported to this architecture, please update.
#endif
#ifdef linux
#include<netinet/in.h>
#include<net/if.h>
#include<net/if_arp.h>
#define IFACE_NAME_LENGTH IF_NAMESIZE
#define NET_ADDRESS_LENGTH INET_ADDRSTRLEN
#define IFCONF_LENGTH 10
#define BSD_INTERFACE_FUNCTIONS
#include<endian.h>
#if __BYTE_ORDER == __LITTLE_ENDIAN
#define PTPD_LSBF
#elif __BYTE_ORDER == __BIG_ENDIAN
#define PTPD_MSBF
#endif
#endif /* linux */
#if defined(__NetBSD__) || defined(__FreeBSD__)
# include <sys/types.h>
# include <sys/socket.h>
# include <netinet/in.h>
# include <net/if.h>
# include <net/if_dl.h>
# include <net/if_types.h>
# if defined(__FreeBSD__)
# include <net/ethernet.h>
# include <sys/uio.h>
# else
# include <net/if_ether.h>
# endif
# include <ifaddrs.h>
# define IFACE_NAME_LENGTH IF_NAMESIZE
# define NET_ADDRESS_LENGTH INET_ADDRSTRLEN
# define IFCONF_LENGTH 10
//# define adjtimex ntp_adjtime
# include <machine/endian.h>
# if BYTE_ORDER == LITTLE_ENDIAN
# define PTPD_LSBF
# elif BYTE_ORDER == BIG_ENDIAN
# define PTPD_MSBF
# endif
#endif
#define CLOCK_IDENTITY_LENGTH 8
#define ADJ_FREQ_MAX 512000
/* UDP/IPv4 dependent */
#define SUBDOMAIN_ADDRESS_LENGTH 4
#define PORT_ADDRESS_LENGTH 2
#define PTP_UUID_LENGTH 6
#define CLOCK_IDENTITY_LENGTH 8
#define FLAG_FIELD_LENGTH 2
#define PACKET_SIZE 1024 //ptpdv1 value kept because of use of TLV...
#define PTP_EVENT_PORT 319
#define PTP_GENERAL_PORT 320
#define DEFAULT_PTP_DOMAIN_ADDRESS "224.0.1.129"
#define PEER_PTP_DOMAIN_ADDRESS "224.0.0.107"
#define MM_STARTING_BOUNDARY_HOPS 0x7fff
/* others */
#define SCREEN_BUFSZ 128
#define SCREEN_MAXSZ 80
#endif /*CONSTANTS_DEP_H_*/
#ifndef DATATYPES_DEP_H_
#define DATATYPES_DEP_H_
#include "ptpd_netif.h"
/**
*\file
* \brief Implementation specific datatype
*/
typedef enum {FALSE=0, TRUE} Boolean;
typedef char Octet;
typedef signed char Integer8;
typedef signed short Integer16;
typedef signed int Integer32;
typedef unsigned char UInteger8;
typedef unsigned short UInteger16;
typedef unsigned int UInteger32;
typedef unsigned short Enumeration16;
typedef unsigned char Enumeration8;
typedef unsigned char Enumeration4;
typedef unsigned char UInteger4;
typedef unsigned char Nibble;
/**
* \brief Implementation specific of UInteger48 type
*/
typedef struct {
unsigned int lsb;
unsigned short msb;
} UInteger48;
/**
* \brief Implementation specific of Integer64 type
*/
typedef struct {
unsigned int lsb;
int msb;
} Integer64;
/**
* \brief Implementation specific of Integer64 type
*/
typedef struct {
unsigned int lsb;
unsigned int msb;
} UInteger64;
/**
* \brief Struct used to average the offset from master
*
* The FIR filtering of the offset from master input is a simple, two-sample average
*/
typedef struct {
Integer32 nsec_prev, y;
} offset_from_master_filter;
/**
* \brief Struct used to average the one way delay
*
* It is a variable cutoff/delay low-pass, infinite impulse response (IIR) filter.
*
* The one-way delay filter has the difference equation: s*y[n] - (s-1)*y[n-1] = x[n]/2 + x[n-1]/2, where increasing the stiffness (s) lowers the cutoff and increases the delay.
*/
typedef struct {
Integer32 nsec_prev, y;
Integer32 s_exp;
} one_way_delay_filter;
/**
* \brief Struct used to store network datas
*/
typedef struct {
wr_socket_t *wrSock;
char ifaceName[IFACE_NAME_LENGTH];
wr_sockaddr_t multicastAddr, peerMulticastAddr,unicastAddr;
} NetPath;
typedef struct {
char if_name[16];
int state;
int next_state;
wr_timestamp_t prev_t4;
wr_timestamp_t mu;
wr_timestamp_t nsec_offset;
int32_t delta_tx_m;
int32_t delta_rx_m;
int32_t delta_tx_s;
int32_t delta_rx_s;
int32_t cur_setpoint;
int64_t delta_ms;
int64_t delta_ms_prev;
wr_timestamp_t t1, t2, t3, t4;
uint64_t last_tics;
} wr_servo_state_t;
#endif /*DATATYPES_DEP_H_*/
This diff is collapsed.
/* net.c */
/*
Here we have some intermediate layer between platform-independent *PTPd* and *ptpd_netif* library
It's not entirely necessary, it is a consequence of the fact that PTPd was adapted from opensource PTPd
*/
#include "../ptpd.h"
#include "ptpd_netif.h"
#include "hal_exports.h"
const mac_addr_t PTP_MULTICAST_ADDR[6] = {0x01, 0x1b, 0x19, 0 , 0, 0};
const mac_addr_t PTP_UNICAST_ADDR[6] = {0x01, 0x1b, 0x19, 0 , 0, 0};
const mac_addr_t ZERO_ADDR[6] = {0x00, 0x00, 0x00, 0x00, 0x001, 0x00};
/* shut down the UDP stuff */
Boolean netShutdown(NetPath *netPath)
{
PERROR("WR: not implemented: %s\n", __FUNCTION__ );
return TRUE;
#if 0
//original implementation
struct ip_mreq imr;
/*Close General Multicast*/
imr.imr_multiaddr.s_addr = netPath->multicastAddr;
imr.imr_interface.s_addr = htonl(INADDR_ANY);
setsockopt(netPath->eventSock, IPPROTO_IP, IP_DROP_MEMBERSHIP, &imr, sizeof(struct ip_mreq));
setsockopt(netPath->generalSock, IPPROTO_IP, IP_DROP_MEMBERSHIP, &imr, sizeof(struct ip_mreq));
/*Close Peer Multicast*/
imr.imr_multiaddr.s_addr = netPath->peerMulticastAddr;
imr.imr_interface.s_addr = htonl(INADDR_ANY);
setsockopt(netPath->eventSock, IPPROTO_IP, IP_DROP_MEMBERSHIP, &imr, sizeof(struct ip_mreq));
setsockopt(netPath->generalSock, IPPROTO_IP, IP_DROP_MEMBERSHIP, &imr, sizeof(struct ip_mreq));
netPath->multicastAddr = 0;
netPath->unicastAddr = 0;
netPath->peerMulticastAddr = 0;
/*Close sockets*/
if(netPath->eventSock > 0)
close(netPath->eventSock);
netPath->eventSock = -1;
if(netPath->generalSock > 0)
close(netPath->generalSock);
netPath->generalSock = -1;
return TRUE;
#endif
}
/*Test if network layer is OK for PTP*/
UInteger8 lookupCommunicationTechnology(UInteger8 communicationTechnology)
{
PERROR("WR: not implemented: %s\n", __FUNCTION__ );
return PTP_DEFAULT;
//original implementation
#if 0
#if defined(linux)
switch(communicationTechnology)
{
case ARPHRD_ETHER:
case ARPHRD_EETHER:
case ARPHRD_IEEE802:
return PTP_ETHER;
default:
break;
}
#elif defined(BSD_INTERFACE_FUNCTIONS)
#endif
return PTP_DEFAULT;
#endif
}
Boolean netStartup()
{
if(ptpd_netif_init() < 0)
return FALSE;
return TRUE;
}
/* start all of the UDP stuff */
/* must specify 'subdomainName', optionally 'ifaceName', if not then pass ifaceName == "" */
/* returns other args */
/* on socket options, see the 'socket(7)' and 'ip' man pages */
Boolean netInit(NetPath *netPath, RunTimeOpts *rtOpts, PtpClock *ptpClock)
{
mac_addr_t portMacAddress[6];
hexp_port_state_t pstate;
// Create a PTP socket:
wr_sockaddr_t bindaddr;
if(rtOpts->ifaceName[ptpClock->portIdentity.portNumber - 1][0] != '\0')
{
/*interface specified at PTPd start*/
strcpy(bindaddr.if_name, rtOpts->ifaceName[ptpClock->portIdentity.portNumber - 1]); // TODO: network intarface
DBG("Network interface : %s\n",rtOpts->ifaceName[ptpClock->portIdentity.portNumber - 1] );
}
else
{
/*
get interface name (port name) for the port
*/
if( ptpd_netif_get_ifName(bindaddr.if_name,ptpClock->portIdentity.portNumber ) == PTPD_NETIF_ERROR )
{
strcpy(bindaddr.if_name,"wru1"); // TODO: network intarface
DBG("Network interface forced to be wru1, but none of the WR ports seems to be up \n");
}
else
DBG("Network interface retrieved automatically by ptpd_netif: %s\n",bindaddr.if_name);
}
strncpy(netPath->ifaceName,bindaddr.if_name,IFACE_NAME_LENGTH);
DBG("Network interface : %s\n",netPath->ifaceName);
bindaddr.family = PTPD_SOCK_RAW_ETHERNET; // socket type
bindaddr.ethertype = 0x88f7; // PTPv2
memcpy(bindaddr.mac, PTP_MULTICAST_ADDR, 6);
// Create one socket for event and general messages (WR lower level layer requires that
netPath->wrSock = ptpd_netif_create_socket(PTPD_SOCK_RAW_ETHERNET, 0, &bindaddr);
if(netPath->wrSock == NULL)
{
PERROR("failed to initalize sockets");
return FALSE;
}
/* send a uni-cast address if specified (useful for testing) */
if(rtOpts->unicastAddress[0])
{
memcpy(netPath->unicastAddr.mac, PTP_UNICAST_ADDR, 6);
}
else
memcpy(netPath->unicastAddr.mac, ZERO_ADDR, 6);
memcpy(netPath->multicastAddr.mac, PTP_MULTICAST_ADDR, 6);
memcpy(netPath->peerMulticastAddr.mac, PTP_MULTICAST_ADDR, 6);
netPath->unicastAddr.ethertype = 0x88f7;
netPath->multicastAddr.ethertype = 0x88f7;
netPath->peerMulticastAddr.ethertype = 0x88f7;
ptpd_netif_get_hw_addr(netPath->wrSock, portMacAddress);
/* copy mac part to uuid */
memcpy(ptpClock->port_uuid_field,portMacAddress, PTP_UUID_LENGTH);
DBG("[%s] mac: %x:%x:%x:%x:%x:%x\n",__func__,\
ptpClock->port_uuid_field[0],\
ptpClock->port_uuid_field[1],\
ptpClock->port_uuid_field[2],\
ptpClock->port_uuid_field[3],\
ptpClock->port_uuid_field[4],\
ptpClock->port_uuid_field[5]);
// fixme: error handling
halexp_get_port_state(&pstate, netPath->ifaceName);
DBG(" netif_WR_mode = %d\n", pstate.mode);
if(rtOpts->wrNodeMode == NON_WR)
{
switch(pstate.mode)
{
case HEXP_PORT_MODE_WR_MASTER:
DBG("wrNodeMode(auto config) ....... MASTER\n");
ptpClock->wrNodeMode = WR_MASTER;
//tmp solution
break;
case HEXP_PORT_MODE_WR_SLAVE:
DBG("wrNodeMode(auto config) ........ SLAVE\n");
ptpClock->wrNodeMode = WR_SLAVE;
ptpd_init_exports();
//tmp solution
break;
case HEXP_PORT_MODE_NON_WR:
default:
DBG("wrNodeMode(auto config) ........ NON_WR\n");
ptpClock->wrNodeMode = NON_WR;
//tmp solution
break;
}
}else
{
ptpClock->wrNodeMode = rtOpts->wrNodeMode;
DBG("wrNodeMode (............ FORCE ON STARTUP\n");
}
DBG("netInit: exiting OK\n");
return TRUE;
}
/*Check if data have been received*/
int netSelect(TimeInternal *timeout, NetPath *netPath)
{
/*
TODO: ptpd_netif_select improve
*/
struct timeval tv, *tv_ptr;
if(timeout)
{
tv.tv_sec = timeout->seconds;
tv.tv_usec = timeout->nanoseconds/1000;
tv_ptr = &tv;
}
else
tv_ptr = 0;
return ptpd_netif_select(netPath->wrSock);
}
/*store received data from network to "buf" , get and store the SO_TIMESTAMP value in "time" for an event message*/
ssize_t netRecvMsg(Octet *buf, NetPath *netPath, wr_timestamp_t *current_rx_ts)
{
wr_sockaddr_t from_addr;
int ret;
if((ret = ptpd_netif_recvfrom(netPath->wrSock, &from_addr, buf, 1518, current_rx_ts)) > 0)
{
//DBG("RX timestamp %s [ret=%d]\n", format_wr_timestamp(*current_rx_ts), ret);
}
return (ssize_t)ret;
}
ssize_t netSendEvent(Octet *buf, UInteger16 length, NetPath *netPath, wr_timestamp_t *current_tx_ts)
{
int ret;
//Send a frame
ret = ptpd_netif_sendto(netPath->wrSock, &netPath->multicastAddr, buf, length, current_tx_ts);
if(ret <= 0)
DBGNPI("error sending multi-cast event message\n");
return (ssize_t)ret;
}
ssize_t netSendGeneral(Octet *buf, UInteger16 length, NetPath *netPath)
{
wr_timestamp_t ts;
int ret;
//Send a frame
ret = ptpd_netif_sendto(netPath->wrSock, &(netPath->multicastAddr), buf, length, &ts);
if(ret <= 0)
DBGNPI("error sending multi-cast event message\n");
return (ssize_t)ret;
}
ssize_t netSendPeerGeneral(Octet *buf,UInteger16 length,NetPath *netPath)
{
int ret;
//Send a frame
ret = ptpd_netif_sendto(netPath->wrSock, &(netPath->multicastAddr), buf, length, NULL);
if(ret <= 0)
DBGNPI("error sending multi-cast general message\n");
return (ssize_t)ret;
}
ssize_t netSendPeerEvent(Octet *buf,UInteger16 length,NetPath *netPath,wr_timestamp_t *current_tx_ts)
{
int ret;
//Send a frame
// ret = ptpd_netif_sendto(netPath->wrSock, &(netPath->multicastAddr), buf, length, current_tx_ts);
if(ret <= 0)
DBGNPI("error sending multi-cast event message\n");
return (ssize_t)ret;
}
This diff is collapsed.
#include "../ptpd.h"
void initClock(RunTimeOpts *rtOpts, PtpClock *ptpClock)
{
}
void updateDelay (one_way_delay_filter *owd_filt, RunTimeOpts *rtOpts, PtpClock *ptpClock,TimeInternal *correctionField)
{
}
void updatePeerDelay (one_way_delay_filter *owd_filt, RunTimeOpts *rtOpts, PtpClock *ptpClock,TimeInternal *correctionField,Boolean twoStep)
{
}
void updateOffset(TimeInternal *send_time, TimeInternal *recv_time,
offset_from_master_filter *ofm_filt, RunTimeOpts *rtOpts, PtpClock *ptpClock,TimeInternal *correctionField)
{
}
void updateClock(RunTimeOpts *rtOpts, PtpClock *ptpClock)
{
}
This diff is collapsed.
/* sys.c */
#include "../ptpd.h"
void displayStats(RunTimeOpts *rtOpts, PtpClock *ptpClock)
{
static int start = 1;
static char sbuf[SCREEN_BUFSZ];
char *s;
int len = 0;
if(start && rtOpts->csvStats)
{
start = 0;
printf("state, one way delay, offset from master, drift");
fflush(stdout);
}
memset(sbuf, ' ', SCREEN_BUFSZ);
switch(ptpClock->portState)
{
case PTP_INITIALIZING: s = "init"; break;
case PTP_FAULTY: s = "flt"; break;
case PTP_LISTENING: s = "lstn"; break;
case PTP_PASSIVE: s = "pass"; break;
case PTP_UNCALIBRATED: s = "uncl"; break;
case PTP_SLAVE: s = "slv"; break;
case PTP_PRE_MASTER: s = "pmst"; break;
case PTP_MASTER: s = "mst"; break;
case PTP_DISABLED: s = "dsbl"; break;
default: s = "?"; break;
}
len += sprintf(sbuf + len, "%s%s", rtOpts->csvStats ? "\n": "\rstate: ", s);
if(ptpClock->portState == PTP_SLAVE)
{
len += sprintf(sbuf + len,
", %s%d.%09d" ", %s%d.%09d",
rtOpts->csvStats ? "" : "owd: ",
ptpClock->meanPathDelay.seconds,
ptpClock->meanPathDelay.nanoseconds,
//abs(ptpClock->meanPathDelay.nanoseconds),
rtOpts->csvStats ? "" : "ofm: ",
ptpClock->offsetFromMaster.seconds,
ptpClock->offsetFromMaster.nanoseconds);
//abs(ptpClock->offsetFromMaster.nanoseconds));
len += sprintf(sbuf + len,
", %s%d" ,
rtOpts->csvStats ? "" : "drift: ", ptpClock->observed_drift);
}
write(1, sbuf, rtOpts->csvStats ? len : SCREEN_MAXSZ + 1);
}
Boolean nanoSleep(TimeInternal *t)
{
struct timespec ts, tr;
ts.tv_sec = t->seconds;
ts.tv_nsec = t->nanoseconds;
if(nanosleep(&ts, &tr) < 0)
{
t->seconds = tr.tv_sec;
t->nanoseconds = tr.tv_nsec;
return FALSE;
}
return TRUE;
}
void getTime(TimeInternal *time)
{
struct timeval tv;
gettimeofday(&tv, 0);
time->seconds = tv.tv_sec;
time->nanoseconds = tv.tv_usec*1000;
}
void setTime(TimeInternal *time)
{
struct timeval tv;
tv.tv_sec = time->seconds;
tv.tv_usec = time->nanoseconds/1000;
settimeofday(&tv, 0);
NOTIFY("resetting system clock to %ds %dns\n", time->seconds, time->nanoseconds);
}
double getRand()
{
return ((rand() * 1.0)/RAND_MAX);
}
Boolean adjFreq(Integer32 adj)
{
//ML
return 0;
/*
struct timex t;
if(adj > ADJ_FREQ_MAX)
adj = ADJ_FREQ_MAX;
else if(adj < -ADJ_FREQ_MAX)
adj = -ADJ_FREQ_MAX;
t.modes = MOD_FREQUENCY;
t.freq = adj*((1<<16)/1000);
return !adjtimex(&t);*/
}
This diff is collapsed.
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment