| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544 |
- /*!
- * Copyright (C) Fraunhofer-Institut for Photonic Microsystems (IPMS)
- * Maria-Reiche-Str. 2
- * 01109 Dresden
- *
- * Unauthorized copying of this file, via any medium is strictly prohibited
- * Proprietary and confidential
- *
- * \file tsn_ptp_stack.c
- * \author zimmerli
- * \date 2019-01-17
- * \brief IEEE 802.1as software protocol stack
- *
- */
- #include "tsn_ptp_stack.h"
- #define SWAP16(value) (((value & 0xFF) << 8 | (value >> 8)) & 0xFFFF)
- #define PTPHDR_OFS_MSGID 0
- #define PTPHDR_OFS_MSGLEN 2
- #define PTPHDR_OFS_DOMAIN 4
- #define PTPHDR_OFS_FLAGS 6
- #define PTPHDR_OFS_CORFIELD 8
- #define PTPHDR_OFS_SPID 20
- #define PTPHDR_OFS_SEQID 30
- #define PTPHDR_OFS_LOGIVAL 33
- #define PTPHDR_OFS_FUP_TLV (34 + 10)
- #define PTPHDR_OFS_ANNC_STEP_REM (34 + 27)
- #define NS_PER_SEC (1000000000LL)
- // PDelay-Request State-Machine events
- // do calculation of Pdelay, neighbor rate ratio only on complete event list
- #define PDREQ_FLAG_TXDONE (1 << 0)
- #define PDREQ_FLAG_RXRESP (1 << 1)
- #define PDREQ_FLAG_RXRSPFUP (1 << 2)
- #define PDREQ_MASK_COMPLETE (0x7)
- // Delay mechanism defines IEEE 802.1as-2020 14.8.5
- #define PTP_DELAY_MECH_P2P 2
- #define PTP_DELAY_MECH_COMP2P 3
- enum announce_info_is_e {
- INFO_IS_DISABLED = 0,
- INFO_IS_MINE = 1,
- INFO_IS_RECEIVED = 2,
- INFO_IS_AGED = 3
- };
- // ----------------------------------------------------------------
- // declarations
- static struct ptp_header_s _ptp_default_header = {
- // set default header information
- .majorSdoId = PTP_MAJOR_SDO_ID,
- .minorSdoId = PTP_MINOR_SDO_ID,
- .domainNumber = 0,
- .minorVersionPTP = 1,
- .version = PTP_VERSION,
- .correctionField = 0,
- .sequenceId = 0,
- .sourcePortId = { 0, 0 },
- .msgType = 0,
- .msgLen = PTP_HEADER_SZ,
- .flags = PTP_FLAG_PTP_TIMESCALE,
- .control = PTP_CONTROL_OTHER,
- .logMsgInterval = 0x7F
- };
- // ----------------------------------------------------------------
- // function declarations
- static uint16_t ptp_get_seqid(uintptr_t hdraddr);
- static void ptp_get_corfield(uintptr_t hdraddr, int64_t *pCorrectionField);
- // state machine functions
- static void mdpdelayresp_rcvdPdelayReq(tsn_ptp_instance_t *pStack, tsn_ptp_port_t *pPort, uintptr_t hdrAddr, ptp_timestamp_t *pRxTime);
- static void mdpdelayresp_rcvdMDTimestampReceive(tsn_ptp_instance_t *pStack, tsn_ptp_port_t *pPort, ptp_timestamp_t *pTxTime);
- static void mdpdelayreq_rcvdPdelayResp(tsn_ptp_port_t *pProtocol, uintptr_t hdrAddr, ptp_timestamp_t *pRxTime);
- static void mdpdelayreq_rcvdPdelayRespFup(tsn_ptp_port_t *pProtocol, uintptr_t hdrAddr);
- static void mdpdelayreq_calculate(tsn_ptp_port_t *pProtocol);
- static void mdpdelayreq_rcvdMDTimestampReceive(tsn_ptp_port_t *pProtocol, ptp_timestamp_t *pTxTime);
- static void mdpdelayreq_pdelayIntervalTimer(tsn_ptp_instance_t *pStack, tsn_ptp_port_t *pPort);
- static void mdsyncreceive_rcvdSync(tsn_ptp_instance_t *pStack, tsn_ptp_port_t *pProtocol, uintptr_t hdrAddr, ptp_timestamp_t *pRxTime);
- static void mdsyncreceive_rcvdFollowup(tsn_ptp_instance_t *pStack, tsn_ptp_port_t *pProtocol, uintptr_t hdrAddr);
- static void portsyncsyncrecv_rcvdMdSync(tsn_ptp_instance_t *pStack, port_sync_sync_t *pPSS);
- static void portannouncerecv(tsn_ptp_instance_t *pStack, tsn_ptp_port_t *pPort, uintptr_t hdrAddr);
- static void portannouncerecv_timeout(tsn_ptp_instance_t *pStack, tsn_ptp_port_t *pPort);
- static void portannouncesend(tsn_ptp_instance_t *pStack, tsn_ptp_port_t *pPort);
- static void portsyncsyncsend(tsn_ptp_instance_t *pStack, tsn_ptp_port_t *pPort, port_sync_sync_t *pPSS);
- static void mdsyncsend_rcvdMDTimestampReceive(tsn_ptp_instance_t *pStack, tsn_ptp_port_t *pPort, ptp_timestamp_t *pTxTime);
- static void siteSyncIntervalTimer(tsn_ptp_instance_t *pStack);
- static void siteSyncPssHandle(tsn_ptp_instance_t *pStack, port_sync_sync_t *pPSS);
- static void siteSyncPssReceive(tsn_ptp_instance_t *pStack, port_sync_sync_t *pPSS);
- static uint64_t tsn_ptp_clock_get_offset(tsn_ptp_clock_t *domain_clk, uint64_t localtime);
- static uint64_t ptp_timestamp_to_ns(ptp_timestamp_t *ts);
- // static void signalingrecv(tsn_ptp_port_t *pPort, uintptr_t hdrAddr);
- // ----------------------------------------------------------------
- void tsn_ptp_stack_init(tsn_ptp_instance_t *pStack, uint8_t *pMacAddr, uint8_t domainNumber)
- {
- uint32_t idx;
- tsn_ptp_port_t *port;
- uint16_t pnum; // port number
- // set clock identity
- tsn_ptp_mac_to_clockid(pMacAddr, (uint8_t *)(&pStack->thisClock));
- // init hook defaults
- pStack->cbParam = 0;
- pStack->hookSetTimer = 0;
- pStack->hookGetLocalTime = 0;
- pStack->hookGetLocalOffset = 0;
- pStack->hookStatusEvent = 0;
- pStack->hookTxFrame = 0;
- // init system -> default values
- pStack->systemId.prio1 = 254;
- pStack->systemId.prio2 = 255;
- pStack->systemId.clockQuality.clockClass = 248;
- pStack->systemId.clockQuality.clockAccuracy = 254;
- pStack->systemId.clockQuality.offsetScaledLogVariance = 17258;
- pStack->systemId.clockIdentity = pStack->thisClock;
- pStack->gmPriority.rootSystemId = pStack->systemId;
- pStack->gmPriority.stepsRemoved = 0;
- pStack->gmPriority.sourcePortId.clockIdentity = pStack->thisClock;
- pStack->gmPriority.sourcePortId.portNumber = 0;
- pStack->gmPriority.portNumber = 0;
- pStack->masterStepsRemoved = 0;
- pStack->gmChanges = 0;
- pStack->pathTrace[0] = pStack->thisClock;
- pStack->pathTraceCount = 1;
- pStack->selectedRole0 = PTP_PORT_ROLE_SLAVE; // default: system clock is slave
- // system flags and fields - defaults
- pStack->sysInfo.curUtcOfs = 37; // latest known value - 2017-01-01
- pStack->sysInfo.timeSource = PTP_SRC_OTHER;
- pStack->sysInfo.flags = PTP_FLAG_TIME_TRACEABLE | PTP_FLAG_FREQ_TRACEABLE; // leap59/61 unknown, utc valid unknown
- pStack->announceInfo = pStack->sysInfo;
- pStack->domainNumber = domainNumber;
- pStack->enableInvoke = 0;
- // SiteSync initialization
- pStack->siteSync.gmRateOfs = 0;
- pStack->siteSync.hasSavedSync = 0;
- pStack->siteSync.hasSyncRcvd = 0;
- pStack->siteSync.clkSrcPhOfs.fns = 0;
- pStack->siteSync.clkSrcPhOfs.ns_msb = 0;
- pStack->siteSync.clkSrcPhOfs.ns_lsb = 0;
- pStack->siteSync.clkTimeBaseInd = 0;
- pStack->siteSync.clkFrqOfsScaled = 0;
- pStack->siteSync.gmOffset = 0;
- pStack->siteSync.gmOffsetSum = 0;
- pStack->siteSync.logSyncIval = PTP_INIT_INTVAL_SYNC;
- // LocalClock initialization
- pStack->localClock.offset_ns = 0;
- pStack->localClock.rateOfs = 0;
- pStack->localClock.fractOfs = 0;
- // init ports
- for (idx = 0; idx < TSN_PTP_CFG_PORTNUM; ++idx) {
- port = &(pStack->port[idx]);
- pnum = idx + 1; // Port number: 1 .. N
- // port
- port->port.thisPort = pnum; // Port number: 1 .. N
- port->port.thisPortId.clockIdentity = pStack->thisClock;
- port->port.thisPortId.portNumber = pnum;
- port->port.asCapable = 1;
- port->port.enabled = 0;
- port->port.curLogSyncInterval = PTP_INIT_INTVAL_SYNC;
- port->port.neighborRateOfs32 = 0;
- port->port.portIndex = idx;
- port->port.meanLinkDelay = 0;
- port->port.computeNeighborRateRatio = 1;
- port->port.computeMeanLinkDelay = 1;
- port->port.selectedRole = PTP_PORT_ROLE_DISABLED;
- port->port.delayMechanism = PTP_DELAY_MECH_P2P;
- port->port.rcvdPortStateInd = 0;
- port->port.rcvdPortState = PTP_PORT_ROLE_DISABLED;
- // md
- port->md.curLogPdelayReqInterval = PTP_INIT_INTVAL_PDELAY;
- port->md.isMeasuringDelay = 0;
- port->md.meanLinkDelayTresh = 10 * 1000; // init as 10us fixed
- port->md.syncSeqId = 0x1234; // random
- port->md.asCapableAcrossDomains = 0;
- // init mdPdReqSm
- port->mdPdReq.seqid = 0x2345; // random
- port->mdPdReq.measIsRunning = 0;
- port->mdPdReq.lostResponses = 0;
- port->mdPdReq.neighborRateRatioValid = 0;
- port->mdPdReq.saved_local_rxresp = 0;
- port->mdPdReq.saved_peer_txresp = 0;
- port->mdPdReq.eventflags = 0;
- // init mdPdRespSm
- port->mdPdResp.seqid = 0;
- // init mdSyncRecv
- port->mdSyncRecv.seqid = 0;
- port->mdSyncRecv.waitFup = 0;
- // init mdSyncSend
- port->mdSyncSend.seqid = 0x6789; // random
- // init anncInfo (see IEEE 802.1as 10.3.4)
- port->anncInfo.newInfo = 0;
- port->anncInfo.infoIs = INFO_IS_DISABLED;
- port->anncInfo.txSeqId = 0x4567; // random
- port->anncInfo.curLogInterval = PTP_INIT_INTVAL_ANNC;
- }
- }
- void tsn_ptp_stack_enable(tsn_ptp_instance_t *pStack, uint16_t bEnable)
- {
- if (bEnable) {
- // timer hooks - enable, defaults
- if (pStack->hookSetTimer != 0) {
- pStack->hookSetTimer(pStack->cbParam, PTP_TMR_EVENT_TXSYNC, 0, pStack->siteSync.logSyncIval, 1);
- }
- } else {
- // timer hooks - disable (127)
- if (pStack->hookSetTimer != 0) {
- pStack->hookSetTimer(pStack->cbParam, PTP_TMR_EVENT_TXSYNC, 0, 127, 1);
- pStack->hookSetTimer(pStack->cbParam, PTP_TMR_EVENT_RXSYNC, 0, 127, 1);
- }
- }
- }
- void tsn_ptp_stack_rxframe(tsn_ptp_instance_t *pStack, uint16_t portIndex, uintptr_t hdrAddr, uint32_t length, ptp_timestamp_t *pRxTime)
- {
- (void)length;
- (void)pStack;
- uint8_t msgType;
- tsn_ptp_port_t *pPort;
- if (portIndex >= TSN_PTP_CFG_PORTNUM)
- return;
- pPort = &(pStack->port[portIndex]);
- if (!pPort->port.enabled)
- return;
- // get msgType and sequence id
- msgType = (*(uint8_t *)(hdrAddr + PTPHDR_OFS_MSGID));
- msgType &= PTP_MSGTYPE_MASK;
- if (msgType == PTP_MSGTYPE_SYNC) {
- // MDSyncReceive state machine: IEEE 802.1as 11.2.13
- mdsyncreceive_rcvdSync(pStack, pPort, hdrAddr, pRxTime);
- } else if (msgType == PTP_MSGTYPE_PDELAY_REQ) {
- // MDPdelayResp state machine: IEEE 802.1as 11.2.16
- mdpdelayresp_rcvdPdelayReq(pStack, pPort, hdrAddr, pRxTime);
- } else if (msgType == PTP_MSGTYPE_PDELAY_RESP) {
- // MDPdelayResp state machine: IEEE 802.1as 11.2.15
- mdpdelayreq_rcvdPdelayResp(pPort, hdrAddr, pRxTime);
- } else if (msgType == PTP_MSGTYPE_FOLLOWUP) {
- // MDSyncReceive state machine: IEEE 802.1as 11.2.13
- mdsyncreceive_rcvdFollowup(pStack, pPort, hdrAddr);
- } else if (msgType == PTP_MSGTYPE_PDELAY_FUP) {
- // MDPdelayResp state machine: IEEE 802.1as 11.2.15
- mdpdelayreq_rcvdPdelayRespFup(pPort, hdrAddr);
- //TODO: optimize according IEEE 802.1as-2020 11.2.2
- if (pPort->md.asCapableAcrossDomains) // && pStack->domainNumber == 0)
- pPort->port.asCapable = 1;
- } else if (msgType == PTP_MSGTYPE_ANNOUNCE) {
- // PortAnnounceReceive: IEEE 802.1as 10.3.10
- // PortAnnounceInformation: IEEE 802.1as 10.3.11
- portannouncerecv(pStack, pPort, hdrAddr);
- } else if (msgType == PTP_MSGTYPE_SIGNALING) {
- // TODO: LinkDelayIntervalSetting : IEEE 802.1as 11.2.17
- // TODO: AnnounceIntervalSetting : IEEE 802.1as 10.3.14
- // signalingrecv(pPort, hdrAddr);
- }
- }
- void tsn_ptp_stack_txdone(tsn_ptp_instance_t *pStack, tsn_ptp_port_t *pPort, uint8_t msgType, ptp_timestamp_t *pTxTime)
- {
- if (msgType == PTP_MSGTYPE_SYNC) {
- // MDSyncSend 11.2.14
- mdsyncsend_rcvdMDTimestampReceive(pStack, pPort, pTxTime);
- } else if (msgType == PTP_MSGTYPE_PDELAY_RESP) {
- // MDPdelayResp state machine: IEEE 802.1as 11.2.16
- mdpdelayresp_rcvdMDTimestampReceive(pStack, pPort, pTxTime);
- } else if (msgType == PTP_MSGTYPE_PDELAY_REQ) {
- // MDPdelayReq state machine: IEEE 802.1as 11.2.15
- mdpdelayreq_rcvdMDTimestampReceive(pPort, pTxTime);
- }
- }
- void tsn_ptp_stack_portroleselection(tsn_ptp_instance_t *pStack)
- {
- uint32_t idx;
- int32_t cmp;
- ptp_prio_vect_t gmPriorityVector;
- ptp_prio_vect_t prioVect; // used as gmPathPriorityVector and masterPriorityVector
- tsn_ptp_port_t *port;
- time_info_t tmInfo;
- uint16_t portNum;
- uint8_t updtInfo; // used as bool
- // clearReselectTree(); not needed
- // setSelectedTree(); not needed - as port update is done within this function
- // updtRolesTree(); IEEE802.1as: 10.3.12.1.4
- // a) gmPathPrioVect for every port
- // SEARCH BEST GM from set <system, port 1 .. N>
- // only use ports, where infoIs received
- // init: use system as GM
- portNum = 0;
- gmPriorityVector.rootSystemId = pStack->systemId;
- gmPriorityVector.stepsRemoved = 0;
- gmPriorityVector.sourcePortId.clockIdentity = pStack->thisClock;
- gmPriorityVector.sourcePortId.portNumber = 1; //0;
- gmPriorityVector.portNumber = 0;
- tmInfo = pStack->sysInfo;
- for (idx = 0; idx < TSN_PTP_CFG_PORTNUM; ++idx) {
- // port pointer
- port = &(pStack->port[idx]);
- // check info is received; but not my own clockId
- if ((port->anncInfo.infoIs == INFO_IS_RECEIVED) && (port->anncInfo.portPriority.sourcePortId.clockIdentity != pStack->thisClock)) {
- // gmPathPrioVect (is prioVect)
- prioVect = port->anncInfo.portPriority;
- prioVect.stepsRemoved += 1; // increment stepsRemoved, see 10.3.5
- // compare gmPathPrio and current gmPriorityVector
- cmp = tsn_ptp_cmp_priovect(&prioVect, &gmPriorityVector);
- if (cmp < 0) {
- // received priority vector from port is better than actual vector
- // copy to gmPriorityVector, update portNum, copy time information (flags, ...)
- gmPriorityVector = prioVect;
- portNum = port->port.thisPort;
- tmInfo = port->anncInfo.annInfo;
- }
- } // if
- } // for
- // check for GM change --> increment counter
- if (pStack->gmPriority.rootSystemId.clockIdentity != gmPriorityVector.rootSystemId.clockIdentity) {
- pStack->gmChanges++;
- }
- // b) gmPriority = gmPriorityVector
- pStack->gmPriority = gmPriorityVector;
- // c) set global vars&fields for announce (from Slave-Port or System)
- pStack->announceInfo = tmInfo;
- // d) compute masterPrioVect for each port
- // masterPrioVect: is prioVect
- prioVect.rootSystemId = gmPriorityVector.rootSystemId;
- prioVect.stepsRemoved = gmPriorityVector.stepsRemoved;
- prioVect.sourcePortId.clockIdentity = pStack->thisClock;
- // e) compute masterStepsRemoved (portStepsRem + 1 | 0)
- // same as gmPriorityVector.stepsRemoved
- pStack->masterStepsRemoved = gmPriorityVector.stepsRemoved;
- // f) update roles
- for (idx = 0; idx < TSN_PTP_CFG_PORTNUM; ++idx) {
- // port pointer
- port = &(pStack->port[idx]);
- updtInfo = 0;
- // IEEE802.1as-2020: 10.3.15
- if (port->port.rcvdPortStateInd) {
- port->port.selectedRole = port->port.rcvdPortState;
- continue;
- }
- // d) compute masterPrioVect for each port
- // masterPrioVect: is prioVect
- prioVect.portNumber = port->port.thisPort;
- prioVect.sourcePortId.portNumber = port->port.thisPort;
- if (port->anncInfo.infoIs == INFO_IS_DISABLED) {
- // f3) infois==disabled --> role = disabledport
- port->port.selectedRole = PTP_PORT_ROLE_DISABLED;
- } else if (port->anncInfo.infoIs == INFO_IS_AGED) {
- // f4) infois==aged --> role = master + updtInfo
- port->port.selectedRole = PTP_PORT_ROLE_MASTER;
- updtInfo = 1;
- } else if (port->anncInfo.infoIs == INFO_IS_MINE) {
- // f5) infois==mine --> role = master + updtInfo
- port->port.selectedRole = PTP_PORT_ROLE_MASTER;
- updtInfo = 1;
- } else if (port->anncInfo.infoIs == INFO_IS_RECEIVED) {
- // f6-9) infois==received
- if (port->port.thisPort == portNum) {
- // f6) gmPrio derived from port --> slave
- port->port.selectedRole = PTP_PORT_ROLE_SLAVE;
- updtInfo = 0;
- } else {
- if (tsn_ptp_cmp_priovect(&prioVect, &(port->anncInfo.portPriority)) < 0) {
- // f9) masterPrio better then portPrio --> master
- port->port.selectedRole = PTP_PORT_ROLE_MASTER;
- updtInfo = 1;
- } else {
- // f7-8) else --> passive
- port->port.selectedRole = PTP_PORT_ROLE_PASSIVE;
- }
- }
- }
- if (updtInfo) {
- // update info per port (when updtInfo==TRUE)
- // portPrio = masterPrio, portStepsRem = masterStepRem, infoIs=mine, newInfo=true
- port->anncInfo.portPriority = prioVect;
- port->anncInfo.portStepsRemoved = pStack->masterStepsRemoved;
- port->anncInfo.infoIs = INFO_IS_MINE;
- port->anncInfo.newInfo = 1;
- }
- }
- // g) SKIPPED gmPresent true if gmPrio1 < 255
- // h) role port0: any slave-port --> role = passive; else role = slave
- if (portNum > 0) {
- pStack->selectedRole0 = PTP_PORT_ROLE_PASSIVE;
- } else {
- pStack->selectedRole0 = PTP_PORT_ROLE_SLAVE;
- }
- // i) set pathtrace if grandmaster (gmPrio.sys.clkid == thisClock)
- if (gmPriorityVector.rootSystemId.clockIdentity == pStack->thisClock) {
- pStack->pathTrace[0] = pStack->thisClock;
- pStack->pathTraceCount = 1;
- }
- // all master-ports -> set tx timer announce (immediately)
- for (idx = 0; idx < TSN_PTP_CFG_PORTNUM; ++idx) {
- // port pointer
- port = &(pStack->port[idx]);
- if (pStack->hookSetTimer != 0 && port->port.enabled) {
- pStack->hookSetTimer(pStack->cbParam, PTP_TMR_EVENT_TXANNC, idx, port->anncInfo.curLogInterval, 0);
- }
- }
- }
- //TODO: split timerevent to disable portIndex for site timer event
- void tsn_ptp_stack_timerevent(tsn_ptp_instance_t *pStack, ptp_timer_event_t tmrEvent, uint32_t id)
- {
- tsn_ptp_port_t *pPort;
- if (tmrEvent == PTP_TMR_EVENT_TXSYNC) {
- if (pStack->hookSetTimer != 0) {
- pStack->hookSetTimer(pStack->cbParam, PTP_TMR_EVENT_TXSYNC, 0, pStack->siteSync.logSyncIval, 1);
- }
- siteSyncIntervalTimer(pStack);
- return;
- }
- if (tmrEvent == PTP_TMR_EVENT_RXSYNC) {
- // Will only be counted
- // no action - see 11.2.13
- if (pStack->hookStatusEvent != 0) {
- pStack->hookStatusEvent(pStack->cbParam, PTP_STS_EVENT_SYNCLOST, 0);
- pStack->siteSync.hasSyncRcvd = 0;
- }
- }
- // check id and get port pointer for the following events
- if (id >= TSN_PTP_CFG_PORTNUM)
- return;
- pPort = &(pStack->port[id]);
- if (tmrEvent == PTP_TMR_EVENT_TXPDREQ) {
- // reset timer
- if (pStack->hookSetTimer != 0) {
- pStack->hookSetTimer(pStack->cbParam, PTP_TMR_EVENT_TXPDREQ, id, pPort->md.curLogPdelayReqInterval, 1);
- }
- // MDPdelayReq state machine: IEEE 802.1as 11.2.15
- mdpdelayreq_pdelayIntervalTimer(pStack, pPort);
- }
- if (tmrEvent == PTP_TMR_EVENT_RXANNC) {
- // PortAnnounceInformation: IEEE 802.1as 10.3.11
- portannouncerecv_timeout(pStack, pPort);
- }
- if (tmrEvent == PTP_TMR_EVENT_TXANNC) {
- // PortAnnounceTransmit: IEEE 802.1as 10.3.13
- portannouncesend(pStack, pPort);
- // reset timer
- if (pPort->port.selectedRole == PTP_PORT_ROLE_MASTER) {
- // reset timer
- if (pStack->hookSetTimer != 0) {
- pStack->hookSetTimer(pStack->cbParam, PTP_TMR_EVENT_TXANNC, id, pPort->anncInfo.curLogInterval, 1);
- }
- }
- }
- if (tmrEvent == PTP_TMR_EVENT_TXSYNC) {
- siteSyncIntervalTimer(pStack);
- }
- }
- void tsn_ptp_stack_port_enable(tsn_ptp_instance_t *pStack, uint16_t portIndex, uint16_t bEnable)
- {
- tsn_ptp_port_t *port;
- // check index
- if (portIndex >= TSN_PTP_CFG_PORTNUM)
- return;
- port = (tsn_ptp_port_t *)(&pStack->port[portIndex]);
- if (bEnable) {
- // enable
- // set default intervals
- port->md.curLogPdelayReqInterval = PTP_INIT_INTVAL_PDELAY;
- port->anncInfo.curLogInterval = PTP_INIT_INTVAL_ANNC;
- // announce info: copy master prio
- port->anncInfo.portPriority = pStack->gmPriority;
- port->anncInfo.portPriority.portNumber = port->port.thisPort;
- port->anncInfo.portStepsRemoved = pStack->masterStepsRemoved;
- port->anncInfo.infoIs = INFO_IS_MINE;
- port->anncInfo.newInfo = 1;
- port->port.selectedRole = PTP_PORT_ROLE_MASTER; // 10.3.12.1.4 (f2)
- port->port.rcvdPortStateInd = 0;
- // timer hooks - enable, defaults
- if (pStack->hookSetTimer != 0) {
- pStack->hookSetTimer(pStack->cbParam, PTP_TMR_EVENT_TXPDREQ, portIndex, port->md.curLogPdelayReqInterval, 1);
- pStack->hookSetTimer(pStack->cbParam, PTP_TMR_EVENT_TXANNC, portIndex, port->anncInfo.curLogInterval, 1);
- // enabling of RX timer not required
- }
- } else {
- // disable port
- port->anncInfo.infoIs = INFO_IS_DISABLED;
- port->port.selectedRole = PTP_PORT_ROLE_DISABLED;
- // timer hooks - disable (127)
- if (pStack->hookSetTimer != 0) {
- pStack->hookSetTimer(pStack->cbParam, PTP_TMR_EVENT_TXPDREQ, portIndex, 127, 1);
- pStack->hookSetTimer(pStack->cbParam, PTP_TMR_EVENT_TXANNC, portIndex, 127, 1);
- pStack->hookSetTimer(pStack->cbParam, PTP_TMR_EVENT_RXANNC, portIndex, 127, 1);
- }
- tsn_ptp_stack_portroleselection(pStack);
- }
- port->port.enabled = (uint8_t)bEnable; // set enabled flag
- }
- void tsn_ptp_stack_send_pss(tsn_ptp_instance_t *pStack, port_sync_sync_t *pPSS)
- {
- uint32_t idx;
- tsn_ptp_port_t *port;
- // SiteSyncSync: 10.2.6
- for (idx = 0; idx < TSN_PTP_CFG_PORTNUM; ++idx) {
- port = &(pStack->port[idx]);
- if ((port->port.thisPort != pPSS->localPortNum) && (port->port.selectedRole == PTP_PORT_ROLE_MASTER)) {
- portsyncsyncsend(pStack, port, pPSS);
- }
- }
- }
- uint8_t tsn_ptp_msg(uintptr_t hdrAddr)
- {
- uint8_t tmp;
- // info: aligned access, hdraddr expected to be aligned to u16
- tmp = (*(uint8_t *)(hdrAddr + PTPHDR_OFS_MSGID));
- return tmp & PTP_MSGTYPE_MASK;
- }
- uint8_t tsn_ptp_domain(uintptr_t hdrAddr)
- {
- uint8_t tmp;
- // info: aligned access, hdraddr expected to be aligned to u16
- tmp = (*(uint8_t *)(hdrAddr + PTPHDR_OFS_DOMAIN));
- return tmp;
- }
- uint64_t tsn_ptp_clock_offset(tsn_ptp_instance_t *pStack)
- {
- ptp_timestamp_t localtime;
- uint64_t localtime_ns;
- if (!pStack->hookGetLocalTime)
- return 0;
- pStack->hookGetLocalTime(pStack->cbParam, &localtime);
- localtime_ns = ptp_timestamp_to_ns(&localtime);
- return tsn_ptp_clock_get_offset(&pStack->localClock, localtime_ns);
- }
- // ----------------------------------------------------------------
- /**
- * Get sequenceId from PTP header
- *
- * @param hdraddr address of start of PTP header
- * @return sequenceId
- */
- static uint16_t ptp_get_seqid(uintptr_t hdraddr)
- {
- uint16_t tmp;
- // info: aligned access, hdraddr expected to be aligned to u16
- tmp = (*(uint16_t *)(hdraddr + PTPHDR_OFS_SEQID));
- return SWAP16(tmp);
- }
- /**
- * Get correction field from PTP header
- *
- * @param hdraddr address of start of PTP header
- * @param pCorrectionField pointer to correctionField
- */
- static void ptp_get_corfield(uintptr_t hdraddr, int64_t *pCorrectionField)
- {
- uint8_t *pDst8;
- uint8_t *pSrc8;
- uint32_t idx;
- pSrc8 = (uint8_t *)(hdraddr + PTPHDR_OFS_CORFIELD);
- pDst8 = (uint8_t *)pCorrectionField;
- for (idx = 0; idx < 8; idx++) {
- pDst8[idx] = pSrc8[7 - idx]; // swap endianess
- }
- }
- // ----------------------------------------------------------------
- // state machine functions
- /* ---------------- */
- /* MDPdelayResp */
- /* ---------------- */
- static void mdpdelayresp_rcvdPdelayReq(tsn_ptp_instance_t *pStack, tsn_ptp_port_t *pPort, uintptr_t hdrAddr, ptp_timestamp_t *pRxTime)
- {
- // Part of:
- // MDPdelayResp state machine: IEEE 802.1as 11.2.16
- // notes: correction field is currently ignored (= 0)
- struct ptp_header_s hdr;
- uint32_t payload[5] = { 0, 0, 0, 0, 0 };
- uint16_t sequid;
- sequid = ptp_get_seqid(hdrAddr);
- pPort->mdPdResp.seqid = sequid; // copy sequence id
- tsn_ptp_get_portid(hdrAddr + PTPHDR_OFS_SPID, &pPort->mdPdResp.srcPortId);
- // set header PdelayResponse
- hdr = _ptp_default_header;
- hdr.sequenceId = sequid;
- hdr.sourcePortId = pPort->port.thisPortId;
- hdr.msgType = PTP_MSGTYPE_PDELAY_RESP;
- hdr.msgLen = PTP_HEADER_SZ + PTP_PAYLOAD_SZ_PDELAY;
- hdr.flags |= PTP_FLAG_TWO_STEP;
- hdr.control = PTP_CONTROL_OTHER;
- hdr.logMsgInterval = 0x7F;
- hdr.domainNumber = pStack->domainNumber;
- // set payload
- tsn_ptp_set_pdelay_resp((uintptr_t)(&payload), pRxTime, &pPort->mdPdResp.srcPortId);
- // call TX PdelayResponse
- if (pStack->hookTxFrame != 0) {
- pStack->hookTxFrame(pStack->cbParam, pPort->port.portIndex, &hdr, (uint8_t *)&payload, PTP_PAYLOAD_SZ_PDELAY);
- }
- }
- static void mdpdelayresp_rcvdMDTimestampReceive(tsn_ptp_instance_t *pStack, tsn_ptp_port_t *pPort, ptp_timestamp_t *pTxTime)
- {
- // Part of:
- // MDPdelayResp state machine: IEEE 802.1as 11.2.16
- // notes: correction field is currently ignored (= 0)
- struct ptp_header_s hdr;
- uint32_t payload[5] = { 0, 0, 0, 0, 0 };
- // set header PdelayRespFup
- hdr = _ptp_default_header;
- hdr.sequenceId = pPort->mdPdResp.seqid;
- hdr.sourcePortId = pPort->port.thisPortId;
- hdr.msgType = PTP_MSGTYPE_PDELAY_FUP;
- hdr.msgLen = PTP_HEADER_SZ + PTP_PAYLOAD_SZ_PDELAY;
- (void)hdr.flags; // no change, default: PTP_FLAG_PTP_TIMESCALE
- hdr.control = PTP_CONTROL_OTHER;
- hdr.logMsgInterval = 0x7F;
- hdr.domainNumber = pStack->domainNumber;
- // set payload
- tsn_ptp_set_pdelay_resp((uintptr_t)(&payload), pTxTime, &pPort->mdPdResp.srcPortId);
- // call TX PdelayResponseFup
- if (pStack->hookTxFrame != 0) {
- pStack->hookTxFrame(pStack->cbParam, pPort->port.portIndex, &hdr, (uint8_t *)&payload, PTP_PAYLOAD_SZ_PDELAY);
- }
- }
- /* ---------------- */
- /* MDPdelayReq */
- /* ---------------- */
- static void mdpdelayreq_rcvdPdelayResp(tsn_ptp_port_t *pProtocol, uintptr_t hdrAddr, ptp_timestamp_t *pRxTime)
- {
- // Part of:
- // MDPdelayReq state machine: IEEE 802.1as 11.2.15
- int64_t corfield;
- ptp_timestamp_t tstamp;
- uint16_t seqid;
- // get frame infos
- seqid = ptp_get_seqid(hdrAddr);
- // check validity
- // TODO: check reqportid == thisclock/thisport
- if ((seqid == pProtocol->mdPdReq.seqid)) {
- // save peer rx timestamp
- // timestamp from payload + correctionField
- tsn_ptp_get_tstamp(hdrAddr + PTP_HEADER_SZ, &tstamp);
- ptp_get_corfield(hdrAddr, &corfield);
- pProtocol->mdPdReq.time_peer_rxreq = tstamp.seconds * NS_PER_SEC;
- pProtocol->mdPdReq.time_peer_rxreq += tstamp.nanoseconds;
- pProtocol->mdPdReq.time_peer_rxreq += (corfield >> 16);
- // save local rx timestamp
- pProtocol->mdPdReq.time_local_rxresp = pRxTime->seconds * NS_PER_SEC;
- pProtocol->mdPdReq.time_local_rxresp += pRxTime->nanoseconds;
- // set event flag
- pProtocol->mdPdReq.eventflags |= PDREQ_FLAG_RXRESP;
- }
- // no else branch:
- // in case of invalid response we rely on timer and do reset,
- // because measIsRunning==TRUE
- }
- static void mdpdelayreq_rcvdPdelayRespFup(tsn_ptp_port_t *pProtocol, uintptr_t hdrAddr)
- {
- // Part of:
- // MDPdelayReq state machine: IEEE 802.1as 11.2.15
- int64_t corfield;
- ptp_timestamp_t tstamp;
- uint16_t seqid;
- // get frame infos
- seqid = ptp_get_seqid(hdrAddr);
- // check validity
- // TODO: check sourceportid == responseSrcPortId
- if ((seqid == pProtocol->mdPdReq.seqid)) {
- // save peer tx timestamp
- tsn_ptp_get_tstamp(hdrAddr + PTP_HEADER_SZ, &tstamp);
- ptp_get_corfield(hdrAddr, &corfield);
- pProtocol->mdPdReq.time_peer_txresp = tstamp.seconds * NS_PER_SEC;
- pProtocol->mdPdReq.time_peer_txresp += tstamp.nanoseconds;
- pProtocol->mdPdReq.time_peer_txresp += (corfield >> 16);
- // set event flag
- pProtocol->mdPdReq.eventflags |= PDREQ_FLAG_RXRSPFUP;
- }
- // calculate PDelay if all events are complete
- if (pProtocol->mdPdReq.eventflags == PDREQ_MASK_COMPLETE) {
- mdpdelayreq_calculate(pProtocol);
- }
- }
- static int32_t calc_nrr(int64_t diffPeer, int64_t diffLocal)
- {
- // ratio = (double)(diffPeer) / ((double)diffLocal);
- // rateOfs = (ratio-1.0) * 2^32
- int64_t tmp64;
- // difference
- tmp64 = (diffPeer - diffLocal);
- tmp64 <<= 32;
- tmp64 /= diffLocal;
- // high word expected 0 or -1
- // return lower 32 bit
- return (int32_t)tmp64;
- }
- static uint32_t calc_pdelay(int64_t diffPeer, int64_t diffLocal, int32_t rateOfs)
- {
- // pdelay = ((NRR*diffLocal) - diffPeer) / 2.0
- int64_t diff;
- diff = diffLocal * rateOfs;
- diff += (diffLocal << 32);
- diff >>= 32;
- diff -= diffPeer;
- diff /= 2;
- if (diff < 0)
- diff = 0;
- return (uint32_t)diff;
- }
- static void mdpdelayreq_calculate(tsn_ptp_port_t *pProtocol)
- {
- // Part of:
- // MDPdelayReq state machine: IEEE 802.1as 11.2.15
- int64_t diffPeer;
- int64_t diffLocal;
- // computeNeighborRateRatio
- if (pProtocol->port.computeNeighborRateRatio) {
- diffPeer = pProtocol->mdPdReq.time_peer_txresp - pProtocol->mdPdReq.saved_peer_txresp;
- diffLocal = pProtocol->mdPdReq.time_local_rxresp - pProtocol->mdPdReq.saved_local_rxresp;
- if (diffPeer < 10LL * NS_PER_SEC) {
- pProtocol->port.neighborRateOfs32 = calc_nrr(diffPeer, diffLocal);
- pProtocol->mdPdReq.neighborRateRatioValid = 1;
- } else {
- pProtocol->port.neighborRateOfs32 = 0;
- pProtocol->mdPdReq.neighborRateRatioValid = 0;
- }
- }
- pProtocol->mdPdReq.saved_local_rxresp = pProtocol->mdPdReq.time_local_rxresp;
- pProtocol->mdPdReq.saved_peer_txresp = pProtocol->mdPdReq.time_peer_txresp;
- // computeNeighborPropTime
- if (pProtocol->port.computeMeanLinkDelay) {
- diffLocal = pProtocol->mdPdReq.time_local_rxresp - pProtocol->mdPdReq.time_local_txreq;
- diffPeer = pProtocol->mdPdReq.time_peer_txresp - pProtocol->mdPdReq.time_peer_rxreq;
- pProtocol->port.meanLinkDelay = calc_pdelay(diffPeer, diffLocal, pProtocol->port.neighborRateOfs32);
- }
- //
- pProtocol->mdPdReq.lostResponses = 0;
- pProtocol->md.isMeasuringDelay = 1;
- if ((pProtocol->port.meanLinkDelay < pProtocol->md.meanLinkDelayTresh) && (pProtocol->mdPdReq.neighborRateRatioValid)) {
- pProtocol->md.asCapableAcrossDomains = 1;
- pProtocol->md.detectedFaults = 0;
- } else {
- if (pProtocol->md.detectedFaults <= PTP_ALLOW_PREQ_FAULTS) {
- pProtocol->md.detectedFaults++;
- } else {
- pProtocol->md.detectedFaults = 0;
- pProtocol->md.asCapableAcrossDomains = 0;
- }
- }
- // measuring done
- pProtocol->mdPdReq.measIsRunning = 0;
- // clear event flags
- pProtocol->mdPdReq.eventflags = 0;
- }
- static void mdpdelayreq_rcvdMDTimestampReceive(tsn_ptp_port_t *pProtocol, ptp_timestamp_t *pTxTime)
- {
- // Part of:
- // MDPdelayReq state machine: IEEE 802.1as 11.2.15
- // save timestamp (t1)
- pProtocol->mdPdReq.time_local_txreq = pTxTime->seconds * NS_PER_SEC;
- pProtocol->mdPdReq.time_local_txreq += pTxTime->nanoseconds;
- // set event flag
- pProtocol->mdPdReq.eventflags |= PDREQ_FLAG_TXDONE;
- // if for any reason event processing order is inaccurate the TX timestamp may be last event;
- // the pdelay calculation must then be done here
- if (pProtocol->mdPdReq.eventflags == PDREQ_MASK_COMPLETE) {
- mdpdelayreq_calculate(pProtocol);
- }
- }
- static void mdpdelayreq_pdelayIntervalTimer(tsn_ptp_instance_t *pStack, tsn_ptp_port_t *pPort)
- {
- // Part of:
- // MDPdelayReq state machine: IEEE 802.1as 11.2.15
- struct ptp_header_s hdr;
- uint32_t payload[5] = { 0, 0, 0, 0, 0 };
- // check measuring not completely done
- // action: do state RESET
- if (pPort->mdPdReq.measIsRunning) {
- if (pPort->mdPdReq.lostResponses > PTP_ALLOW_LOST_RESP) {
- pPort->md.isMeasuringDelay = 0;
- pPort->md.asCapableAcrossDomains = 0;
- } else {
- pPort->mdPdReq.lostResponses++;
- }
- }
- pPort->mdPdReq.measIsRunning = 0;
- pPort->mdPdReq.seqid++; // increase Sequence ID, do before copying to hdr
- pPort->mdPdReq.eventflags = 0; // clear any pending flags
- // set header PdelayRequest
- hdr = _ptp_default_header;
- hdr.sequenceId = pPort->mdPdReq.seqid;
- hdr.sourcePortId = pPort->port.thisPortId;
- hdr.msgType = PTP_MSGTYPE_PDELAY_REQ;
- hdr.msgLen = PTP_HEADER_SZ + PTP_PAYLOAD_SZ_PDELAY;
- (void)hdr.flags; // no change, default: PTP_FLAG_PTP_TIMESCALE
- hdr.control = PTP_CONTROL_OTHER;
- hdr.logMsgInterval = pPort->md.curLogPdelayReqInterval;
- hdr.domainNumber = pStack->domainNumber;
- // Send Pdelay Request
- if (pStack->hookTxFrame != 0) {
- pPort->mdPdReq.measIsRunning = 1;
- pStack->hookTxFrame(pStack->cbParam, pPort->port.portIndex, &hdr, (uint8_t *)&payload, PTP_PAYLOAD_SZ_PDELAY);
- }
- }
- /* ---------------- */
- /* MDSyncReceive */
- /* ---------------- */
- static void mdsyncreceive_rcvdSync(tsn_ptp_instance_t *pStack, tsn_ptp_port_t *pProtocol, uintptr_t hdrAddr, ptp_timestamp_t *pRxTime)
- {
- // Part of:
- // MDSyncReceive state machine: IEEE 802.1as 11.2.13
- (void)pStack;
- uint16_t seqid;
- uint32_t propDelay;
- // check asCapable
- if (!(pProtocol->port.asCapable)) {
- pProtocol->mdSyncRecv.waitFup = 0;
- return;
- }
- // get frame infos
- seqid = ptp_get_seqid(hdrAddr);
- pProtocol->mdSyncRecv.waitFup = 1;
- pProtocol->mdSyncRecv.seqid = seqid;
- tsn_ptp_get_portid(hdrAddr + PTPHDR_OFS_SPID, &pProtocol->mdSyncRecv.pss.srcPortIdentity); // 11.2.13.2.1 b
- pProtocol->mdSyncRecv.pss.logMsgInterval = *((int8_t *)hdrAddr + PTPHDR_OFS_LOGIVAL); // 11.2.13.2.1 c
- pProtocol->mdSyncRecv.pss.upstreamTxTimeNs = pRxTime->seconds * NS_PER_SEC + pRxTime->nanoseconds; // 11.2.13.2.1 f
- if (pProtocol->port.meanLinkDelay < INT32_MAX) {
- // propDelay = (uint32_t)((double)pProtocol->port.neighborPropDelayNs / pProtocol->port.neighborRateRatio);
- // simplified: (pdelay / neighborRateRation) ~~ pdelay
- // expected values: pdelay (0 .. 5000), nrr (0.9996 .. 1.0004) --> +- 2ns
- propDelay = pProtocol->port.meanLinkDelay;
- pProtocol->mdSyncRecv.pss.upstreamTxTimeNs -= propDelay;
- }
- }
- static void mdsyncreceive_rcvdFollowup(tsn_ptp_instance_t *pStack, tsn_ptp_port_t *pProtocol, uintptr_t hdrAddr)
- {
- // Part of:
- // MDSyncReceive state machine: IEEE 802.1as 11.2.13
- uint16_t seqid;
- struct ptp_followup_s followupData;
- // check waiting for followup
- if (!(pProtocol->mdSyncRecv.waitFup))
- return;
- // TODO: check timeout
- // currentTime >= followupReceiptTimeout
- // check correct sequenceId
- seqid = ptp_get_seqid(hdrAddr);
- if (seqid != pProtocol->mdSyncRecv.seqid)
- return;
- // read followup data
- if (tsn_ptp_get_followup(hdrAddr + PTP_HEADER_SZ, &followupData)) {
- // error reading followup
- return;
- }
- // setMDSyncReceive
- ptp_get_corfield(hdrAddr, &pProtocol->mdSyncRecv.pss.followUpCorrectionField); // 11.2.13.2.1 a
- pProtocol->mdSyncRecv.pss.preciseOriginTimestamp = followupData.preciseOriginTimestamp; // 11.2.13.2.1 d
- pProtocol->mdSyncRecv.pss.scaledRateRatio = followupData.cumScaledRateOfs; // 11.2.13.2.1 e
- pProtocol->mdSyncRecv.pss.gmTimeBaseIndicator = followupData.gmTimeBaseInd; // 11.2.13.2.1 g
- pProtocol->mdSyncRecv.pss.lastGmPhaseChange = followupData.lastGmPhaseCh; // 11.2.13.2.1 h
- pProtocol->mdSyncRecv.pss.scaledLastGmFreqChange = followupData.scaledLastGmFreqCh; // 11.2.13.2.1 i
- // txMDSyncReceive: transmit PSS to portSyncSyncRecv
- // code contains parts of PortSyncSyncRecv (10.2.7) due to optimization
- pProtocol->mdSyncRecv.pss.localPortNum = pProtocol->port.thisPort; // 10.2.7.1 a
- // pProtocol->mdSyncRecv.pss.rateRatio += (pProtocol->port.neighborRateRatio - 1.0); // 10.2.7.1 e
- pProtocol->mdSyncRecv.pss.scaledRateRatio += (pProtocol->port.neighborRateOfs32 << 9); // 10.2.7.1 e
- portsyncsyncrecv_rcvdMdSync(pStack, &(pProtocol->mdSyncRecv.pss));
- // wait for next sync
- pProtocol->mdSyncRecv.waitFup = 0;
- }
- /* ---------------- */
- /* PortSyncSyncRecv */
- /* ---------------- */
- static void portsyncsyncrecv_rcvdMdSync(tsn_ptp_instance_t *pStack, port_sync_sync_t *pPSS)
- {
- // Part of:
- // PortSyncSyncRecv state machine: IEEE 802.1as 10.2.7
- // check field gmPriority.srcPortId
- if (pStack->gmPriority.sourcePortId.clockIdentity != pPSS->srcPortIdentity.clockIdentity)
- return;
- if (pStack->gmPriority.sourcePortId.portNumber != pPSS->srcPortIdentity.portNumber)
- return;
- // 10.2.7.1 a localPortNum, already adjusted before call
- // 10.2.7.1 b,c no need for copying, using pPSS structure
- // 10.2.7.1 d TODO: pPSS->syncReceiptTimeout = ?;
- // 10.2.7.1 e rateRatio, already adjusted before call
- // reset timer
- if (pStack->hookSetTimer != 0) {
- pStack->hookSetTimer(pStack->cbParam, PTP_TMR_EVENT_RXSYNC, 0, pStack->siteSync.logSyncIval, 3);
- }
- if (pStack->hookStatusEvent != 0 && pStack->siteSync.hasSyncRcvd == 0) {
- pStack->hookStatusEvent(pStack->cbParam, PTP_STS_EVENT_SYNCRECV, 0);
- }
- siteSyncPssHandle(pStack, pPSS);
- pStack->siteSync.hasSyncRcvd = 1;
- }
- /* ------------------- */
- /* PortAnnounceReceive */
- /* ------------------- */
- static clock_id rdClockId(uint8_t *ptr)
- {
- uint32_t idx;
- clock_id id;
- uint8_t *pDst;
- pDst = (uint8_t *)(&id);
- for (idx = 0; idx < 8; ++idx) {
- pDst[idx] = ptr[idx];
- }
- return id;
- }
- static void portannouncerecv(tsn_ptp_instance_t *pStack, tsn_ptp_port_t *pPort, uintptr_t hdrAddr)
- {
- uint32_t idx;
- port_id_t srcportid;
- clock_id pathTraceElem;
- struct ptp_announce_s announceInfo;
- ptp_prio_vect_t msgPrioVect;
- int32_t rcvdInfo;
- uint16_t anncFlags;
- int8_t anncLogInterval;
- //
- // qualify announce (10.3.10.2.1)
- //
- if (!(pPort->port.asCapable))
- return; // (state machine)
- // check thisClock != srcPortId.clockId (a)
- tsn_ptp_get_portid(hdrAddr + PTPHDR_OFS_SPID, &srcportid);
- if (srcportid.clockIdentity == pStack->thisClock)
- return;
- // get announce payload info
- if (tsn_ptp_get_announce(hdrAddr + PTP_HEADER_SZ, &announceInfo) < 0)
- return;
- // check stepsremoved < 255 (b)
- if (announceInfo.stepsRemoved >= 255)
- return;
- // check path trace tlv (if present) (c)
- for (idx = 0; idx < announceInfo.pathCount; ++idx) {
- pathTraceElem = rdClockId(announceInfo.pPathSequence + (idx * PTP_PATHTRACE_SZ));
- if (pathTraceElem == pStack->thisClock)
- return;
- }
- // copy path trace tlv when slave port
- if (pPort->port.selectedRole == PTP_PORT_ROLE_SLAVE) {
- // copy all elements from path trace
- for (idx = 0; idx < announceInfo.pathCount; ++idx) {
- pathTraceElem = rdClockId(announceInfo.pPathSequence + (idx * PTP_PATHTRACE_SZ));
- if (idx < TSN_PTP_CFG_PATHTRACE_MAX) {
- pStack->pathTrace[idx] = pathTraceElem;
- }
- }
- // append thisClock (idx == announceInfo.pathCount)
- if (idx < TSN_PTP_CFG_PATHTRACE_MAX) {
- pStack->pathTrace[idx] = pStack->thisClock;
- }
- pStack->pathTraceCount = announceInfo.pathCount + 1;
- }
- // buid messagePriorityVector (see 10.3.5)
- msgPrioVect.rootSystemId.prio1 = announceInfo.gmPrio1;
- msgPrioVect.rootSystemId.prio2 = announceInfo.gmPrio2;
- msgPrioVect.rootSystemId.clockIdentity = announceInfo.gmIdentity;
- msgPrioVect.rootSystemId.clockQuality = announceInfo.clockQuality;
- msgPrioVect.stepsRemoved = announceInfo.stepsRemoved;
- tsn_ptp_get_portid(hdrAddr + PTPHDR_OFS_SPID, &msgPrioVect.sourcePortId);
- msgPrioVect.portNumber = pPort->port.thisPort;
- // rcvdInfo = rcvInfo(); IEEE802.1as 10.13.11.2.1
- rcvdInfo = tsn_ptp_cmp_priovect(&msgPrioVect, &pPort->anncInfo.portPriority);
- anncFlags = tsn_ptp_get_flags(hdrAddr + PTPHDR_OFS_FLAGS);
- anncFlags &= (PTP_FLAG_LEAP61 | PTP_FLAG_LEAP59 | PTP_FLAG_CURUTCO_VALID | PTP_FLAG_FREQ_TRACEABLE | PTP_FLAG_TIME_TRACEABLE);
- anncLogInterval = *((uint8_t *)(hdrAddr + PTPHDR_OFS_LOGIVAL));
- if (rcvdInfo == 0) {
- // REPEATED MASTER INFO
- // check here for update of flags&fields?
- // reset timer
- if (pStack->hookSetTimer != 0) {
- pStack->hookSetTimer(pStack->cbParam, PTP_TMR_EVENT_RXANNC, pPort->port.portIndex, anncLogInterval, 3);
- }
- } else {
- // SUPERIOR MASTER INFO +
- // INFERIOR MASTER INFO - do port role selection
- // copy information
- pPort->anncInfo.portPriority = msgPrioVect;
- pPort->anncInfo.portStepsRemoved = announceInfo.stepsRemoved;
- pPort->anncInfo.infoIs = INFO_IS_RECEIVED;
- // recordOtherAnnounceInfo(); // 10.3.11.2.2
- // leap61, leap59, curUtcOfsValid, timeTraceable, freqTraceable; curUtcOfs; timeSrc
- pPort->anncInfo.annInfo.flags = anncFlags;
- pPort->anncInfo.annInfo.curUtcOfs = announceInfo.currentUtcOfs;
- pPort->anncInfo.annInfo.timeSource = announceInfo.timeSource;
- // PortRoleSelect: reselect
- tsn_ptp_stack_portroleselection(pStack);
- // reset timer
- if (pStack->hookSetTimer != 0) {
- pStack->hookSetTimer(pStack->cbParam, PTP_TMR_EVENT_RXANNC, pPort->port.portIndex, anncLogInterval, 3);
- }
- }
- }
- static void portannouncerecv_timeout(tsn_ptp_instance_t *pStack, tsn_ptp_port_t *pPort)
- {
- // PortAnnounceInformation: IEEE802.1as 10.3.13
- // set info is aged
- pPort->anncInfo.infoIs = INFO_IS_AGED;
- // PortRoleSelect: reselect
- tsn_ptp_stack_portroleselection(pStack);
- }
- static void portannouncesend(tsn_ptp_instance_t *pStack, tsn_ptp_port_t *pPort)
- {
- // PortAnnounceTransmit: IEEE 802.1as 10.3.13
- struct ptp_header_s hdr;
- struct ptp_announce_s announce;
- uint32_t payloadLen;
- uint8_t *ptrPayload;
- // only send, when master
- if (pPort->port.selectedRole != PTP_PORT_ROLE_MASTER)
- return;
- ptrPayload = (uint8_t *)&(pPort->anncInfo.payloadBuf);
- // build payload
- payloadLen = PTP_PAYLOAD_SZ_ANNOUNCE;
- announce.currentUtcOfs = pPort->anncInfo.annInfo.curUtcOfs;
- announce.gmPrio1 = pStack->gmPriority.rootSystemId.prio1;
- announce.gmPrio2 = pStack->gmPriority.rootSystemId.prio2;
- announce.clockQuality = pStack->gmPriority.rootSystemId.clockQuality;
- announce.gmIdentity = pStack->gmPriority.rootSystemId.clockIdentity;
- announce.stepsRemoved = pStack->masterStepsRemoved;
- announce.timeSource = pPort->anncInfo.annInfo.timeSource;
- announce.pPathSequence = (uint8_t *)&pStack->pathTrace;
- announce.pathCount = pStack->pathTraceCount;
- if (announce.pathCount > TSN_PTP_CFG_PATHTRACE_MAX) {
- announce.pathCount = 0; // -> do not send pathTrace TLV
- }
- payloadLen = tsn_ptp_set_announce((uintptr_t)ptrPayload, &announce);
- // set header announce-frame
- hdr = _ptp_default_header;
- hdr.sequenceId = pPort->anncInfo.txSeqId;
- hdr.sourcePortId = pPort->port.thisPortId;
- hdr.msgType = PTP_MSGTYPE_ANNOUNCE;
- hdr.msgLen = PTP_HEADER_SZ + payloadLen;
- hdr.flags |= pPort->anncInfo.annInfo.flags;
- hdr.control = PTP_CONTROL_OTHER;
- hdr.logMsgInterval = pPort->anncInfo.curLogInterval;
- hdr.domainNumber = pStack->domainNumber;
- if (pStack->hookTxFrame != 0) {
- pStack->hookTxFrame(pStack->cbParam, pPort->port.portIndex, &hdr, ptrPayload, payloadLen);
- pPort->anncInfo.txSeqId++;
- }
- }
- /* ------------------- */
- /* PortSyncSyncSend */
- /* ------------------- */
- static void portsyncsyncsend(tsn_ptp_instance_t *pStack, tsn_ptp_port_t *pPort, port_sync_sync_t *pPSS)
- {
- struct ptp_header_s hdr;
- uint32_t payloadBuffer[3] = { 0, 0, 0 };
- //
- // PortSyncSyncSend: 10.2.11
- //
- // check enabled and asCapable
- if (!(pPort->port.enabled))
- return;
- if (!(pPort->port.asCapable))
- return;
- pPort->mdSyncSend.pss = *pPSS; // copy PSS
- pPort->mdSyncSend.pss.srcPortIdentity = pPort->port.thisPortId; // 10.2.11.2.1 a
- pPort->mdSyncSend.pss.logMsgInterval = pPort->port.curLogSyncInterval; // 10.2.11.2.1 b
- // nothing to be done: 10.2.11.2.1 c-f
- // inc sequence ID
- pPort->mdSyncSend.seqid++;
- //
- // MDSyncSend (11.2.14)
- //
- // set header sync-frame
- hdr = _ptp_default_header;
- hdr.sequenceId = pPort->mdSyncSend.seqid;
- hdr.sourcePortId = pPort->mdSyncSend.pss.srcPortIdentity;
- hdr.msgType = PTP_MSGTYPE_SYNC;
- hdr.msgLen = PTP_HEADER_SZ + PTP_PAYLOAD_SZ_SYNC;
- hdr.flags |= PTP_FLAG_TWO_STEP;
- hdr.control = PTP_CONTROL_SYNC;
- hdr.logMsgInterval = pPort->port.curLogSyncInterval;
- hdr.domainNumber = pStack->domainNumber;
- // call hookTx Sync
- if (pStack->hookTxFrame != 0) {
- // call hook
- pStack->hookTxFrame(pStack->cbParam, pPort->port.portIndex, &hdr, (uint8_t *)(&payloadBuffer), PTP_PAYLOAD_SZ_SYNC);
- }
- }
- static int64_t _scale_residence_time(int64_t residenceTime, int32_t scaledRateRatio)
- {
- // residenceTime = pPort->mdSyncSend.pss.rateRatio * residenceTime;
- // scaledRateRatio: scaled to 2^41
- int64_t tmp;
- // scale to 2^32
- scaledRateRatio >>= 9;
- tmp = residenceTime;
- tmp *= scaledRateRatio;
- tmp += (residenceTime << 32);
- tmp >>= 32;
- return tmp;
- }
- static void mdsyncsend_rcvdMDTimestampReceive(tsn_ptp_instance_t *pStack, tsn_ptp_port_t *pPort, ptp_timestamp_t *pTxTime)
- {
- struct ptp_header_s hdr;
- struct ptp_followup_s fupData;
- int64_t residenceTime;
- uint32_t payloadBuffer[12]; // must be large enough for PTP_PAYLOAD_SZ_FOLLOWUP data
- //
- // MDSyncSend (11.2.14)
- //
- // setFollowUp() (11.2.14.2.3)
- // a) followUpCorrectionField
- residenceTime = pTxTime->seconds * NS_PER_SEC;
- residenceTime += pTxTime->nanoseconds;
- residenceTime -= pPort->mdSyncSend.pss.upstreamTxTimeNs;
- // here: residenceTime relative to LocalClock
- // next: scale to GM time
- residenceTime = _scale_residence_time(residenceTime, pPort->mdSyncSend.pss.scaledRateRatio);
- // set header follow-up frame
- hdr = _ptp_default_header;
- hdr.correctionField = pPort->mdSyncSend.pss.followUpCorrectionField + (residenceTime << 16);
- hdr.sequenceId = pPort->mdSyncSend.seqid;
- hdr.sourcePortId = pPort->mdSyncSend.pss.srcPortIdentity;
- hdr.msgType = PTP_MSGTYPE_FOLLOWUP;
- hdr.msgLen = PTP_HEADER_SZ + PTP_PAYLOAD_SZ_FOLLOWUP;
- (void)hdr.flags; // no change, default: PTP_FLAG_PTP_TIMESCALE
- hdr.control = PTP_CONTROL_FOLLOWUP;
- hdr.logMsgInterval = pPort->port.curLogSyncInterval;
- hdr.domainNumber = pStack->domainNumber;
- // set payload
- fupData.preciseOriginTimestamp = pPort->mdSyncSend.pss.preciseOriginTimestamp;
- fupData.cumScaledRateOfs = pPort->mdSyncSend.pss.scaledRateRatio;
- fupData.gmTimeBaseInd = pPort->mdSyncSend.pss.gmTimeBaseIndicator;
- fupData.lastGmPhaseCh = pPort->mdSyncSend.pss.lastGmPhaseChange;
- fupData.scaledLastGmFreqCh = pPort->mdSyncSend.pss.scaledLastGmFreqChange;
- tsn_ptp_set_followup((uintptr_t)(&payloadBuffer), &fupData); // fupData -> payloadBuffer
- // txFollowUp
- if (pStack->hookTxFrame != 0) {
- // call hook
- pStack->hookTxFrame(pStack->cbParam, pPort->port.portIndex, &hdr, (uint8_t *)(&payloadBuffer), PTP_PAYLOAD_SZ_FOLLOWUP);
- }
- }
- /**
- * \brief: Convert timespec to nanoseconds
- *
- * @param ts pointer to timespec
- * @return scalar nanoseconds
- */
- static uint64_t ptp_timestamp_to_ns(ptp_timestamp_t *ts)
- {
- return ((uint64_t)ts->seconds * NS_PER_SEC) + ts->nanoseconds;
- }
- static uint64_t tsn_ptp_clock_get_offset(tsn_ptp_clock_t *domain_clk, uint64_t localtime)
- {
- int64_t timediff;
- timediff = localtime - domain_clk->last_localtime;
- if (domain_clk->rateOfs) {
- timediff *= domain_clk->rateOfs;
- timediff += domain_clk->fractOfs;
- domain_clk->fractOfs = (timediff & 0xFFFFFFFF); // low 32 bits
- timediff >>= 32;
- domain_clk->offset_ns += timediff;
- }
- domain_clk->last_localtime = localtime;
- return domain_clk->offset_ns;
- }
- void tsn_ptp_clock_set_offset(tsn_ptp_clock_t *domain_clk, uint64_t localtime, uint64_t offset)
- {
- domain_clk->offset_ns = offset;
- domain_clk->fractOfs = 0;
- domain_clk->last_localtime = localtime;
- }
- uint64_t tsn_ptp_time_get(tsn_ptp_instance_t *pStack)
- {
- ptp_timestamp_t localtime;
- uint64_t localtime_ns, local_ofs;
- if (!pStack->hookGetLocalTime)
- return 0;
- pStack->hookGetLocalTime(pStack->cbParam, &localtime);
- localtime_ns = ptp_timestamp_to_ns(&localtime);
- local_ofs = tsn_ptp_clock_get_offset(&pStack->localClock, localtime_ns);
- return localtime_ns + local_ofs;
- }
- /* ------------------- */
- /* SiteSync */
- /* ------------------- */
- static void siteSyncIntervalTimer(tsn_ptp_instance_t *pStack)
- {
- port_sync_sync_t portSync;
- ptp_timestamp_t localtime;
- ptp_timestamp_t offset;
- uint64_t localtime_ns;
- uint64_t rtctime;
- //
- // ClockMasterSyncSend 10.2.8; sends when no sync is received by any port
- //
- if (pStack->siteSync.hasSyncRcvd)
- return;
- // get local time from upper layer
- if (!pStack->hookGetLocalTime)
- return;
- pStack->hookGetLocalTime(pStack->cbParam, &localtime);
- if (!pStack->hookGetLocalOffset)
- return;
- pStack->hookGetLocalOffset(pStack->cbParam, &offset);
- localtime_ns = ptp_timestamp_to_ns(&localtime);
- pStack->localClock.offset_ns = ptp_timestamp_to_ns(&offset);
- // set rtc time
- // rtctime = localtime + localpriv->domainclock.offset_ns;
- rtctime = localtime_ns + pStack->localClock.offset_ns;
- // build port sync structure
- portSync.localPortNum = 0; // a
- portSync.preciseOriginTimestamp.nanoseconds = rtctime % NS_PER_SEC; // b
- portSync.preciseOriginTimestamp.seconds = rtctime / NS_PER_SEC; // b
- portSync.followUpCorrectionField = 0; // c
- portSync.srcPortIdentity.clockIdentity = pStack->thisClock; // d
- portSync.srcPortIdentity.portNumber = 0; // e
- portSync.logMsgInterval = pStack->siteSync.logSyncIval; // f
- portSync.upstreamTxTimeNs = localtime_ns; // g
- portSync.syncReceiptTimeout = 0xFFFFFFFFFFFFFFFFLL; // h
- // portSync.rateRatio = site->clock_master.gmRateRatio; // i
- portSync.scaledRateRatio = pStack->siteSync.gmRateOfs << 9; // i
- portSync.gmTimeBaseIndicator = pStack->siteSync.clkTimeBaseInd; // j
- portSync.lastGmPhaseChange = pStack->siteSync.clkSrcPhOfs; // k
- portSync.scaledLastGmFreqChange = pStack->siteSync.clkFrqOfsScaled; // l
- // call GM received PSS
- siteSyncPssHandle(pStack, &portSync);
- }
- static void siteSyncPssHandle(tsn_ptp_instance_t *pStack, port_sync_sync_t *pPSS)
- {
- uint8_t receivingPortRole;
- // reset sync timeout
- pStack->siteSync.hasSyncRcvd = 0;
- // default: port 0
- receivingPortRole = pStack->selectedRole0;
- if ((pPSS->localPortNum > 0) && (pPSS->localPortNum <= TSN_PTP_CFG_PORTNUM)) {
- receivingPortRole = pStack->port[pPSS->localPortNum - 1].port.selectedRole;
- }
- // check gmpresent: gmPrio.priority1 < 255
- // check role == slavePort
- if ((pStack->gmPriority.rootSystemId.prio1 < 255) && (receivingPortRole == PTP_PORT_ROLE_SLAVE)) {
- // slave clock
- siteSyncPssReceive(pStack, pPSS);
- // send PortSyncSync / (== MDSync) structure to all Master ports
- tsn_ptp_stack_send_pss(pStack, pPSS);
- }
- }
- // GM abstraction
- static int32_t _scale_lc_offset_change(int64_t diff, int32_t rateOfs)
- {
- diff *= (int64_t)rateOfs;
- diff >>= 32;
- return (int32_t)diff;
- }
- static void siteSyncPssReceive(tsn_ptp_instance_t *pStack, port_sync_sync_t *pPSS)
- {
- int64_t syncReceiptTime;
- int64_t syncReceiptLocalTime;
- int64_t lc_ofs_ns;
- int32_t lc_ofs_ch;
- int64_t gmTimeDiff;
- int64_t localTimeDiff;
- uint64_t lc_offset;
- uint64_t localtime_ns;
- uint64_t lc_offset_old;
- ptp_timestamp_t localtime;
- // created by this time aware system? -> do nothing
- if (pPSS->localPortNum == 0)
- return;
- // calc syncReceiptTime, syncReceiptLocalTime
- syncReceiptTime = pPSS->preciseOriginTimestamp.seconds * NS_PER_SEC + pPSS->preciseOriginTimestamp.nanoseconds;
- syncReceiptTime += (pPSS->followUpCorrectionField >> 16);
- syncReceiptLocalTime = pPSS->upstreamTxTimeNs;
- // get local time from upper layer
- if (!pStack->hookGetLocalTime)
- return;
- pStack->hookGetLocalTime(pStack->cbParam, &localtime);
- localtime_ns = ptp_timestamp_to_ns(&localtime);
- // set RTC offset to current offset
- // calc RTC-OFFSET
- lc_ofs_ns = syncReceiptTime - syncReceiptLocalTime;
- // take account of gmRateRatio
- lc_ofs_ch = _scale_lc_offset_change(localtime_ns - syncReceiptLocalTime, pStack->siteSync.gmRateOfs);
- lc_ofs_ns -= lc_ofs_ch;
- // calc parts: sec, ns
- lc_offset = (uint64_t)lc_ofs_ns;
- // get old RTC offset, calc gmDifference
- lc_offset_old = tsn_ptp_clock_get_offset(&pStack->localClock, localtime_ns);
- pStack->siteSync.gmOffset = lc_offset - lc_offset_old;
- pStack->siteSync.gmOffsetSum += pStack->siteSync.gmOffset;
- // set new RTC-OFFSET
- tsn_ptp_clock_set_offset(&pStack->localClock, localtime_ns, lc_offset);
- if (pStack->hookStatusEvent != 0 && pStack->enableInvoke) {
- pStack->hookStatusEvent(pStack->cbParam, PTP_STS_EVENT_PHASE_CHANGE, (void *)&lc_offset);
- }
- // calc: gmRateRatio --> ofs change
- gmTimeDiff = syncReceiptTime - pStack->siteSync.savedSyncReceiptTime;
- // skip negative and very large jumps
- if ((gmTimeDiff < 0) || (gmTimeDiff > (32 * PTP_SYNC_ADJ_FREQ_IVAL))) {
- pStack->siteSync.hasSavedSync = 0;
- pStack->siteSync.gmOffsetSum = 0;
- }
- if ((pStack->siteSync.hasSavedSync) && (gmTimeDiff > PTP_SYNC_ADJ_FREQ_IVAL)) {
- // recalc gmRateRatio at around ADJ_FREQ_IVAL
- localTimeDiff = syncReceiptLocalTime - pStack->siteSync.savedSyncReceiptLocalTime;
- // calc gmRateRatio
- // site->clock_master.gmRateRatio = (double)(gmTimeDiff) / (double)localTimeDiff;
- int64_t diff;
- diff = gmTimeDiff - localTimeDiff;
- diff <<= 32;
- diff /= localTimeDiff;
- pStack->siteSync.gmRateOfs = (int32_t)diff;
- // calc rtc_ofs_ch
- // sanity check
- if ((pStack->siteSync.gmRateOfs > -PTP_SYNC_RATE_OFS_TH) && (pStack->siteSync.gmRateOfs < PTP_SYNC_RATE_OFS_TH)) {
- // rtc_adjfine(site->rtc, localpriv->clock_master.gmRateOfs);
- pStack->localClock.rateOfs = pStack->siteSync.gmRateOfs;
- if (pStack->hookStatusEvent != 0 && pStack->enableInvoke) {
- pStack->hookStatusEvent(pStack->cbParam, PTP_STS_EVENT_FREQ_CHANGE, (void *)&pStack->localClock.rateOfs);
- }
- }
- // trigger saving of current timestamp
- pStack->siteSync.hasSavedSync = 0;
- pStack->siteSync.gmOffsetSum = 0;
- }
- // save current receipt timestamps
- if (!(pStack->siteSync.hasSavedSync)) {
- pStack->siteSync.savedSyncReceiptTime = syncReceiptTime;
- pStack->siteSync.savedSyncReceiptLocalTime = syncReceiptLocalTime;
- pStack->siteSync.hasSavedSync = 1;
- }
- }
|