tsn_ptp_stack.c 55 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544
  1. /*!
  2. * Copyright (C) Fraunhofer-Institut for Photonic Microsystems (IPMS)
  3. * Maria-Reiche-Str. 2
  4. * 01109 Dresden
  5. *
  6. * Unauthorized copying of this file, via any medium is strictly prohibited
  7. * Proprietary and confidential
  8. *
  9. * \file tsn_ptp_stack.c
  10. * \author zimmerli
  11. * \date 2019-01-17
  12. * \brief IEEE 802.1as software protocol stack
  13. *
  14. */
  15. #include "tsn_ptp_stack.h"
  16. #define SWAP16(value) (((value & 0xFF) << 8 | (value >> 8)) & 0xFFFF)
  17. #define PTPHDR_OFS_MSGID 0
  18. #define PTPHDR_OFS_MSGLEN 2
  19. #define PTPHDR_OFS_DOMAIN 4
  20. #define PTPHDR_OFS_FLAGS 6
  21. #define PTPHDR_OFS_CORFIELD 8
  22. #define PTPHDR_OFS_SPID 20
  23. #define PTPHDR_OFS_SEQID 30
  24. #define PTPHDR_OFS_LOGIVAL 33
  25. #define PTPHDR_OFS_FUP_TLV (34 + 10)
  26. #define PTPHDR_OFS_ANNC_STEP_REM (34 + 27)
  27. #define NS_PER_SEC (1000000000LL)
  28. // PDelay-Request State-Machine events
  29. // do calculation of Pdelay, neighbor rate ratio only on complete event list
  30. #define PDREQ_FLAG_TXDONE (1 << 0)
  31. #define PDREQ_FLAG_RXRESP (1 << 1)
  32. #define PDREQ_FLAG_RXRSPFUP (1 << 2)
  33. #define PDREQ_MASK_COMPLETE (0x7)
  34. // Delay mechanism defines IEEE 802.1as-2020 14.8.5
  35. #define PTP_DELAY_MECH_P2P 2
  36. #define PTP_DELAY_MECH_COMP2P 3
  37. enum announce_info_is_e {
  38. INFO_IS_DISABLED = 0,
  39. INFO_IS_MINE = 1,
  40. INFO_IS_RECEIVED = 2,
  41. INFO_IS_AGED = 3
  42. };
  43. // ----------------------------------------------------------------
  44. // declarations
  45. static struct ptp_header_s _ptp_default_header = {
  46. // set default header information
  47. .majorSdoId = PTP_MAJOR_SDO_ID,
  48. .minorSdoId = PTP_MINOR_SDO_ID,
  49. .domainNumber = 0,
  50. .minorVersionPTP = 1,
  51. .version = PTP_VERSION,
  52. .correctionField = 0,
  53. .sequenceId = 0,
  54. .sourcePortId = { 0, 0 },
  55. .msgType = 0,
  56. .msgLen = PTP_HEADER_SZ,
  57. .flags = PTP_FLAG_PTP_TIMESCALE,
  58. .control = PTP_CONTROL_OTHER,
  59. .logMsgInterval = 0x7F
  60. };
  61. // ----------------------------------------------------------------
  62. // function declarations
  63. static uint16_t ptp_get_seqid(uintptr_t hdraddr);
  64. static void ptp_get_corfield(uintptr_t hdraddr, int64_t *pCorrectionField);
  65. // state machine functions
  66. static void mdpdelayresp_rcvdPdelayReq(tsn_ptp_instance_t *pStack, tsn_ptp_port_t *pPort, uintptr_t hdrAddr, ptp_timestamp_t *pRxTime);
  67. static void mdpdelayresp_rcvdMDTimestampReceive(tsn_ptp_instance_t *pStack, tsn_ptp_port_t *pPort, ptp_timestamp_t *pTxTime);
  68. static void mdpdelayreq_rcvdPdelayResp(tsn_ptp_port_t *pProtocol, uintptr_t hdrAddr, ptp_timestamp_t *pRxTime);
  69. static void mdpdelayreq_rcvdPdelayRespFup(tsn_ptp_port_t *pProtocol, uintptr_t hdrAddr);
  70. static void mdpdelayreq_calculate(tsn_ptp_port_t *pProtocol);
  71. static void mdpdelayreq_rcvdMDTimestampReceive(tsn_ptp_port_t *pProtocol, ptp_timestamp_t *pTxTime);
  72. static void mdpdelayreq_pdelayIntervalTimer(tsn_ptp_instance_t *pStack, tsn_ptp_port_t *pPort);
  73. static void mdsyncreceive_rcvdSync(tsn_ptp_instance_t *pStack, tsn_ptp_port_t *pProtocol, uintptr_t hdrAddr, ptp_timestamp_t *pRxTime);
  74. static void mdsyncreceive_rcvdFollowup(tsn_ptp_instance_t *pStack, tsn_ptp_port_t *pProtocol, uintptr_t hdrAddr);
  75. static void portsyncsyncrecv_rcvdMdSync(tsn_ptp_instance_t *pStack, port_sync_sync_t *pPSS);
  76. static void portannouncerecv(tsn_ptp_instance_t *pStack, tsn_ptp_port_t *pPort, uintptr_t hdrAddr);
  77. static void portannouncerecv_timeout(tsn_ptp_instance_t *pStack, tsn_ptp_port_t *pPort);
  78. static void portannouncesend(tsn_ptp_instance_t *pStack, tsn_ptp_port_t *pPort);
  79. static void portsyncsyncsend(tsn_ptp_instance_t *pStack, tsn_ptp_port_t *pPort, port_sync_sync_t *pPSS);
  80. static void mdsyncsend_rcvdMDTimestampReceive(tsn_ptp_instance_t *pStack, tsn_ptp_port_t *pPort, ptp_timestamp_t *pTxTime);
  81. static void siteSyncIntervalTimer(tsn_ptp_instance_t *pStack);
  82. static void siteSyncPssHandle(tsn_ptp_instance_t *pStack, port_sync_sync_t *pPSS);
  83. static void siteSyncPssReceive(tsn_ptp_instance_t *pStack, port_sync_sync_t *pPSS);
  84. static uint64_t tsn_ptp_clock_get_offset(tsn_ptp_clock_t *domain_clk, uint64_t localtime);
  85. static uint64_t ptp_timestamp_to_ns(ptp_timestamp_t *ts);
  86. // static void signalingrecv(tsn_ptp_port_t *pPort, uintptr_t hdrAddr);
  87. // ----------------------------------------------------------------
  88. void tsn_ptp_stack_init(tsn_ptp_instance_t *pStack, uint8_t *pMacAddr, uint8_t domainNumber)
  89. {
  90. uint32_t idx;
  91. tsn_ptp_port_t *port;
  92. uint16_t pnum; // port number
  93. // set clock identity
  94. tsn_ptp_mac_to_clockid(pMacAddr, (uint8_t *)(&pStack->thisClock));
  95. // init hook defaults
  96. pStack->cbParam = 0;
  97. pStack->hookSetTimer = 0;
  98. pStack->hookGetLocalTime = 0;
  99. pStack->hookGetLocalOffset = 0;
  100. pStack->hookStatusEvent = 0;
  101. pStack->hookTxFrame = 0;
  102. // init system -> default values
  103. pStack->systemId.prio1 = 254;
  104. pStack->systemId.prio2 = 255;
  105. pStack->systemId.clockQuality.clockClass = 248;
  106. pStack->systemId.clockQuality.clockAccuracy = 254;
  107. pStack->systemId.clockQuality.offsetScaledLogVariance = 17258;
  108. pStack->systemId.clockIdentity = pStack->thisClock;
  109. pStack->gmPriority.rootSystemId = pStack->systemId;
  110. pStack->gmPriority.stepsRemoved = 0;
  111. pStack->gmPriority.sourcePortId.clockIdentity = pStack->thisClock;
  112. pStack->gmPriority.sourcePortId.portNumber = 0;
  113. pStack->gmPriority.portNumber = 0;
  114. pStack->masterStepsRemoved = 0;
  115. pStack->gmChanges = 0;
  116. pStack->pathTrace[0] = pStack->thisClock;
  117. pStack->pathTraceCount = 1;
  118. pStack->selectedRole0 = PTP_PORT_ROLE_SLAVE; // default: system clock is slave
  119. // system flags and fields - defaults
  120. pStack->sysInfo.curUtcOfs = 37; // latest known value - 2017-01-01
  121. pStack->sysInfo.timeSource = PTP_SRC_OTHER;
  122. pStack->sysInfo.flags = PTP_FLAG_TIME_TRACEABLE | PTP_FLAG_FREQ_TRACEABLE; // leap59/61 unknown, utc valid unknown
  123. pStack->announceInfo = pStack->sysInfo;
  124. pStack->domainNumber = domainNumber;
  125. pStack->enableInvoke = 0;
  126. // SiteSync initialization
  127. pStack->siteSync.gmRateOfs = 0;
  128. pStack->siteSync.hasSavedSync = 0;
  129. pStack->siteSync.hasSyncRcvd = 0;
  130. pStack->siteSync.clkSrcPhOfs.fns = 0;
  131. pStack->siteSync.clkSrcPhOfs.ns_msb = 0;
  132. pStack->siteSync.clkSrcPhOfs.ns_lsb = 0;
  133. pStack->siteSync.clkTimeBaseInd = 0;
  134. pStack->siteSync.clkFrqOfsScaled = 0;
  135. pStack->siteSync.gmOffset = 0;
  136. pStack->siteSync.gmOffsetSum = 0;
  137. pStack->siteSync.logSyncIval = PTP_INIT_INTVAL_SYNC;
  138. // LocalClock initialization
  139. pStack->localClock.offset_ns = 0;
  140. pStack->localClock.rateOfs = 0;
  141. pStack->localClock.fractOfs = 0;
  142. // init ports
  143. for (idx = 0; idx < TSN_PTP_CFG_PORTNUM; ++idx) {
  144. port = &(pStack->port[idx]);
  145. pnum = idx + 1; // Port number: 1 .. N
  146. // port
  147. port->port.thisPort = pnum; // Port number: 1 .. N
  148. port->port.thisPortId.clockIdentity = pStack->thisClock;
  149. port->port.thisPortId.portNumber = pnum;
  150. port->port.asCapable = 1;
  151. port->port.enabled = 0;
  152. port->port.curLogSyncInterval = PTP_INIT_INTVAL_SYNC;
  153. port->port.neighborRateOfs32 = 0;
  154. port->port.portIndex = idx;
  155. port->port.meanLinkDelay = 0;
  156. port->port.computeNeighborRateRatio = 1;
  157. port->port.computeMeanLinkDelay = 1;
  158. port->port.selectedRole = PTP_PORT_ROLE_DISABLED;
  159. port->port.delayMechanism = PTP_DELAY_MECH_P2P;
  160. port->port.rcvdPortStateInd = 0;
  161. port->port.rcvdPortState = PTP_PORT_ROLE_DISABLED;
  162. // md
  163. port->md.curLogPdelayReqInterval = PTP_INIT_INTVAL_PDELAY;
  164. port->md.isMeasuringDelay = 0;
  165. port->md.meanLinkDelayTresh = 10 * 1000; // init as 10us fixed
  166. port->md.syncSeqId = 0x1234; // random
  167. port->md.asCapableAcrossDomains = 0;
  168. // init mdPdReqSm
  169. port->mdPdReq.seqid = 0x2345; // random
  170. port->mdPdReq.measIsRunning = 0;
  171. port->mdPdReq.lostResponses = 0;
  172. port->mdPdReq.neighborRateRatioValid = 0;
  173. port->mdPdReq.saved_local_rxresp = 0;
  174. port->mdPdReq.saved_peer_txresp = 0;
  175. port->mdPdReq.eventflags = 0;
  176. // init mdPdRespSm
  177. port->mdPdResp.seqid = 0;
  178. // init mdSyncRecv
  179. port->mdSyncRecv.seqid = 0;
  180. port->mdSyncRecv.waitFup = 0;
  181. // init mdSyncSend
  182. port->mdSyncSend.seqid = 0x6789; // random
  183. // init anncInfo (see IEEE 802.1as 10.3.4)
  184. port->anncInfo.newInfo = 0;
  185. port->anncInfo.infoIs = INFO_IS_DISABLED;
  186. port->anncInfo.txSeqId = 0x4567; // random
  187. port->anncInfo.curLogInterval = PTP_INIT_INTVAL_ANNC;
  188. }
  189. }
  190. void tsn_ptp_stack_enable(tsn_ptp_instance_t *pStack, uint16_t bEnable)
  191. {
  192. if (bEnable) {
  193. // timer hooks - enable, defaults
  194. if (pStack->hookSetTimer != 0) {
  195. pStack->hookSetTimer(pStack->cbParam, PTP_TMR_EVENT_TXSYNC, 0, pStack->siteSync.logSyncIval, 1);
  196. }
  197. } else {
  198. // timer hooks - disable (127)
  199. if (pStack->hookSetTimer != 0) {
  200. pStack->hookSetTimer(pStack->cbParam, PTP_TMR_EVENT_TXSYNC, 0, 127, 1);
  201. pStack->hookSetTimer(pStack->cbParam, PTP_TMR_EVENT_RXSYNC, 0, 127, 1);
  202. }
  203. }
  204. }
  205. void tsn_ptp_stack_rxframe(tsn_ptp_instance_t *pStack, uint16_t portIndex, uintptr_t hdrAddr, uint32_t length, ptp_timestamp_t *pRxTime)
  206. {
  207. (void)length;
  208. (void)pStack;
  209. uint8_t msgType;
  210. tsn_ptp_port_t *pPort;
  211. if (portIndex >= TSN_PTP_CFG_PORTNUM)
  212. return;
  213. pPort = &(pStack->port[portIndex]);
  214. if (!pPort->port.enabled)
  215. return;
  216. // get msgType and sequence id
  217. msgType = (*(uint8_t *)(hdrAddr + PTPHDR_OFS_MSGID));
  218. msgType &= PTP_MSGTYPE_MASK;
  219. if (msgType == PTP_MSGTYPE_SYNC) {
  220. // MDSyncReceive state machine: IEEE 802.1as 11.2.13
  221. mdsyncreceive_rcvdSync(pStack, pPort, hdrAddr, pRxTime);
  222. } else if (msgType == PTP_MSGTYPE_PDELAY_REQ) {
  223. // MDPdelayResp state machine: IEEE 802.1as 11.2.16
  224. mdpdelayresp_rcvdPdelayReq(pStack, pPort, hdrAddr, pRxTime);
  225. } else if (msgType == PTP_MSGTYPE_PDELAY_RESP) {
  226. // MDPdelayResp state machine: IEEE 802.1as 11.2.15
  227. mdpdelayreq_rcvdPdelayResp(pPort, hdrAddr, pRxTime);
  228. } else if (msgType == PTP_MSGTYPE_FOLLOWUP) {
  229. // MDSyncReceive state machine: IEEE 802.1as 11.2.13
  230. mdsyncreceive_rcvdFollowup(pStack, pPort, hdrAddr);
  231. } else if (msgType == PTP_MSGTYPE_PDELAY_FUP) {
  232. // MDPdelayResp state machine: IEEE 802.1as 11.2.15
  233. mdpdelayreq_rcvdPdelayRespFup(pPort, hdrAddr);
  234. //TODO: optimize according IEEE 802.1as-2020 11.2.2
  235. if (pPort->md.asCapableAcrossDomains) // && pStack->domainNumber == 0)
  236. pPort->port.asCapable = 1;
  237. } else if (msgType == PTP_MSGTYPE_ANNOUNCE) {
  238. // PortAnnounceReceive: IEEE 802.1as 10.3.10
  239. // PortAnnounceInformation: IEEE 802.1as 10.3.11
  240. portannouncerecv(pStack, pPort, hdrAddr);
  241. } else if (msgType == PTP_MSGTYPE_SIGNALING) {
  242. // TODO: LinkDelayIntervalSetting : IEEE 802.1as 11.2.17
  243. // TODO: AnnounceIntervalSetting : IEEE 802.1as 10.3.14
  244. // signalingrecv(pPort, hdrAddr);
  245. }
  246. }
  247. void tsn_ptp_stack_txdone(tsn_ptp_instance_t *pStack, tsn_ptp_port_t *pPort, uint8_t msgType, ptp_timestamp_t *pTxTime)
  248. {
  249. if (msgType == PTP_MSGTYPE_SYNC) {
  250. // MDSyncSend 11.2.14
  251. mdsyncsend_rcvdMDTimestampReceive(pStack, pPort, pTxTime);
  252. } else if (msgType == PTP_MSGTYPE_PDELAY_RESP) {
  253. // MDPdelayResp state machine: IEEE 802.1as 11.2.16
  254. mdpdelayresp_rcvdMDTimestampReceive(pStack, pPort, pTxTime);
  255. } else if (msgType == PTP_MSGTYPE_PDELAY_REQ) {
  256. // MDPdelayReq state machine: IEEE 802.1as 11.2.15
  257. mdpdelayreq_rcvdMDTimestampReceive(pPort, pTxTime);
  258. }
  259. }
  260. void tsn_ptp_stack_portroleselection(tsn_ptp_instance_t *pStack)
  261. {
  262. uint32_t idx;
  263. int32_t cmp;
  264. ptp_prio_vect_t gmPriorityVector;
  265. ptp_prio_vect_t prioVect; // used as gmPathPriorityVector and masterPriorityVector
  266. tsn_ptp_port_t *port;
  267. time_info_t tmInfo;
  268. uint16_t portNum;
  269. uint8_t updtInfo; // used as bool
  270. // clearReselectTree(); not needed
  271. // setSelectedTree(); not needed - as port update is done within this function
  272. // updtRolesTree(); IEEE802.1as: 10.3.12.1.4
  273. // a) gmPathPrioVect for every port
  274. // SEARCH BEST GM from set <system, port 1 .. N>
  275. // only use ports, where infoIs received
  276. // init: use system as GM
  277. portNum = 0;
  278. gmPriorityVector.rootSystemId = pStack->systemId;
  279. gmPriorityVector.stepsRemoved = 0;
  280. gmPriorityVector.sourcePortId.clockIdentity = pStack->thisClock;
  281. gmPriorityVector.sourcePortId.portNumber = 1; //0;
  282. gmPriorityVector.portNumber = 0;
  283. tmInfo = pStack->sysInfo;
  284. for (idx = 0; idx < TSN_PTP_CFG_PORTNUM; ++idx) {
  285. // port pointer
  286. port = &(pStack->port[idx]);
  287. // check info is received; but not my own clockId
  288. if ((port->anncInfo.infoIs == INFO_IS_RECEIVED) && (port->anncInfo.portPriority.sourcePortId.clockIdentity != pStack->thisClock)) {
  289. // gmPathPrioVect (is prioVect)
  290. prioVect = port->anncInfo.portPriority;
  291. prioVect.stepsRemoved += 1; // increment stepsRemoved, see 10.3.5
  292. // compare gmPathPrio and current gmPriorityVector
  293. cmp = tsn_ptp_cmp_priovect(&prioVect, &gmPriorityVector);
  294. if (cmp < 0) {
  295. // received priority vector from port is better than actual vector
  296. // copy to gmPriorityVector, update portNum, copy time information (flags, ...)
  297. gmPriorityVector = prioVect;
  298. portNum = port->port.thisPort;
  299. tmInfo = port->anncInfo.annInfo;
  300. }
  301. } // if
  302. } // for
  303. // check for GM change --> increment counter
  304. if (pStack->gmPriority.rootSystemId.clockIdentity != gmPriorityVector.rootSystemId.clockIdentity) {
  305. pStack->gmChanges++;
  306. }
  307. // b) gmPriority = gmPriorityVector
  308. pStack->gmPriority = gmPriorityVector;
  309. // c) set global vars&fields for announce (from Slave-Port or System)
  310. pStack->announceInfo = tmInfo;
  311. // d) compute masterPrioVect for each port
  312. // masterPrioVect: is prioVect
  313. prioVect.rootSystemId = gmPriorityVector.rootSystemId;
  314. prioVect.stepsRemoved = gmPriorityVector.stepsRemoved;
  315. prioVect.sourcePortId.clockIdentity = pStack->thisClock;
  316. // e) compute masterStepsRemoved (portStepsRem + 1 | 0)
  317. // same as gmPriorityVector.stepsRemoved
  318. pStack->masterStepsRemoved = gmPriorityVector.stepsRemoved;
  319. // f) update roles
  320. for (idx = 0; idx < TSN_PTP_CFG_PORTNUM; ++idx) {
  321. // port pointer
  322. port = &(pStack->port[idx]);
  323. updtInfo = 0;
  324. // IEEE802.1as-2020: 10.3.15
  325. if (port->port.rcvdPortStateInd) {
  326. port->port.selectedRole = port->port.rcvdPortState;
  327. continue;
  328. }
  329. // d) compute masterPrioVect for each port
  330. // masterPrioVect: is prioVect
  331. prioVect.portNumber = port->port.thisPort;
  332. prioVect.sourcePortId.portNumber = port->port.thisPort;
  333. if (port->anncInfo.infoIs == INFO_IS_DISABLED) {
  334. // f3) infois==disabled --> role = disabledport
  335. port->port.selectedRole = PTP_PORT_ROLE_DISABLED;
  336. } else if (port->anncInfo.infoIs == INFO_IS_AGED) {
  337. // f4) infois==aged --> role = master + updtInfo
  338. port->port.selectedRole = PTP_PORT_ROLE_MASTER;
  339. updtInfo = 1;
  340. } else if (port->anncInfo.infoIs == INFO_IS_MINE) {
  341. // f5) infois==mine --> role = master + updtInfo
  342. port->port.selectedRole = PTP_PORT_ROLE_MASTER;
  343. updtInfo = 1;
  344. } else if (port->anncInfo.infoIs == INFO_IS_RECEIVED) {
  345. // f6-9) infois==received
  346. if (port->port.thisPort == portNum) {
  347. // f6) gmPrio derived from port --> slave
  348. port->port.selectedRole = PTP_PORT_ROLE_SLAVE;
  349. updtInfo = 0;
  350. } else {
  351. if (tsn_ptp_cmp_priovect(&prioVect, &(port->anncInfo.portPriority)) < 0) {
  352. // f9) masterPrio better then portPrio --> master
  353. port->port.selectedRole = PTP_PORT_ROLE_MASTER;
  354. updtInfo = 1;
  355. } else {
  356. // f7-8) else --> passive
  357. port->port.selectedRole = PTP_PORT_ROLE_PASSIVE;
  358. }
  359. }
  360. }
  361. if (updtInfo) {
  362. // update info per port (when updtInfo==TRUE)
  363. // portPrio = masterPrio, portStepsRem = masterStepRem, infoIs=mine, newInfo=true
  364. port->anncInfo.portPriority = prioVect;
  365. port->anncInfo.portStepsRemoved = pStack->masterStepsRemoved;
  366. port->anncInfo.infoIs = INFO_IS_MINE;
  367. port->anncInfo.newInfo = 1;
  368. }
  369. }
  370. // g) SKIPPED gmPresent true if gmPrio1 < 255
  371. // h) role port0: any slave-port --> role = passive; else role = slave
  372. if (portNum > 0) {
  373. pStack->selectedRole0 = PTP_PORT_ROLE_PASSIVE;
  374. } else {
  375. pStack->selectedRole0 = PTP_PORT_ROLE_SLAVE;
  376. }
  377. // i) set pathtrace if grandmaster (gmPrio.sys.clkid == thisClock)
  378. if (gmPriorityVector.rootSystemId.clockIdentity == pStack->thisClock) {
  379. pStack->pathTrace[0] = pStack->thisClock;
  380. pStack->pathTraceCount = 1;
  381. }
  382. // all master-ports -> set tx timer announce (immediately)
  383. for (idx = 0; idx < TSN_PTP_CFG_PORTNUM; ++idx) {
  384. // port pointer
  385. port = &(pStack->port[idx]);
  386. if (pStack->hookSetTimer != 0 && port->port.enabled) {
  387. pStack->hookSetTimer(pStack->cbParam, PTP_TMR_EVENT_TXANNC, idx, port->anncInfo.curLogInterval, 0);
  388. }
  389. }
  390. }
  391. //TODO: split timerevent to disable portIndex for site timer event
  392. void tsn_ptp_stack_timerevent(tsn_ptp_instance_t *pStack, ptp_timer_event_t tmrEvent, uint32_t id)
  393. {
  394. tsn_ptp_port_t *pPort;
  395. if (tmrEvent == PTP_TMR_EVENT_TXSYNC) {
  396. if (pStack->hookSetTimer != 0) {
  397. pStack->hookSetTimer(pStack->cbParam, PTP_TMR_EVENT_TXSYNC, 0, pStack->siteSync.logSyncIval, 1);
  398. }
  399. siteSyncIntervalTimer(pStack);
  400. return;
  401. }
  402. if (tmrEvent == PTP_TMR_EVENT_RXSYNC) {
  403. // Will only be counted
  404. // no action - see 11.2.13
  405. if (pStack->hookStatusEvent != 0) {
  406. pStack->hookStatusEvent(pStack->cbParam, PTP_STS_EVENT_SYNCLOST, 0);
  407. pStack->siteSync.hasSyncRcvd = 0;
  408. }
  409. }
  410. // check id and get port pointer for the following events
  411. if (id >= TSN_PTP_CFG_PORTNUM)
  412. return;
  413. pPort = &(pStack->port[id]);
  414. if (tmrEvent == PTP_TMR_EVENT_TXPDREQ) {
  415. // reset timer
  416. if (pStack->hookSetTimer != 0) {
  417. pStack->hookSetTimer(pStack->cbParam, PTP_TMR_EVENT_TXPDREQ, id, pPort->md.curLogPdelayReqInterval, 1);
  418. }
  419. // MDPdelayReq state machine: IEEE 802.1as 11.2.15
  420. mdpdelayreq_pdelayIntervalTimer(pStack, pPort);
  421. }
  422. if (tmrEvent == PTP_TMR_EVENT_RXANNC) {
  423. // PortAnnounceInformation: IEEE 802.1as 10.3.11
  424. portannouncerecv_timeout(pStack, pPort);
  425. }
  426. if (tmrEvent == PTP_TMR_EVENT_TXANNC) {
  427. // PortAnnounceTransmit: IEEE 802.1as 10.3.13
  428. portannouncesend(pStack, pPort);
  429. // reset timer
  430. if (pPort->port.selectedRole == PTP_PORT_ROLE_MASTER) {
  431. // reset timer
  432. if (pStack->hookSetTimer != 0) {
  433. pStack->hookSetTimer(pStack->cbParam, PTP_TMR_EVENT_TXANNC, id, pPort->anncInfo.curLogInterval, 1);
  434. }
  435. }
  436. }
  437. if (tmrEvent == PTP_TMR_EVENT_TXSYNC) {
  438. siteSyncIntervalTimer(pStack);
  439. }
  440. }
  441. void tsn_ptp_stack_port_enable(tsn_ptp_instance_t *pStack, uint16_t portIndex, uint16_t bEnable)
  442. {
  443. tsn_ptp_port_t *port;
  444. // check index
  445. if (portIndex >= TSN_PTP_CFG_PORTNUM)
  446. return;
  447. port = (tsn_ptp_port_t *)(&pStack->port[portIndex]);
  448. if (bEnable) {
  449. // enable
  450. // set default intervals
  451. port->md.curLogPdelayReqInterval = PTP_INIT_INTVAL_PDELAY;
  452. port->anncInfo.curLogInterval = PTP_INIT_INTVAL_ANNC;
  453. // announce info: copy master prio
  454. port->anncInfo.portPriority = pStack->gmPriority;
  455. port->anncInfo.portPriority.portNumber = port->port.thisPort;
  456. port->anncInfo.portStepsRemoved = pStack->masterStepsRemoved;
  457. port->anncInfo.infoIs = INFO_IS_MINE;
  458. port->anncInfo.newInfo = 1;
  459. port->port.selectedRole = PTP_PORT_ROLE_MASTER; // 10.3.12.1.4 (f2)
  460. port->port.rcvdPortStateInd = 0;
  461. // timer hooks - enable, defaults
  462. if (pStack->hookSetTimer != 0) {
  463. pStack->hookSetTimer(pStack->cbParam, PTP_TMR_EVENT_TXPDREQ, portIndex, port->md.curLogPdelayReqInterval, 1);
  464. pStack->hookSetTimer(pStack->cbParam, PTP_TMR_EVENT_TXANNC, portIndex, port->anncInfo.curLogInterval, 1);
  465. // enabling of RX timer not required
  466. }
  467. } else {
  468. // disable port
  469. port->anncInfo.infoIs = INFO_IS_DISABLED;
  470. port->port.selectedRole = PTP_PORT_ROLE_DISABLED;
  471. // timer hooks - disable (127)
  472. if (pStack->hookSetTimer != 0) {
  473. pStack->hookSetTimer(pStack->cbParam, PTP_TMR_EVENT_TXPDREQ, portIndex, 127, 1);
  474. pStack->hookSetTimer(pStack->cbParam, PTP_TMR_EVENT_TXANNC, portIndex, 127, 1);
  475. pStack->hookSetTimer(pStack->cbParam, PTP_TMR_EVENT_RXANNC, portIndex, 127, 1);
  476. }
  477. tsn_ptp_stack_portroleselection(pStack);
  478. }
  479. port->port.enabled = (uint8_t)bEnable; // set enabled flag
  480. }
  481. void tsn_ptp_stack_send_pss(tsn_ptp_instance_t *pStack, port_sync_sync_t *pPSS)
  482. {
  483. uint32_t idx;
  484. tsn_ptp_port_t *port;
  485. // SiteSyncSync: 10.2.6
  486. for (idx = 0; idx < TSN_PTP_CFG_PORTNUM; ++idx) {
  487. port = &(pStack->port[idx]);
  488. if ((port->port.thisPort != pPSS->localPortNum) && (port->port.selectedRole == PTP_PORT_ROLE_MASTER)) {
  489. portsyncsyncsend(pStack, port, pPSS);
  490. }
  491. }
  492. }
  493. uint8_t tsn_ptp_msg(uintptr_t hdrAddr)
  494. {
  495. uint8_t tmp;
  496. // info: aligned access, hdraddr expected to be aligned to u16
  497. tmp = (*(uint8_t *)(hdrAddr + PTPHDR_OFS_MSGID));
  498. return tmp & PTP_MSGTYPE_MASK;
  499. }
  500. uint8_t tsn_ptp_domain(uintptr_t hdrAddr)
  501. {
  502. uint8_t tmp;
  503. // info: aligned access, hdraddr expected to be aligned to u16
  504. tmp = (*(uint8_t *)(hdrAddr + PTPHDR_OFS_DOMAIN));
  505. return tmp;
  506. }
  507. uint64_t tsn_ptp_clock_offset(tsn_ptp_instance_t *pStack)
  508. {
  509. ptp_timestamp_t localtime;
  510. uint64_t localtime_ns;
  511. if (!pStack->hookGetLocalTime)
  512. return 0;
  513. pStack->hookGetLocalTime(pStack->cbParam, &localtime);
  514. localtime_ns = ptp_timestamp_to_ns(&localtime);
  515. return tsn_ptp_clock_get_offset(&pStack->localClock, localtime_ns);
  516. }
  517. // ----------------------------------------------------------------
  518. /**
  519. * Get sequenceId from PTP header
  520. *
  521. * @param hdraddr address of start of PTP header
  522. * @return sequenceId
  523. */
  524. static uint16_t ptp_get_seqid(uintptr_t hdraddr)
  525. {
  526. uint16_t tmp;
  527. // info: aligned access, hdraddr expected to be aligned to u16
  528. tmp = (*(uint16_t *)(hdraddr + PTPHDR_OFS_SEQID));
  529. return SWAP16(tmp);
  530. }
  531. /**
  532. * Get correction field from PTP header
  533. *
  534. * @param hdraddr address of start of PTP header
  535. * @param pCorrectionField pointer to correctionField
  536. */
  537. static void ptp_get_corfield(uintptr_t hdraddr, int64_t *pCorrectionField)
  538. {
  539. uint8_t *pDst8;
  540. uint8_t *pSrc8;
  541. uint32_t idx;
  542. pSrc8 = (uint8_t *)(hdraddr + PTPHDR_OFS_CORFIELD);
  543. pDst8 = (uint8_t *)pCorrectionField;
  544. for (idx = 0; idx < 8; idx++) {
  545. pDst8[idx] = pSrc8[7 - idx]; // swap endianess
  546. }
  547. }
  548. // ----------------------------------------------------------------
  549. // state machine functions
  550. /* ---------------- */
  551. /* MDPdelayResp */
  552. /* ---------------- */
  553. static void mdpdelayresp_rcvdPdelayReq(tsn_ptp_instance_t *pStack, tsn_ptp_port_t *pPort, uintptr_t hdrAddr, ptp_timestamp_t *pRxTime)
  554. {
  555. // Part of:
  556. // MDPdelayResp state machine: IEEE 802.1as 11.2.16
  557. // notes: correction field is currently ignored (= 0)
  558. struct ptp_header_s hdr;
  559. uint32_t payload[5] = { 0, 0, 0, 0, 0 };
  560. uint16_t sequid;
  561. sequid = ptp_get_seqid(hdrAddr);
  562. pPort->mdPdResp.seqid = sequid; // copy sequence id
  563. tsn_ptp_get_portid(hdrAddr + PTPHDR_OFS_SPID, &pPort->mdPdResp.srcPortId);
  564. // set header PdelayResponse
  565. hdr = _ptp_default_header;
  566. hdr.sequenceId = sequid;
  567. hdr.sourcePortId = pPort->port.thisPortId;
  568. hdr.msgType = PTP_MSGTYPE_PDELAY_RESP;
  569. hdr.msgLen = PTP_HEADER_SZ + PTP_PAYLOAD_SZ_PDELAY;
  570. hdr.flags |= PTP_FLAG_TWO_STEP;
  571. hdr.control = PTP_CONTROL_OTHER;
  572. hdr.logMsgInterval = 0x7F;
  573. hdr.domainNumber = pStack->domainNumber;
  574. // set payload
  575. tsn_ptp_set_pdelay_resp((uintptr_t)(&payload), pRxTime, &pPort->mdPdResp.srcPortId);
  576. // call TX PdelayResponse
  577. if (pStack->hookTxFrame != 0) {
  578. pStack->hookTxFrame(pStack->cbParam, pPort->port.portIndex, &hdr, (uint8_t *)&payload, PTP_PAYLOAD_SZ_PDELAY);
  579. }
  580. }
  581. static void mdpdelayresp_rcvdMDTimestampReceive(tsn_ptp_instance_t *pStack, tsn_ptp_port_t *pPort, ptp_timestamp_t *pTxTime)
  582. {
  583. // Part of:
  584. // MDPdelayResp state machine: IEEE 802.1as 11.2.16
  585. // notes: correction field is currently ignored (= 0)
  586. struct ptp_header_s hdr;
  587. uint32_t payload[5] = { 0, 0, 0, 0, 0 };
  588. // set header PdelayRespFup
  589. hdr = _ptp_default_header;
  590. hdr.sequenceId = pPort->mdPdResp.seqid;
  591. hdr.sourcePortId = pPort->port.thisPortId;
  592. hdr.msgType = PTP_MSGTYPE_PDELAY_FUP;
  593. hdr.msgLen = PTP_HEADER_SZ + PTP_PAYLOAD_SZ_PDELAY;
  594. (void)hdr.flags; // no change, default: PTP_FLAG_PTP_TIMESCALE
  595. hdr.control = PTP_CONTROL_OTHER;
  596. hdr.logMsgInterval = 0x7F;
  597. hdr.domainNumber = pStack->domainNumber;
  598. // set payload
  599. tsn_ptp_set_pdelay_resp((uintptr_t)(&payload), pTxTime, &pPort->mdPdResp.srcPortId);
  600. // call TX PdelayResponseFup
  601. if (pStack->hookTxFrame != 0) {
  602. pStack->hookTxFrame(pStack->cbParam, pPort->port.portIndex, &hdr, (uint8_t *)&payload, PTP_PAYLOAD_SZ_PDELAY);
  603. }
  604. }
  605. /* ---------------- */
  606. /* MDPdelayReq */
  607. /* ---------------- */
  608. static void mdpdelayreq_rcvdPdelayResp(tsn_ptp_port_t *pProtocol, uintptr_t hdrAddr, ptp_timestamp_t *pRxTime)
  609. {
  610. // Part of:
  611. // MDPdelayReq state machine: IEEE 802.1as 11.2.15
  612. int64_t corfield;
  613. ptp_timestamp_t tstamp;
  614. uint16_t seqid;
  615. // get frame infos
  616. seqid = ptp_get_seqid(hdrAddr);
  617. // check validity
  618. // TODO: check reqportid == thisclock/thisport
  619. if ((seqid == pProtocol->mdPdReq.seqid)) {
  620. // save peer rx timestamp
  621. // timestamp from payload + correctionField
  622. tsn_ptp_get_tstamp(hdrAddr + PTP_HEADER_SZ, &tstamp);
  623. ptp_get_corfield(hdrAddr, &corfield);
  624. pProtocol->mdPdReq.time_peer_rxreq = tstamp.seconds * NS_PER_SEC;
  625. pProtocol->mdPdReq.time_peer_rxreq += tstamp.nanoseconds;
  626. pProtocol->mdPdReq.time_peer_rxreq += (corfield >> 16);
  627. // save local rx timestamp
  628. pProtocol->mdPdReq.time_local_rxresp = pRxTime->seconds * NS_PER_SEC;
  629. pProtocol->mdPdReq.time_local_rxresp += pRxTime->nanoseconds;
  630. // set event flag
  631. pProtocol->mdPdReq.eventflags |= PDREQ_FLAG_RXRESP;
  632. }
  633. // no else branch:
  634. // in case of invalid response we rely on timer and do reset,
  635. // because measIsRunning==TRUE
  636. }
  637. static void mdpdelayreq_rcvdPdelayRespFup(tsn_ptp_port_t *pProtocol, uintptr_t hdrAddr)
  638. {
  639. // Part of:
  640. // MDPdelayReq state machine: IEEE 802.1as 11.2.15
  641. int64_t corfield;
  642. ptp_timestamp_t tstamp;
  643. uint16_t seqid;
  644. // get frame infos
  645. seqid = ptp_get_seqid(hdrAddr);
  646. // check validity
  647. // TODO: check sourceportid == responseSrcPortId
  648. if ((seqid == pProtocol->mdPdReq.seqid)) {
  649. // save peer tx timestamp
  650. tsn_ptp_get_tstamp(hdrAddr + PTP_HEADER_SZ, &tstamp);
  651. ptp_get_corfield(hdrAddr, &corfield);
  652. pProtocol->mdPdReq.time_peer_txresp = tstamp.seconds * NS_PER_SEC;
  653. pProtocol->mdPdReq.time_peer_txresp += tstamp.nanoseconds;
  654. pProtocol->mdPdReq.time_peer_txresp += (corfield >> 16);
  655. // set event flag
  656. pProtocol->mdPdReq.eventflags |= PDREQ_FLAG_RXRSPFUP;
  657. }
  658. // calculate PDelay if all events are complete
  659. if (pProtocol->mdPdReq.eventflags == PDREQ_MASK_COMPLETE) {
  660. mdpdelayreq_calculate(pProtocol);
  661. }
  662. }
  663. static int32_t calc_nrr(int64_t diffPeer, int64_t diffLocal)
  664. {
  665. // ratio = (double)(diffPeer) / ((double)diffLocal);
  666. // rateOfs = (ratio-1.0) * 2^32
  667. int64_t tmp64;
  668. // difference
  669. tmp64 = (diffPeer - diffLocal);
  670. tmp64 <<= 32;
  671. tmp64 /= diffLocal;
  672. // high word expected 0 or -1
  673. // return lower 32 bit
  674. return (int32_t)tmp64;
  675. }
  676. static uint32_t calc_pdelay(int64_t diffPeer, int64_t diffLocal, int32_t rateOfs)
  677. {
  678. // pdelay = ((NRR*diffLocal) - diffPeer) / 2.0
  679. int64_t diff;
  680. diff = diffLocal * rateOfs;
  681. diff += (diffLocal << 32);
  682. diff >>= 32;
  683. diff -= diffPeer;
  684. diff /= 2;
  685. if (diff < 0)
  686. diff = 0;
  687. return (uint32_t)diff;
  688. }
  689. static void mdpdelayreq_calculate(tsn_ptp_port_t *pProtocol)
  690. {
  691. // Part of:
  692. // MDPdelayReq state machine: IEEE 802.1as 11.2.15
  693. int64_t diffPeer;
  694. int64_t diffLocal;
  695. // computeNeighborRateRatio
  696. if (pProtocol->port.computeNeighborRateRatio) {
  697. diffPeer = pProtocol->mdPdReq.time_peer_txresp - pProtocol->mdPdReq.saved_peer_txresp;
  698. diffLocal = pProtocol->mdPdReq.time_local_rxresp - pProtocol->mdPdReq.saved_local_rxresp;
  699. if (diffPeer < 10LL * NS_PER_SEC) {
  700. pProtocol->port.neighborRateOfs32 = calc_nrr(diffPeer, diffLocal);
  701. pProtocol->mdPdReq.neighborRateRatioValid = 1;
  702. } else {
  703. pProtocol->port.neighborRateOfs32 = 0;
  704. pProtocol->mdPdReq.neighborRateRatioValid = 0;
  705. }
  706. }
  707. pProtocol->mdPdReq.saved_local_rxresp = pProtocol->mdPdReq.time_local_rxresp;
  708. pProtocol->mdPdReq.saved_peer_txresp = pProtocol->mdPdReq.time_peer_txresp;
  709. // computeNeighborPropTime
  710. if (pProtocol->port.computeMeanLinkDelay) {
  711. diffLocal = pProtocol->mdPdReq.time_local_rxresp - pProtocol->mdPdReq.time_local_txreq;
  712. diffPeer = pProtocol->mdPdReq.time_peer_txresp - pProtocol->mdPdReq.time_peer_rxreq;
  713. pProtocol->port.meanLinkDelay = calc_pdelay(diffPeer, diffLocal, pProtocol->port.neighborRateOfs32);
  714. }
  715. //
  716. pProtocol->mdPdReq.lostResponses = 0;
  717. pProtocol->md.isMeasuringDelay = 1;
  718. if ((pProtocol->port.meanLinkDelay < pProtocol->md.meanLinkDelayTresh) && (pProtocol->mdPdReq.neighborRateRatioValid)) {
  719. pProtocol->md.asCapableAcrossDomains = 1;
  720. pProtocol->md.detectedFaults = 0;
  721. } else {
  722. if (pProtocol->md.detectedFaults <= PTP_ALLOW_PREQ_FAULTS) {
  723. pProtocol->md.detectedFaults++;
  724. } else {
  725. pProtocol->md.detectedFaults = 0;
  726. pProtocol->md.asCapableAcrossDomains = 0;
  727. }
  728. }
  729. // measuring done
  730. pProtocol->mdPdReq.measIsRunning = 0;
  731. // clear event flags
  732. pProtocol->mdPdReq.eventflags = 0;
  733. }
  734. static void mdpdelayreq_rcvdMDTimestampReceive(tsn_ptp_port_t *pProtocol, ptp_timestamp_t *pTxTime)
  735. {
  736. // Part of:
  737. // MDPdelayReq state machine: IEEE 802.1as 11.2.15
  738. // save timestamp (t1)
  739. pProtocol->mdPdReq.time_local_txreq = pTxTime->seconds * NS_PER_SEC;
  740. pProtocol->mdPdReq.time_local_txreq += pTxTime->nanoseconds;
  741. // set event flag
  742. pProtocol->mdPdReq.eventflags |= PDREQ_FLAG_TXDONE;
  743. // if for any reason event processing order is inaccurate the TX timestamp may be last event;
  744. // the pdelay calculation must then be done here
  745. if (pProtocol->mdPdReq.eventflags == PDREQ_MASK_COMPLETE) {
  746. mdpdelayreq_calculate(pProtocol);
  747. }
  748. }
  749. static void mdpdelayreq_pdelayIntervalTimer(tsn_ptp_instance_t *pStack, tsn_ptp_port_t *pPort)
  750. {
  751. // Part of:
  752. // MDPdelayReq state machine: IEEE 802.1as 11.2.15
  753. struct ptp_header_s hdr;
  754. uint32_t payload[5] = { 0, 0, 0, 0, 0 };
  755. // check measuring not completely done
  756. // action: do state RESET
  757. if (pPort->mdPdReq.measIsRunning) {
  758. if (pPort->mdPdReq.lostResponses > PTP_ALLOW_LOST_RESP) {
  759. pPort->md.isMeasuringDelay = 0;
  760. pPort->md.asCapableAcrossDomains = 0;
  761. } else {
  762. pPort->mdPdReq.lostResponses++;
  763. }
  764. }
  765. pPort->mdPdReq.measIsRunning = 0;
  766. pPort->mdPdReq.seqid++; // increase Sequence ID, do before copying to hdr
  767. pPort->mdPdReq.eventflags = 0; // clear any pending flags
  768. // set header PdelayRequest
  769. hdr = _ptp_default_header;
  770. hdr.sequenceId = pPort->mdPdReq.seqid;
  771. hdr.sourcePortId = pPort->port.thisPortId;
  772. hdr.msgType = PTP_MSGTYPE_PDELAY_REQ;
  773. hdr.msgLen = PTP_HEADER_SZ + PTP_PAYLOAD_SZ_PDELAY;
  774. (void)hdr.flags; // no change, default: PTP_FLAG_PTP_TIMESCALE
  775. hdr.control = PTP_CONTROL_OTHER;
  776. hdr.logMsgInterval = pPort->md.curLogPdelayReqInterval;
  777. hdr.domainNumber = pStack->domainNumber;
  778. // Send Pdelay Request
  779. if (pStack->hookTxFrame != 0) {
  780. pPort->mdPdReq.measIsRunning = 1;
  781. pStack->hookTxFrame(pStack->cbParam, pPort->port.portIndex, &hdr, (uint8_t *)&payload, PTP_PAYLOAD_SZ_PDELAY);
  782. }
  783. }
  784. /* ---------------- */
  785. /* MDSyncReceive */
  786. /* ---------------- */
  787. static void mdsyncreceive_rcvdSync(tsn_ptp_instance_t *pStack, tsn_ptp_port_t *pProtocol, uintptr_t hdrAddr, ptp_timestamp_t *pRxTime)
  788. {
  789. // Part of:
  790. // MDSyncReceive state machine: IEEE 802.1as 11.2.13
  791. (void)pStack;
  792. uint16_t seqid;
  793. uint32_t propDelay;
  794. // check asCapable
  795. if (!(pProtocol->port.asCapable)) {
  796. pProtocol->mdSyncRecv.waitFup = 0;
  797. return;
  798. }
  799. // get frame infos
  800. seqid = ptp_get_seqid(hdrAddr);
  801. pProtocol->mdSyncRecv.waitFup = 1;
  802. pProtocol->mdSyncRecv.seqid = seqid;
  803. tsn_ptp_get_portid(hdrAddr + PTPHDR_OFS_SPID, &pProtocol->mdSyncRecv.pss.srcPortIdentity); // 11.2.13.2.1 b
  804. pProtocol->mdSyncRecv.pss.logMsgInterval = *((int8_t *)hdrAddr + PTPHDR_OFS_LOGIVAL); // 11.2.13.2.1 c
  805. pProtocol->mdSyncRecv.pss.upstreamTxTimeNs = pRxTime->seconds * NS_PER_SEC + pRxTime->nanoseconds; // 11.2.13.2.1 f
  806. if (pProtocol->port.meanLinkDelay < INT32_MAX) {
  807. // propDelay = (uint32_t)((double)pProtocol->port.neighborPropDelayNs / pProtocol->port.neighborRateRatio);
  808. // simplified: (pdelay / neighborRateRation) ~~ pdelay
  809. // expected values: pdelay (0 .. 5000), nrr (0.9996 .. 1.0004) --> +- 2ns
  810. propDelay = pProtocol->port.meanLinkDelay;
  811. pProtocol->mdSyncRecv.pss.upstreamTxTimeNs -= propDelay;
  812. }
  813. }
  814. static void mdsyncreceive_rcvdFollowup(tsn_ptp_instance_t *pStack, tsn_ptp_port_t *pProtocol, uintptr_t hdrAddr)
  815. {
  816. // Part of:
  817. // MDSyncReceive state machine: IEEE 802.1as 11.2.13
  818. uint16_t seqid;
  819. struct ptp_followup_s followupData;
  820. // check waiting for followup
  821. if (!(pProtocol->mdSyncRecv.waitFup))
  822. return;
  823. // TODO: check timeout
  824. // currentTime >= followupReceiptTimeout
  825. // check correct sequenceId
  826. seqid = ptp_get_seqid(hdrAddr);
  827. if (seqid != pProtocol->mdSyncRecv.seqid)
  828. return;
  829. // read followup data
  830. if (tsn_ptp_get_followup(hdrAddr + PTP_HEADER_SZ, &followupData)) {
  831. // error reading followup
  832. return;
  833. }
  834. // setMDSyncReceive
  835. ptp_get_corfield(hdrAddr, &pProtocol->mdSyncRecv.pss.followUpCorrectionField); // 11.2.13.2.1 a
  836. pProtocol->mdSyncRecv.pss.preciseOriginTimestamp = followupData.preciseOriginTimestamp; // 11.2.13.2.1 d
  837. pProtocol->mdSyncRecv.pss.scaledRateRatio = followupData.cumScaledRateOfs; // 11.2.13.2.1 e
  838. pProtocol->mdSyncRecv.pss.gmTimeBaseIndicator = followupData.gmTimeBaseInd; // 11.2.13.2.1 g
  839. pProtocol->mdSyncRecv.pss.lastGmPhaseChange = followupData.lastGmPhaseCh; // 11.2.13.2.1 h
  840. pProtocol->mdSyncRecv.pss.scaledLastGmFreqChange = followupData.scaledLastGmFreqCh; // 11.2.13.2.1 i
  841. // txMDSyncReceive: transmit PSS to portSyncSyncRecv
  842. // code contains parts of PortSyncSyncRecv (10.2.7) due to optimization
  843. pProtocol->mdSyncRecv.pss.localPortNum = pProtocol->port.thisPort; // 10.2.7.1 a
  844. // pProtocol->mdSyncRecv.pss.rateRatio += (pProtocol->port.neighborRateRatio - 1.0); // 10.2.7.1 e
  845. pProtocol->mdSyncRecv.pss.scaledRateRatio += (pProtocol->port.neighborRateOfs32 << 9); // 10.2.7.1 e
  846. portsyncsyncrecv_rcvdMdSync(pStack, &(pProtocol->mdSyncRecv.pss));
  847. // wait for next sync
  848. pProtocol->mdSyncRecv.waitFup = 0;
  849. }
  850. /* ---------------- */
  851. /* PortSyncSyncRecv */
  852. /* ---------------- */
  853. static void portsyncsyncrecv_rcvdMdSync(tsn_ptp_instance_t *pStack, port_sync_sync_t *pPSS)
  854. {
  855. // Part of:
  856. // PortSyncSyncRecv state machine: IEEE 802.1as 10.2.7
  857. // check field gmPriority.srcPortId
  858. if (pStack->gmPriority.sourcePortId.clockIdentity != pPSS->srcPortIdentity.clockIdentity)
  859. return;
  860. if (pStack->gmPriority.sourcePortId.portNumber != pPSS->srcPortIdentity.portNumber)
  861. return;
  862. // 10.2.7.1 a localPortNum, already adjusted before call
  863. // 10.2.7.1 b,c no need for copying, using pPSS structure
  864. // 10.2.7.1 d TODO: pPSS->syncReceiptTimeout = ?;
  865. // 10.2.7.1 e rateRatio, already adjusted before call
  866. // reset timer
  867. if (pStack->hookSetTimer != 0) {
  868. pStack->hookSetTimer(pStack->cbParam, PTP_TMR_EVENT_RXSYNC, 0, pStack->siteSync.logSyncIval, 3);
  869. }
  870. if (pStack->hookStatusEvent != 0 && pStack->siteSync.hasSyncRcvd == 0) {
  871. pStack->hookStatusEvent(pStack->cbParam, PTP_STS_EVENT_SYNCRECV, 0);
  872. }
  873. siteSyncPssHandle(pStack, pPSS);
  874. pStack->siteSync.hasSyncRcvd = 1;
  875. }
  876. /* ------------------- */
  877. /* PortAnnounceReceive */
  878. /* ------------------- */
  879. static clock_id rdClockId(uint8_t *ptr)
  880. {
  881. uint32_t idx;
  882. clock_id id;
  883. uint8_t *pDst;
  884. pDst = (uint8_t *)(&id);
  885. for (idx = 0; idx < 8; ++idx) {
  886. pDst[idx] = ptr[idx];
  887. }
  888. return id;
  889. }
  890. static void portannouncerecv(tsn_ptp_instance_t *pStack, tsn_ptp_port_t *pPort, uintptr_t hdrAddr)
  891. {
  892. uint32_t idx;
  893. port_id_t srcportid;
  894. clock_id pathTraceElem;
  895. struct ptp_announce_s announceInfo;
  896. ptp_prio_vect_t msgPrioVect;
  897. int32_t rcvdInfo;
  898. uint16_t anncFlags;
  899. int8_t anncLogInterval;
  900. //
  901. // qualify announce (10.3.10.2.1)
  902. //
  903. if (!(pPort->port.asCapable))
  904. return; // (state machine)
  905. // check thisClock != srcPortId.clockId (a)
  906. tsn_ptp_get_portid(hdrAddr + PTPHDR_OFS_SPID, &srcportid);
  907. if (srcportid.clockIdentity == pStack->thisClock)
  908. return;
  909. // get announce payload info
  910. if (tsn_ptp_get_announce(hdrAddr + PTP_HEADER_SZ, &announceInfo) < 0)
  911. return;
  912. // check stepsremoved < 255 (b)
  913. if (announceInfo.stepsRemoved >= 255)
  914. return;
  915. // check path trace tlv (if present) (c)
  916. for (idx = 0; idx < announceInfo.pathCount; ++idx) {
  917. pathTraceElem = rdClockId(announceInfo.pPathSequence + (idx * PTP_PATHTRACE_SZ));
  918. if (pathTraceElem == pStack->thisClock)
  919. return;
  920. }
  921. // copy path trace tlv when slave port
  922. if (pPort->port.selectedRole == PTP_PORT_ROLE_SLAVE) {
  923. // copy all elements from path trace
  924. for (idx = 0; idx < announceInfo.pathCount; ++idx) {
  925. pathTraceElem = rdClockId(announceInfo.pPathSequence + (idx * PTP_PATHTRACE_SZ));
  926. if (idx < TSN_PTP_CFG_PATHTRACE_MAX) {
  927. pStack->pathTrace[idx] = pathTraceElem;
  928. }
  929. }
  930. // append thisClock (idx == announceInfo.pathCount)
  931. if (idx < TSN_PTP_CFG_PATHTRACE_MAX) {
  932. pStack->pathTrace[idx] = pStack->thisClock;
  933. }
  934. pStack->pathTraceCount = announceInfo.pathCount + 1;
  935. }
  936. // buid messagePriorityVector (see 10.3.5)
  937. msgPrioVect.rootSystemId.prio1 = announceInfo.gmPrio1;
  938. msgPrioVect.rootSystemId.prio2 = announceInfo.gmPrio2;
  939. msgPrioVect.rootSystemId.clockIdentity = announceInfo.gmIdentity;
  940. msgPrioVect.rootSystemId.clockQuality = announceInfo.clockQuality;
  941. msgPrioVect.stepsRemoved = announceInfo.stepsRemoved;
  942. tsn_ptp_get_portid(hdrAddr + PTPHDR_OFS_SPID, &msgPrioVect.sourcePortId);
  943. msgPrioVect.portNumber = pPort->port.thisPort;
  944. // rcvdInfo = rcvInfo(); IEEE802.1as 10.13.11.2.1
  945. rcvdInfo = tsn_ptp_cmp_priovect(&msgPrioVect, &pPort->anncInfo.portPriority);
  946. anncFlags = tsn_ptp_get_flags(hdrAddr + PTPHDR_OFS_FLAGS);
  947. anncFlags &= (PTP_FLAG_LEAP61 | PTP_FLAG_LEAP59 | PTP_FLAG_CURUTCO_VALID | PTP_FLAG_FREQ_TRACEABLE | PTP_FLAG_TIME_TRACEABLE);
  948. anncLogInterval = *((uint8_t *)(hdrAddr + PTPHDR_OFS_LOGIVAL));
  949. if (rcvdInfo == 0) {
  950. // REPEATED MASTER INFO
  951. // check here for update of flags&fields?
  952. // reset timer
  953. if (pStack->hookSetTimer != 0) {
  954. pStack->hookSetTimer(pStack->cbParam, PTP_TMR_EVENT_RXANNC, pPort->port.portIndex, anncLogInterval, 3);
  955. }
  956. } else {
  957. // SUPERIOR MASTER INFO +
  958. // INFERIOR MASTER INFO - do port role selection
  959. // copy information
  960. pPort->anncInfo.portPriority = msgPrioVect;
  961. pPort->anncInfo.portStepsRemoved = announceInfo.stepsRemoved;
  962. pPort->anncInfo.infoIs = INFO_IS_RECEIVED;
  963. // recordOtherAnnounceInfo(); // 10.3.11.2.2
  964. // leap61, leap59, curUtcOfsValid, timeTraceable, freqTraceable; curUtcOfs; timeSrc
  965. pPort->anncInfo.annInfo.flags = anncFlags;
  966. pPort->anncInfo.annInfo.curUtcOfs = announceInfo.currentUtcOfs;
  967. pPort->anncInfo.annInfo.timeSource = announceInfo.timeSource;
  968. // PortRoleSelect: reselect
  969. tsn_ptp_stack_portroleselection(pStack);
  970. // reset timer
  971. if (pStack->hookSetTimer != 0) {
  972. pStack->hookSetTimer(pStack->cbParam, PTP_TMR_EVENT_RXANNC, pPort->port.portIndex, anncLogInterval, 3);
  973. }
  974. }
  975. }
  976. static void portannouncerecv_timeout(tsn_ptp_instance_t *pStack, tsn_ptp_port_t *pPort)
  977. {
  978. // PortAnnounceInformation: IEEE802.1as 10.3.13
  979. // set info is aged
  980. pPort->anncInfo.infoIs = INFO_IS_AGED;
  981. // PortRoleSelect: reselect
  982. tsn_ptp_stack_portroleselection(pStack);
  983. }
  984. static void portannouncesend(tsn_ptp_instance_t *pStack, tsn_ptp_port_t *pPort)
  985. {
  986. // PortAnnounceTransmit: IEEE 802.1as 10.3.13
  987. struct ptp_header_s hdr;
  988. struct ptp_announce_s announce;
  989. uint32_t payloadLen;
  990. uint8_t *ptrPayload;
  991. // only send, when master
  992. if (pPort->port.selectedRole != PTP_PORT_ROLE_MASTER)
  993. return;
  994. ptrPayload = (uint8_t *)&(pPort->anncInfo.payloadBuf);
  995. // build payload
  996. payloadLen = PTP_PAYLOAD_SZ_ANNOUNCE;
  997. announce.currentUtcOfs = pPort->anncInfo.annInfo.curUtcOfs;
  998. announce.gmPrio1 = pStack->gmPriority.rootSystemId.prio1;
  999. announce.gmPrio2 = pStack->gmPriority.rootSystemId.prio2;
  1000. announce.clockQuality = pStack->gmPriority.rootSystemId.clockQuality;
  1001. announce.gmIdentity = pStack->gmPriority.rootSystemId.clockIdentity;
  1002. announce.stepsRemoved = pStack->masterStepsRemoved;
  1003. announce.timeSource = pPort->anncInfo.annInfo.timeSource;
  1004. announce.pPathSequence = (uint8_t *)&pStack->pathTrace;
  1005. announce.pathCount = pStack->pathTraceCount;
  1006. if (announce.pathCount > TSN_PTP_CFG_PATHTRACE_MAX) {
  1007. announce.pathCount = 0; // -> do not send pathTrace TLV
  1008. }
  1009. payloadLen = tsn_ptp_set_announce((uintptr_t)ptrPayload, &announce);
  1010. // set header announce-frame
  1011. hdr = _ptp_default_header;
  1012. hdr.sequenceId = pPort->anncInfo.txSeqId;
  1013. hdr.sourcePortId = pPort->port.thisPortId;
  1014. hdr.msgType = PTP_MSGTYPE_ANNOUNCE;
  1015. hdr.msgLen = PTP_HEADER_SZ + payloadLen;
  1016. hdr.flags |= pPort->anncInfo.annInfo.flags;
  1017. hdr.control = PTP_CONTROL_OTHER;
  1018. hdr.logMsgInterval = pPort->anncInfo.curLogInterval;
  1019. hdr.domainNumber = pStack->domainNumber;
  1020. if (pStack->hookTxFrame != 0) {
  1021. pStack->hookTxFrame(pStack->cbParam, pPort->port.portIndex, &hdr, ptrPayload, payloadLen);
  1022. pPort->anncInfo.txSeqId++;
  1023. }
  1024. }
  1025. /* ------------------- */
  1026. /* PortSyncSyncSend */
  1027. /* ------------------- */
  1028. static void portsyncsyncsend(tsn_ptp_instance_t *pStack, tsn_ptp_port_t *pPort, port_sync_sync_t *pPSS)
  1029. {
  1030. struct ptp_header_s hdr;
  1031. uint32_t payloadBuffer[3] = { 0, 0, 0 };
  1032. //
  1033. // PortSyncSyncSend: 10.2.11
  1034. //
  1035. // check enabled and asCapable
  1036. if (!(pPort->port.enabled))
  1037. return;
  1038. if (!(pPort->port.asCapable))
  1039. return;
  1040. pPort->mdSyncSend.pss = *pPSS; // copy PSS
  1041. pPort->mdSyncSend.pss.srcPortIdentity = pPort->port.thisPortId; // 10.2.11.2.1 a
  1042. pPort->mdSyncSend.pss.logMsgInterval = pPort->port.curLogSyncInterval; // 10.2.11.2.1 b
  1043. // nothing to be done: 10.2.11.2.1 c-f
  1044. // inc sequence ID
  1045. pPort->mdSyncSend.seqid++;
  1046. //
  1047. // MDSyncSend (11.2.14)
  1048. //
  1049. // set header sync-frame
  1050. hdr = _ptp_default_header;
  1051. hdr.sequenceId = pPort->mdSyncSend.seqid;
  1052. hdr.sourcePortId = pPort->mdSyncSend.pss.srcPortIdentity;
  1053. hdr.msgType = PTP_MSGTYPE_SYNC;
  1054. hdr.msgLen = PTP_HEADER_SZ + PTP_PAYLOAD_SZ_SYNC;
  1055. hdr.flags |= PTP_FLAG_TWO_STEP;
  1056. hdr.control = PTP_CONTROL_SYNC;
  1057. hdr.logMsgInterval = pPort->port.curLogSyncInterval;
  1058. hdr.domainNumber = pStack->domainNumber;
  1059. // call hookTx Sync
  1060. if (pStack->hookTxFrame != 0) {
  1061. // call hook
  1062. pStack->hookTxFrame(pStack->cbParam, pPort->port.portIndex, &hdr, (uint8_t *)(&payloadBuffer), PTP_PAYLOAD_SZ_SYNC);
  1063. }
  1064. }
  1065. static int64_t _scale_residence_time(int64_t residenceTime, int32_t scaledRateRatio)
  1066. {
  1067. // residenceTime = pPort->mdSyncSend.pss.rateRatio * residenceTime;
  1068. // scaledRateRatio: scaled to 2^41
  1069. int64_t tmp;
  1070. // scale to 2^32
  1071. scaledRateRatio >>= 9;
  1072. tmp = residenceTime;
  1073. tmp *= scaledRateRatio;
  1074. tmp += (residenceTime << 32);
  1075. tmp >>= 32;
  1076. return tmp;
  1077. }
  1078. static void mdsyncsend_rcvdMDTimestampReceive(tsn_ptp_instance_t *pStack, tsn_ptp_port_t *pPort, ptp_timestamp_t *pTxTime)
  1079. {
  1080. struct ptp_header_s hdr;
  1081. struct ptp_followup_s fupData;
  1082. int64_t residenceTime;
  1083. uint32_t payloadBuffer[12]; // must be large enough for PTP_PAYLOAD_SZ_FOLLOWUP data
  1084. //
  1085. // MDSyncSend (11.2.14)
  1086. //
  1087. // setFollowUp() (11.2.14.2.3)
  1088. // a) followUpCorrectionField
  1089. residenceTime = pTxTime->seconds * NS_PER_SEC;
  1090. residenceTime += pTxTime->nanoseconds;
  1091. residenceTime -= pPort->mdSyncSend.pss.upstreamTxTimeNs;
  1092. // here: residenceTime relative to LocalClock
  1093. // next: scale to GM time
  1094. residenceTime = _scale_residence_time(residenceTime, pPort->mdSyncSend.pss.scaledRateRatio);
  1095. // set header follow-up frame
  1096. hdr = _ptp_default_header;
  1097. hdr.correctionField = pPort->mdSyncSend.pss.followUpCorrectionField + (residenceTime << 16);
  1098. hdr.sequenceId = pPort->mdSyncSend.seqid;
  1099. hdr.sourcePortId = pPort->mdSyncSend.pss.srcPortIdentity;
  1100. hdr.msgType = PTP_MSGTYPE_FOLLOWUP;
  1101. hdr.msgLen = PTP_HEADER_SZ + PTP_PAYLOAD_SZ_FOLLOWUP;
  1102. (void)hdr.flags; // no change, default: PTP_FLAG_PTP_TIMESCALE
  1103. hdr.control = PTP_CONTROL_FOLLOWUP;
  1104. hdr.logMsgInterval = pPort->port.curLogSyncInterval;
  1105. hdr.domainNumber = pStack->domainNumber;
  1106. // set payload
  1107. fupData.preciseOriginTimestamp = pPort->mdSyncSend.pss.preciseOriginTimestamp;
  1108. fupData.cumScaledRateOfs = pPort->mdSyncSend.pss.scaledRateRatio;
  1109. fupData.gmTimeBaseInd = pPort->mdSyncSend.pss.gmTimeBaseIndicator;
  1110. fupData.lastGmPhaseCh = pPort->mdSyncSend.pss.lastGmPhaseChange;
  1111. fupData.scaledLastGmFreqCh = pPort->mdSyncSend.pss.scaledLastGmFreqChange;
  1112. tsn_ptp_set_followup((uintptr_t)(&payloadBuffer), &fupData); // fupData -> payloadBuffer
  1113. // txFollowUp
  1114. if (pStack->hookTxFrame != 0) {
  1115. // call hook
  1116. pStack->hookTxFrame(pStack->cbParam, pPort->port.portIndex, &hdr, (uint8_t *)(&payloadBuffer), PTP_PAYLOAD_SZ_FOLLOWUP);
  1117. }
  1118. }
  1119. /**
  1120. * \brief: Convert timespec to nanoseconds
  1121. *
  1122. * @param ts pointer to timespec
  1123. * @return scalar nanoseconds
  1124. */
  1125. static uint64_t ptp_timestamp_to_ns(ptp_timestamp_t *ts)
  1126. {
  1127. return ((uint64_t)ts->seconds * NS_PER_SEC) + ts->nanoseconds;
  1128. }
  1129. static uint64_t tsn_ptp_clock_get_offset(tsn_ptp_clock_t *domain_clk, uint64_t localtime)
  1130. {
  1131. int64_t timediff;
  1132. timediff = localtime - domain_clk->last_localtime;
  1133. if (domain_clk->rateOfs) {
  1134. timediff *= domain_clk->rateOfs;
  1135. timediff += domain_clk->fractOfs;
  1136. domain_clk->fractOfs = (timediff & 0xFFFFFFFF); // low 32 bits
  1137. timediff >>= 32;
  1138. domain_clk->offset_ns += timediff;
  1139. }
  1140. domain_clk->last_localtime = localtime;
  1141. return domain_clk->offset_ns;
  1142. }
  1143. void tsn_ptp_clock_set_offset(tsn_ptp_clock_t *domain_clk, uint64_t localtime, uint64_t offset)
  1144. {
  1145. domain_clk->offset_ns = offset;
  1146. domain_clk->fractOfs = 0;
  1147. domain_clk->last_localtime = localtime;
  1148. }
  1149. uint64_t tsn_ptp_time_get(tsn_ptp_instance_t *pStack)
  1150. {
  1151. ptp_timestamp_t localtime;
  1152. uint64_t localtime_ns, local_ofs;
  1153. if (!pStack->hookGetLocalTime)
  1154. return 0;
  1155. pStack->hookGetLocalTime(pStack->cbParam, &localtime);
  1156. localtime_ns = ptp_timestamp_to_ns(&localtime);
  1157. local_ofs = tsn_ptp_clock_get_offset(&pStack->localClock, localtime_ns);
  1158. return localtime_ns + local_ofs;
  1159. }
  1160. /* ------------------- */
  1161. /* SiteSync */
  1162. /* ------------------- */
  1163. static void siteSyncIntervalTimer(tsn_ptp_instance_t *pStack)
  1164. {
  1165. port_sync_sync_t portSync;
  1166. ptp_timestamp_t localtime;
  1167. ptp_timestamp_t offset;
  1168. uint64_t localtime_ns;
  1169. uint64_t rtctime;
  1170. //
  1171. // ClockMasterSyncSend 10.2.8; sends when no sync is received by any port
  1172. //
  1173. if (pStack->siteSync.hasSyncRcvd)
  1174. return;
  1175. // get local time from upper layer
  1176. if (!pStack->hookGetLocalTime)
  1177. return;
  1178. pStack->hookGetLocalTime(pStack->cbParam, &localtime);
  1179. if (!pStack->hookGetLocalOffset)
  1180. return;
  1181. pStack->hookGetLocalOffset(pStack->cbParam, &offset);
  1182. localtime_ns = ptp_timestamp_to_ns(&localtime);
  1183. pStack->localClock.offset_ns = ptp_timestamp_to_ns(&offset);
  1184. // set rtc time
  1185. // rtctime = localtime + localpriv->domainclock.offset_ns;
  1186. rtctime = localtime_ns + pStack->localClock.offset_ns;
  1187. // build port sync structure
  1188. portSync.localPortNum = 0; // a
  1189. portSync.preciseOriginTimestamp.nanoseconds = rtctime % NS_PER_SEC; // b
  1190. portSync.preciseOriginTimestamp.seconds = rtctime / NS_PER_SEC; // b
  1191. portSync.followUpCorrectionField = 0; // c
  1192. portSync.srcPortIdentity.clockIdentity = pStack->thisClock; // d
  1193. portSync.srcPortIdentity.portNumber = 0; // e
  1194. portSync.logMsgInterval = pStack->siteSync.logSyncIval; // f
  1195. portSync.upstreamTxTimeNs = localtime_ns; // g
  1196. portSync.syncReceiptTimeout = 0xFFFFFFFFFFFFFFFFLL; // h
  1197. // portSync.rateRatio = site->clock_master.gmRateRatio; // i
  1198. portSync.scaledRateRatio = pStack->siteSync.gmRateOfs << 9; // i
  1199. portSync.gmTimeBaseIndicator = pStack->siteSync.clkTimeBaseInd; // j
  1200. portSync.lastGmPhaseChange = pStack->siteSync.clkSrcPhOfs; // k
  1201. portSync.scaledLastGmFreqChange = pStack->siteSync.clkFrqOfsScaled; // l
  1202. // call GM received PSS
  1203. siteSyncPssHandle(pStack, &portSync);
  1204. }
  1205. static void siteSyncPssHandle(tsn_ptp_instance_t *pStack, port_sync_sync_t *pPSS)
  1206. {
  1207. uint8_t receivingPortRole;
  1208. // reset sync timeout
  1209. pStack->siteSync.hasSyncRcvd = 0;
  1210. // default: port 0
  1211. receivingPortRole = pStack->selectedRole0;
  1212. if ((pPSS->localPortNum > 0) && (pPSS->localPortNum <= TSN_PTP_CFG_PORTNUM)) {
  1213. receivingPortRole = pStack->port[pPSS->localPortNum - 1].port.selectedRole;
  1214. }
  1215. // check gmpresent: gmPrio.priority1 < 255
  1216. // check role == slavePort
  1217. if ((pStack->gmPriority.rootSystemId.prio1 < 255) && (receivingPortRole == PTP_PORT_ROLE_SLAVE)) {
  1218. // slave clock
  1219. siteSyncPssReceive(pStack, pPSS);
  1220. // send PortSyncSync / (== MDSync) structure to all Master ports
  1221. tsn_ptp_stack_send_pss(pStack, pPSS);
  1222. }
  1223. }
  1224. // GM abstraction
  1225. static int32_t _scale_lc_offset_change(int64_t diff, int32_t rateOfs)
  1226. {
  1227. diff *= (int64_t)rateOfs;
  1228. diff >>= 32;
  1229. return (int32_t)diff;
  1230. }
  1231. static void siteSyncPssReceive(tsn_ptp_instance_t *pStack, port_sync_sync_t *pPSS)
  1232. {
  1233. int64_t syncReceiptTime;
  1234. int64_t syncReceiptLocalTime;
  1235. int64_t lc_ofs_ns;
  1236. int32_t lc_ofs_ch;
  1237. int64_t gmTimeDiff;
  1238. int64_t localTimeDiff;
  1239. uint64_t lc_offset;
  1240. uint64_t localtime_ns;
  1241. uint64_t lc_offset_old;
  1242. ptp_timestamp_t localtime;
  1243. // created by this time aware system? -> do nothing
  1244. if (pPSS->localPortNum == 0)
  1245. return;
  1246. // calc syncReceiptTime, syncReceiptLocalTime
  1247. syncReceiptTime = pPSS->preciseOriginTimestamp.seconds * NS_PER_SEC + pPSS->preciseOriginTimestamp.nanoseconds;
  1248. syncReceiptTime += (pPSS->followUpCorrectionField >> 16);
  1249. syncReceiptLocalTime = pPSS->upstreamTxTimeNs;
  1250. // get local time from upper layer
  1251. if (!pStack->hookGetLocalTime)
  1252. return;
  1253. pStack->hookGetLocalTime(pStack->cbParam, &localtime);
  1254. localtime_ns = ptp_timestamp_to_ns(&localtime);
  1255. // set RTC offset to current offset
  1256. // calc RTC-OFFSET
  1257. lc_ofs_ns = syncReceiptTime - syncReceiptLocalTime;
  1258. // take account of gmRateRatio
  1259. lc_ofs_ch = _scale_lc_offset_change(localtime_ns - syncReceiptLocalTime, pStack->siteSync.gmRateOfs);
  1260. lc_ofs_ns -= lc_ofs_ch;
  1261. // calc parts: sec, ns
  1262. lc_offset = (uint64_t)lc_ofs_ns;
  1263. // get old RTC offset, calc gmDifference
  1264. lc_offset_old = tsn_ptp_clock_get_offset(&pStack->localClock, localtime_ns);
  1265. pStack->siteSync.gmOffset = lc_offset - lc_offset_old;
  1266. pStack->siteSync.gmOffsetSum += pStack->siteSync.gmOffset;
  1267. // set new RTC-OFFSET
  1268. tsn_ptp_clock_set_offset(&pStack->localClock, localtime_ns, lc_offset);
  1269. if (pStack->hookStatusEvent != 0 && pStack->enableInvoke) {
  1270. pStack->hookStatusEvent(pStack->cbParam, PTP_STS_EVENT_PHASE_CHANGE, (void *)&lc_offset);
  1271. }
  1272. // calc: gmRateRatio --> ofs change
  1273. gmTimeDiff = syncReceiptTime - pStack->siteSync.savedSyncReceiptTime;
  1274. // skip negative and very large jumps
  1275. if ((gmTimeDiff < 0) || (gmTimeDiff > (32 * PTP_SYNC_ADJ_FREQ_IVAL))) {
  1276. pStack->siteSync.hasSavedSync = 0;
  1277. pStack->siteSync.gmOffsetSum = 0;
  1278. }
  1279. if ((pStack->siteSync.hasSavedSync) && (gmTimeDiff > PTP_SYNC_ADJ_FREQ_IVAL)) {
  1280. // recalc gmRateRatio at around ADJ_FREQ_IVAL
  1281. localTimeDiff = syncReceiptLocalTime - pStack->siteSync.savedSyncReceiptLocalTime;
  1282. // calc gmRateRatio
  1283. // site->clock_master.gmRateRatio = (double)(gmTimeDiff) / (double)localTimeDiff;
  1284. int64_t diff;
  1285. diff = gmTimeDiff - localTimeDiff;
  1286. diff <<= 32;
  1287. diff /= localTimeDiff;
  1288. pStack->siteSync.gmRateOfs = (int32_t)diff;
  1289. // calc rtc_ofs_ch
  1290. // sanity check
  1291. if ((pStack->siteSync.gmRateOfs > -PTP_SYNC_RATE_OFS_TH) && (pStack->siteSync.gmRateOfs < PTP_SYNC_RATE_OFS_TH)) {
  1292. // rtc_adjfine(site->rtc, localpriv->clock_master.gmRateOfs);
  1293. pStack->localClock.rateOfs = pStack->siteSync.gmRateOfs;
  1294. if (pStack->hookStatusEvent != 0 && pStack->enableInvoke) {
  1295. pStack->hookStatusEvent(pStack->cbParam, PTP_STS_EVENT_FREQ_CHANGE, (void *)&pStack->localClock.rateOfs);
  1296. }
  1297. }
  1298. // trigger saving of current timestamp
  1299. pStack->siteSync.hasSavedSync = 0;
  1300. pStack->siteSync.gmOffsetSum = 0;
  1301. }
  1302. // save current receipt timestamps
  1303. if (!(pStack->siteSync.hasSavedSync)) {
  1304. pStack->siteSync.savedSyncReceiptTime = syncReceiptTime;
  1305. pStack->siteSync.savedSyncReceiptLocalTime = syncReceiptLocalTime;
  1306. pStack->siteSync.hasSavedSync = 1;
  1307. }
  1308. }