tsn_ptp.c 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690
  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.c
  10. * \author zimmerli
  11. * \date 2019-01-14
  12. * \brief IEEE 802.1as SW-Implementation, low-level
  13. *
  14. */
  15. #include "tsn_ptp.h"
  16. // Macros
  17. // swap endianess
  18. #define SWAP16(value) (((value & 0xFF) << 8 | (value >> 8)) & 0xFFFF)
  19. // access memory
  20. #define MEM8(addr) (*(uint8_t *)(addr))
  21. #define NS_PER_SEC 1000000000
  22. // ----------------------------------------------------------------
  23. // inline functions
  24. // 32 bit memory access and network to host order conversion
  25. static inline uint32_t mem32_ntohl(uintptr_t addr)
  26. {
  27. uint32_t tmp;
  28. uint8_t *ptr;
  29. ptr = (uint8_t *)addr;
  30. tmp = ptr[0];
  31. tmp = (tmp << 8) | ptr[1];
  32. tmp = (tmp << 8) | ptr[2];
  33. tmp = (tmp << 8) | ptr[3];
  34. return tmp;
  35. }
  36. // 32 bit memory access and host to network order conversion
  37. static inline void mem32_htonl(uintptr_t addr, uint32_t value)
  38. {
  39. uint8_t *ptr;
  40. ptr = (uint8_t *)addr;
  41. ptr[0] = (value >> 24) & 0xFF;
  42. ptr[1] = (value >> 16) & 0xFF;
  43. ptr[2] = (value >> 8) & 0xFF;
  44. ptr[3] = (value) & 0xFF;
  45. }
  46. // 16 bit memory access and network to host order conversion
  47. static inline uint16_t mem16_ntohs(uintptr_t addr)
  48. {
  49. uint16_t tmp;
  50. uint8_t *ptr;
  51. ptr = (uint8_t *)addr;
  52. tmp = ptr[0] << 8;
  53. tmp |= ptr[1];
  54. return tmp;
  55. }
  56. // 16 bit memory access and host to network order conversion
  57. static inline void mem16_htons(uintptr_t addr, uint16_t value)
  58. {
  59. uint8_t *ptr;
  60. ptr = (uint8_t *)addr;
  61. ptr[0] = (value >> 8) & 0xFF;
  62. ptr[1] = (value) & 0xFF;
  63. }
  64. // ----------------------------------------------------------------
  65. /**
  66. * Destination MAC address used by all PTP communication
  67. */
  68. const uint8_t tsn_ptp_macaddr[6] = { 0x01, 0x80, 0xC2, 0x00, 0x00, 0x0E };
  69. // ----------------------------------------------------------------
  70. uint32_t tsn_ptp_set_eth_header(uintptr_t dstaddr, uint8_t *pMacAddr)
  71. {
  72. uint8_t *pu8;
  73. uint32_t idx;
  74. // point pu8 to dstaddr
  75. pu8 = (uint8_t *)dstaddr;
  76. // dst addr
  77. for (idx = 0; idx < 6; ++idx) {
  78. pu8[idx] = tsn_ptp_macaddr[idx];
  79. }
  80. // src addr
  81. for (idx = 0; idx < 6; ++idx) {
  82. pu8[6 + idx] = pMacAddr[idx];
  83. }
  84. // eth type (MSB first)
  85. pu8[12] = ETH_TYPE_PTP >> 8;
  86. pu8[13] = ETH_TYPE_PTP & 0xFF;
  87. return 14;
  88. }
  89. uint32_t tsn_ptp_set_ptp_header(uintptr_t dstaddr, struct ptp_header_s *pPtp)
  90. {
  91. uint32_t ofs;
  92. uint32_t idx;
  93. uint8_t *pSrc;
  94. // start at dstaddr
  95. ofs = 0;
  96. // set header
  97. MEM8(dstaddr + ofs) = pPtp->msgType | (pPtp->majorSdoId << 4);
  98. ofs++;
  99. MEM8(dstaddr + ofs) = pPtp->version | (pPtp->minorVersionPTP << 4);
  100. ofs++;
  101. mem16_htons(dstaddr + ofs, pPtp->msgLen);
  102. ofs += 2;
  103. MEM8(dstaddr + ofs) = pPtp->domainNumber;
  104. ofs++;
  105. MEM8(dstaddr + ofs) = pPtp->minorSdoId;
  106. ofs++;
  107. mem16_htons(dstaddr + ofs, SWAP16(pPtp->flags)); // flags used in network byte order in system
  108. ofs += 2;
  109. pSrc = (uint8_t *)(&(pPtp->correctionField));
  110. for (idx = 0; idx < 8; ++idx) {
  111. MEM8(dstaddr + ofs + idx) = pSrc[7 - idx];
  112. }
  113. ofs += idx; // inc by 8
  114. mem16_htons(dstaddr + ofs, 0); // reserved
  115. ofs += 2;
  116. mem16_htons(dstaddr + ofs, 0); // reserved
  117. ofs += 2;
  118. ofs += tsn_ptp_set_portid(dstaddr + ofs, &(pPtp->sourcePortId));
  119. mem16_htons(dstaddr + ofs, pPtp->sequenceId);
  120. ofs += 2;
  121. MEM8(dstaddr + ofs) = pPtp->control;
  122. ofs++;
  123. MEM8(dstaddr + ofs) = pPtp->logMsgInterval;
  124. ofs++;
  125. return ofs;
  126. }
  127. void tsn_ptp_adjust_timestamp(ptp_timestamp_t *pTimestamp, int32_t adjustNs)
  128. {
  129. int32_t ns;
  130. ns = (int32_t)pTimestamp->nanoseconds;
  131. ns += adjustNs;
  132. while (ns < 0) {
  133. ns += NS_PER_SEC;
  134. pTimestamp->seconds--;
  135. }
  136. while (ns >= NS_PER_SEC) {
  137. ns -= NS_PER_SEC;
  138. pTimestamp->seconds++;
  139. }
  140. pTimestamp->nanoseconds = ns;
  141. }
  142. /**
  143. * Convert MAC address (EUI-48) to ClockIdentity (EUI-64)
  144. *
  145. * @param pMacAddr Pointer to MAC address (u8[6])
  146. * @param pClockId Pointer to ClockIdentity (u8[8])
  147. */
  148. void tsn_ptp_mac_to_clockid(const uint8_t *pMacAddr, uint8_t *pClockId)
  149. {
  150. uint32_t idx;
  151. for (idx = 0; idx < 3; idx++) {
  152. pClockId[idx] = pMacAddr[idx];
  153. };
  154. pClockId[3] = 0xFF;
  155. pClockId[4] = 0xFE;
  156. for (idx = 3; idx < 6; idx++) {
  157. pClockId[idx + 2] = pMacAddr[idx];
  158. };
  159. }
  160. /**
  161. * Copy timestamp (48 sec, 32 bit nanosec)to memory address
  162. *
  163. * @param dstaddr Destination Address
  164. * @param pTimestamp Pointer to ptp_timestamp_t
  165. * @return returns number of written bytes (always 10)
  166. */
  167. uint32_t tsn_ptp_set_tstamp(uintptr_t dstaddr, ptp_timestamp_t *pTimestamp)
  168. {
  169. uint16_t *p16;
  170. // copy seconds
  171. p16 = (uint16_t *)(&pTimestamp->seconds);
  172. mem16_htons(dstaddr + 0, p16[2]);
  173. mem16_htons(dstaddr + 2, p16[1]);
  174. mem16_htons(dstaddr + 4, p16[0]);
  175. // copy nanoseconds
  176. p16 = (uint16_t *)(&pTimestamp->nanoseconds);
  177. mem16_htons(dstaddr + 6, p16[1]);
  178. mem16_htons(dstaddr + 8, p16[0]);
  179. return 10;
  180. }
  181. /**
  182. * Get Timestamp from PTP frame
  183. *
  184. * @param srcaddr Source Address of timestamp
  185. * @param pTimestamp pointer to ptp_timestamp_t structure
  186. */
  187. void tsn_ptp_get_tstamp(uintptr_t srcaddr, ptp_timestamp_t *pTimestamp)
  188. {
  189. uint16_t *pDst16;
  190. // copy seconds
  191. pDst16 = (uint16_t *)(&pTimestamp->seconds);
  192. pDst16[3] = 0; // only 48 bit seconds
  193. pDst16[2] = mem16_ntohs(srcaddr + 0);
  194. pDst16[1] = mem16_ntohs(srcaddr + 2);
  195. pDst16[0] = mem16_ntohs(srcaddr + 4);
  196. // copy nanoseconds
  197. pDst16 = (uint16_t *)(&pTimestamp->nanoseconds);
  198. pDst16[1] = mem16_ntohs(srcaddr + 6);
  199. pDst16[0] = mem16_ntohs(srcaddr + 8);
  200. }
  201. /**
  202. * Copy port identity to memory address
  203. *
  204. * @param dstaddr Destination Address
  205. * @param pPortId Pointer to port_id_t
  206. * @return returns number of written bytes (always 10)
  207. */
  208. uint32_t tsn_ptp_set_portid(uintptr_t dstaddr, port_id_t *pPortId)
  209. {
  210. int idx;
  211. uintptr_t addrClkId;
  212. // ClockIdentity
  213. addrClkId = (uintptr_t)(&pPortId->clockIdentity);
  214. for (idx = 0; idx < 8; ++idx) {
  215. MEM8(dstaddr + idx) = MEM8(addrClkId + idx);
  216. }
  217. // Port Number
  218. mem16_htons(dstaddr + 8, pPortId->portNumber);
  219. return 10;
  220. }
  221. /**
  222. * Get PortIdentity from PTP frame
  223. *
  224. * @param srcaddr address of portID within PTP frame
  225. * @param pPortId pointer to portIdentity structure
  226. */
  227. void tsn_ptp_get_portid(uintptr_t srcaddr, port_id_t *pPortId)
  228. {
  229. int idx;
  230. uintptr_t addrClkId;
  231. // ClockIdentity
  232. addrClkId = (uintptr_t)(&pPortId->clockIdentity);
  233. for (idx = 0; idx < 8; ++idx) {
  234. MEM8(addrClkId + idx) = MEM8(srcaddr + idx);
  235. }
  236. // Port Number
  237. pPortId->portNumber = mem16_ntohs(srcaddr + 8);
  238. }
  239. /**
  240. * Get PTP flags from address
  241. * Flags are defined in network byte order within this stack
  242. *
  243. * @param srcaddr address of flags within ptp header
  244. * @return flags
  245. */
  246. uint16_t tsn_ptp_get_flags(uintptr_t srcaddr)
  247. {
  248. uint16_t flags;
  249. flags = mem16_ntohs(srcaddr);
  250. return SWAP16(flags);
  251. }
  252. /**
  253. * Set Pdelay-Request Payload, 20 reserved bytes (0x00)
  254. * @param dstaddr Destination Address
  255. * @return returns number of written bytes (always 20)
  256. */
  257. uint32_t tsn_ptp_set_pdelay_req(uintptr_t dstaddr)
  258. {
  259. uint32_t ofs;
  260. // 2*10 bytes reserved
  261. for (ofs = 0; ofs < 20; ++ofs) {
  262. MEM8(dstaddr + ofs) = 0x00;
  263. }
  264. return ofs;
  265. }
  266. /**
  267. * Set Pdelay-Response Payload, Rx timestamp of request, request port Id
  268. *
  269. * @param dstaddr Destination Address
  270. * @param pRxTstamp rx timestamp, pointer to ptp_timestamp_t
  271. * @param pReqPortId requesting port id, pointer to port_id_t
  272. * @return returns number of written bytes (always 20)
  273. */
  274. uint32_t tsn_ptp_set_pdelay_resp(uintptr_t dstaddr, ptp_timestamp_t *pRxTstamp, port_id_t *pReqPortId)
  275. {
  276. uint32_t ofs;
  277. ofs = 0;
  278. ofs += tsn_ptp_set_tstamp(dstaddr + ofs, pRxTstamp);
  279. ofs += tsn_ptp_set_portid(dstaddr + ofs, pReqPortId);
  280. return ofs;
  281. }
  282. /**
  283. * Set Pdelay-Response-Followup Payload, Tx timestamp of response, request port Id
  284. *
  285. * @param dstaddr Destination Address
  286. * @param pRespOrigTstamp tx timestamp, pointer to struct ptp_timestamp_s
  287. * @param pReqPortId requesting port id, pointer to port_id_t
  288. * @return returns number of written bytes (always 20)
  289. */
  290. uint32_t tsn_ptp_set_pdelay_fup(uintptr_t dstaddr, ptp_timestamp_t *pRespOrigTstamp, port_id_t *pReqPortId)
  291. {
  292. uint32_t ofs;
  293. ofs = 0;
  294. ofs += tsn_ptp_set_tstamp(dstaddr + ofs, pRespOrigTstamp);
  295. ofs += tsn_ptp_set_portid(dstaddr + ofs, pReqPortId);
  296. return ofs;
  297. }
  298. /**
  299. * Set Sync Payload, 10 reserved bytes (0x00)
  300. *
  301. * @param dstaddr Destination Address
  302. * @return returns number of written bytes (always 10)
  303. */
  304. uint32_t tsn_ptp_set_sync(uintptr_t dstaddr)
  305. {
  306. uint32_t ofs;
  307. // 10 bytes reserved
  308. for (ofs = 0; ofs < 10; ++ofs) {
  309. MEM8(dstaddr + ofs) = 0x00;
  310. }
  311. return ofs;
  312. }
  313. /**
  314. * Copy FollowUp frame payload (precieOriginTimestamp + followup) to memory address
  315. *
  316. * @param dstaddr Destination Address
  317. * @param pFollowup Pointer to struct ptp_followup_tlv_s
  318. * @return returns number of written bytes (always 42)
  319. */
  320. uint32_t tsn_ptp_set_followup(uintptr_t dstaddr, struct ptp_followup_s *pFollowup)
  321. {
  322. uint32_t ofs;
  323. uint32_t idx;
  324. uint8_t orgId[6] = { 0x00, 0x80, 0xC2, 0x00, 0x00, 0x01 };
  325. ofs = 0;
  326. ofs += tsn_ptp_set_tstamp(dstaddr, &pFollowup->preciseOriginTimestamp); // preciseOriginTimestamp
  327. // TLV type + length
  328. mem16_htons(dstaddr + ofs + 0, PTP_TLV_TYPE_ORG_EXT);
  329. mem16_htons(dstaddr + ofs + 2, 28);
  330. ofs += 4;
  331. // Organization
  332. for (idx = 0; idx < 6; ++idx) {
  333. MEM8(dstaddr + ofs + idx) = orgId[idx];
  334. }
  335. ofs += idx;
  336. // cumScaledRateOfs
  337. mem32_htonl(dstaddr + ofs, (uint32_t)pFollowup->cumScaledRateOfs);
  338. ofs += 4;
  339. // gmTimeBaseIndicator
  340. mem16_htons(dstaddr + ofs, pFollowup->gmTimeBaseInd);
  341. ofs += 2;
  342. // lastGmPhaseChange 0, 0, ns[8], fns[2]
  343. mem16_htons(dstaddr + ofs + 0, pFollowup->lastGmPhaseCh.ns_msb);
  344. mem32_htonl(dstaddr + ofs + 2, pFollowup->lastGmPhaseCh.ns_lsb >> 32);
  345. mem32_htonl(dstaddr + ofs + 6, (uint32_t)pFollowup->lastGmPhaseCh.ns_lsb);
  346. mem16_htons(dstaddr + ofs + 10, pFollowup->lastGmPhaseCh.fns);
  347. ofs += 12;
  348. // scaledLastGmFreqChange
  349. mem32_htonl(dstaddr + ofs, (uint32_t)pFollowup->scaledLastGmFreqCh);
  350. ofs += 4;
  351. return ofs;
  352. }
  353. /**
  354. * Copy Signaling information to memory address
  355. *
  356. * @param dstaddr Destination Address
  357. * @param pSignaling Pointer to struct ptp_signaling_tlv_s
  358. * @return returns number of written bytes (always 26)
  359. */
  360. uint32_t tsn_ptp_set_signaling(uintptr_t dstaddr, struct ptp_signaling_tlv_s *pSignaling)
  361. {
  362. uint32_t ofs;
  363. uint32_t idx;
  364. uint8_t orgId[6] = { 0x00, 0x80, 0xC2, 0x00, 0x00, 0x02 };
  365. ofs = 0;
  366. // targetPortIdentity - dummy - "value is 0xFF" (ieee802.1as-2011, 10.5.4.2.1)
  367. for (idx = 0; idx < 10; ++idx) {
  368. MEM8(dstaddr + ofs + idx) = 0xFF;
  369. }
  370. ofs += idx;
  371. // TLV type + length
  372. mem16_htons(dstaddr + ofs + 0, PTP_TLV_TYPE_ORG_EXT);
  373. mem16_htons(dstaddr + ofs + 2, 12);
  374. ofs += 4;
  375. // Organization
  376. for (idx = 0; idx < 6; ++idx) {
  377. MEM8(dstaddr + ofs + idx) = orgId[idx];
  378. }
  379. ofs += idx;
  380. // Intervals + flags
  381. MEM8(dstaddr + ofs + 0) = (uint8_t)(pSignaling->linkDelayInterval);
  382. MEM8(dstaddr + ofs + 1) = (uint8_t)(pSignaling->timeSyncInterval);
  383. MEM8(dstaddr + ofs + 2) = (uint8_t)(pSignaling->announceInterval);
  384. MEM8(dstaddr + ofs + 3) = pSignaling->flags;
  385. ofs += 4;
  386. mem16_htons(dstaddr + ofs, 0); // reserved
  387. ofs += 2;
  388. return ofs;
  389. }
  390. /**
  391. * Copy Announce information to memory address
  392. * @param dstaddr Destination Address
  393. * @param pAnnounce announce information, pointer to struct ptp_announce_s
  394. * @return returns number of written bytes (always 34+8*pathCount)
  395. */
  396. uint32_t tsn_ptp_set_announce(uintptr_t dstaddr, struct ptp_announce_s *pAnnounce)
  397. {
  398. uint32_t ofs;
  399. uint32_t idx;
  400. uint32_t tmp;
  401. uint8_t *p8;
  402. ofs = 0;
  403. // reserved 10 byte
  404. for (idx = 0; idx < 5; ++idx) {
  405. mem16_htons(dstaddr + ofs + idx * 2, 0); // reserved
  406. }
  407. ofs += (idx * 2);
  408. mem16_htons(dstaddr + ofs, (uint16_t)pAnnounce->currentUtcOfs); // currentUtcOfs
  409. ofs += 2;
  410. MEM8(dstaddr + ofs) = 0; // reserved
  411. ofs++;
  412. MEM8(dstaddr + ofs) = pAnnounce->gmPrio1; // prio1
  413. ofs++;
  414. // clockQual
  415. MEM8(dstaddr + ofs) = pAnnounce->clockQuality.clockClass; // clockQual.clockClass
  416. ofs++;
  417. MEM8(dstaddr + ofs) = pAnnounce->clockQuality.clockAccuracy; // clockQual.clockAccuracy
  418. ofs++;
  419. // clockQual.ofsScaledLogVariance
  420. mem16_htons(dstaddr + ofs, pAnnounce->clockQuality.offsetScaledLogVariance);
  421. ofs += 2;
  422. MEM8(dstaddr + ofs) = pAnnounce->gmPrio2; // prio2
  423. ofs++;
  424. // gmid
  425. p8 = (uint8_t *)(&pAnnounce->gmIdentity);
  426. for (idx = 0; idx < 8; ++idx) {
  427. MEM8(dstaddr + ofs + idx) = p8[idx];
  428. }
  429. ofs += 8;
  430. mem16_htons(dstaddr + ofs, pAnnounce->stepsRemoved);
  431. ofs += 2;
  432. MEM8(dstaddr + ofs) = pAnnounce->timeSource;
  433. ofs++;
  434. // TLV type + length
  435. mem16_htons(dstaddr + ofs, PTP_TLV_TYPE_PATHTRACE);
  436. ofs += 2;
  437. tmp = pAnnounce->pathCount * PTP_PATHTRACE_SZ;
  438. mem16_htons(dstaddr + ofs, tmp);
  439. ofs += 2;
  440. // copy path (ClockIdentity)
  441. for (idx = 0; idx < tmp; idx++) {
  442. MEM8(dstaddr + ofs + idx) = pAnnounce->pPathSequence[idx];
  443. }
  444. ofs += idx;
  445. return ofs;
  446. }
  447. /**
  448. * Copy Followup information from frame to structure
  449. * @param addr address, to followup frame payload
  450. * @param pFollowup structure, where followup information is written
  451. * @return 0 on success, -1 on error
  452. */
  453. int32_t tsn_ptp_get_followup(uintptr_t addr, struct ptp_followup_s *pFollowup)
  454. {
  455. uint32_t tmp;
  456. uint32_t idx;
  457. #ifdef TSN_PTP_CFG_FOLLOWUP_TLV_ORG_CHECK
  458. uint8_t orgId[6] = { 0x00, 0x80, 0xC2, 0x00, 0x00, 0x01 };
  459. #endif
  460. // check param for NULL pointer
  461. if (pFollowup == 0)
  462. return -1;
  463. // offset = 0
  464. // precise origin timestamp
  465. tsn_ptp_get_tstamp(addr, &pFollowup->preciseOriginTimestamp);
  466. // offset = 10
  467. // CHECK TLV TYPE/LEN
  468. tmp = mem16_ntohs(addr + 10); // TLVTYPE
  469. if (tmp != PTP_TLV_TYPE_ORG_EXT)
  470. return -1;
  471. tmp = mem16_ntohs(addr + 12); // TLVLEN (exp 28)
  472. if (tmp != 28)
  473. return -1;
  474. // ORG
  475. #ifdef TSN_PTP_CFG_FOLLOWUP_TLV_ORG_CHECK
  476. for (idx = 0; idx < 6; ++idx) {
  477. if (MEM8(addr + idx + 14) != orgId[idx])
  478. return -1;
  479. }
  480. #endif // TSN_PTP_CFG_FOLLOWUP_TLV_ORG_CHECK
  481. // offset = 20
  482. pFollowup->cumScaledRateOfs = mem32_ntohl(addr + 20); // cumScaledRateOfs
  483. // offset = 24
  484. pFollowup->gmTimeBaseInd = mem16_ntohs(addr + 24); // gmTimeBaseIndicator
  485. // ofs = 26
  486. pFollowup->lastGmPhaseCh.ns_msb = mem16_ntohs(addr + 26 + 0);
  487. pFollowup->lastGmPhaseCh.ns_lsb = ((uint64_t)mem32_ntohl(addr + 26 + 2)) << 32;
  488. pFollowup->lastGmPhaseCh.ns_lsb |= mem32_ntohl(addr + 26 + 6);
  489. pFollowup->lastGmPhaseCh.fns = mem16_ntohs(addr + 26 + 10);
  490. // offset = 38
  491. pFollowup->scaledLastGmFreqCh = mem32_ntohl(addr + 38);
  492. return 0; // success
  493. }
  494. /**
  495. * Copy Announce frame information to structure
  496. * @param addr pointer to payload address of frame (first byte of reserve-field)
  497. * @param pAnnounce pointer to structure
  498. * @return 0 on success, -1 on error
  499. */
  500. int32_t tsn_ptp_get_announce(uintptr_t addr, struct ptp_announce_s *pAnnounce)
  501. {
  502. uint32_t idx;
  503. uint8_t *p8;
  504. uint16_t tlvType, tlvLen;
  505. // basic pointer check
  506. if (pAnnounce == 0) {
  507. return -1;
  508. }
  509. // reserved (10)
  510. // currentUtcOfs (2)
  511. pAnnounce->currentUtcOfs = mem16_ntohs(addr + 10);
  512. // rsv (1)
  513. // prio1 (1)
  514. pAnnounce->gmPrio1 = MEM8(addr + 13);
  515. // clock quality (4)
  516. pAnnounce->clockQuality.clockClass = MEM8(addr + 14);
  517. pAnnounce->clockQuality.clockAccuracy = MEM8(addr + 15);
  518. pAnnounce->clockQuality.offsetScaledLogVariance = mem16_ntohs(addr + 16);
  519. ;
  520. // prio2 (1)
  521. pAnnounce->gmPrio2 = MEM8(addr + 18);
  522. // gmid (8)
  523. p8 = (uint8_t *)(&pAnnounce->gmIdentity);
  524. for (idx = 0; idx < 8; ++idx) {
  525. p8[idx] = MEM8(addr + 19 + idx);
  526. }
  527. // stepsRemoved (2)
  528. pAnnounce->stepsRemoved = mem16_ntohs(addr + 27);
  529. // timesource (1)
  530. pAnnounce->timeSource = MEM8(addr + 29);
  531. // pathtrace TLV type/len (2/2)
  532. tlvType = mem16_ntohs(addr + 30);
  533. tlvLen = mem16_ntohs(addr + 32);
  534. if (tlvType == PTP_TLV_TYPE_PATHTRACE) {
  535. pAnnounce->pPathSequence = (uint8_t *)(addr + 34);
  536. pAnnounce->pathCount = tlvLen / PTP_PATHTRACE_SZ;
  537. } else {
  538. pAnnounce->pPathSequence = 0;
  539. pAnnounce->pathCount = 0;
  540. }
  541. return 0; // success
  542. }
  543. /**
  544. * Compare two SystemIdentities A and B
  545. * @param pSysIdA pointer to SystemIdentitiy A
  546. * @param pSysIdB pointer to SystemIdentitiy B
  547. * @return 0 when equal, else -1 if (A < B), else +1 if (A > B)
  548. */
  549. int32_t tsn_ptp_cmp_systemid(ptp_system_id_t *pSysIdA, ptp_system_id_t *pSysIdB)
  550. {
  551. // 10.3.2
  552. // a)
  553. if (pSysIdA->prio1 < pSysIdB->prio1)
  554. return -1;
  555. if (pSysIdA->prio1 > pSysIdB->prio1)
  556. return 1;
  557. // b)
  558. if (pSysIdA->clockQuality.clockClass < pSysIdB->clockQuality.clockClass)
  559. return -1;
  560. if (pSysIdA->clockQuality.clockClass > pSysIdB->clockQuality.clockClass)
  561. return 1;
  562. // c)
  563. if (pSysIdA->clockQuality.clockAccuracy < pSysIdB->clockQuality.clockAccuracy)
  564. return -1;
  565. if (pSysIdA->clockQuality.clockAccuracy > pSysIdB->clockQuality.clockAccuracy)
  566. return 1;
  567. // d)
  568. if (pSysIdA->clockQuality.offsetScaledLogVariance < pSysIdB->clockQuality.offsetScaledLogVariance)
  569. return -1;
  570. if (pSysIdA->clockQuality.offsetScaledLogVariance > pSysIdB->clockQuality.offsetScaledLogVariance)
  571. return 1;
  572. // e)
  573. if (pSysIdA->prio2 < pSysIdB->prio2)
  574. return -1;
  575. if (pSysIdA->prio2 > pSysIdB->prio2)
  576. return 1;
  577. // f
  578. if (pSysIdA->clockIdentity < pSysIdB->clockIdentity)
  579. return -1;
  580. if (pSysIdA->clockIdentity > pSysIdB->clockIdentity)
  581. return 1;
  582. return 0;
  583. }
  584. /**
  585. * Compare two priority vectors A and B
  586. * A is better than B when (A < B)
  587. *
  588. * @param pPrioA pointer to priority vector A
  589. * @param pPrioB pointer to priority vector B
  590. * @return 0 when equal, else -1 if (A < B), else +1 if (A > B)
  591. */
  592. int32_t tsn_ptp_cmp_priovect(ptp_prio_vect_t *pPrioA, ptp_prio_vect_t *pPrioB)
  593. {
  594. int32_t cmp;
  595. // 10.3.5
  596. // cmp systemId
  597. cmp = tsn_ptp_cmp_systemid(&(pPrioA->rootSystemId), &(pPrioB->rootSystemId));
  598. if (cmp != 0)
  599. return cmp;
  600. // cmp stepsRemoved
  601. if (pPrioA->stepsRemoved < pPrioB->stepsRemoved)
  602. return -1;
  603. if (pPrioA->stepsRemoved > pPrioB->stepsRemoved)
  604. return 1;
  605. // cmp sourcePortId
  606. if (pPrioA->sourcePortId.clockIdentity < pPrioB->sourcePortId.clockIdentity)
  607. return -1;
  608. if (pPrioA->sourcePortId.clockIdentity > pPrioB->sourcePortId.clockIdentity)
  609. return 1;
  610. if (pPrioA->sourcePortId.portNumber < pPrioB->sourcePortId.portNumber)
  611. return -1;
  612. if (pPrioA->sourcePortId.portNumber > pPrioB->sourcePortId.portNumber)
  613. return 1;
  614. // cmp portNum
  615. if (pPrioA->portNumber < pPrioB->portNumber)
  616. return -1;
  617. if (pPrioA->portNumber > pPrioB->portNumber)
  618. return 1;
  619. return 0;
  620. }