1 /***************************************************************************
2 * Copyright (c) 2024 Microsoft Corporation
3 *
4 * This program and the accompanying materials are made available under the
5 * terms of the MIT License which is available at
6 * https://opensource.org/licenses/MIT.
7 *
8 * SPDX-License-Identifier: MIT
9 **************************************************************************/
10
11 /**************************************************************************/
12 /**************************************************************************/
13 /** */
14 /** NetX PTP Client Component */
15 /** */
16 /** Precision Time Protocol (PTP) */
17 /** */
18 /**************************************************************************/
19 /**************************************************************************/
20
21 /**************************************************************************/
22 /* */
23 /* APPLICATION INTERFACE DEFINITION RELEASE */
24 /* */
25 /* nxd_ptp_client.c PORTABLE C */
26 /* 6.4.0 */
27 /* AUTHOR */
28 /* */
29 /* Yuxin Zhou, Microsoft Corporation */
30 /* */
31 /* DESCRIPTION */
32 /* */
33 /* This file defines the NetX Precision Time Protocol (PTP) */
34 /* Client component, including all data types and external references. */
35 /* */
36 /* RELEASE HISTORY */
37 /* */
38 /* DATE NAME DESCRIPTION */
39 /* */
40 /* 12-31-2020 Yuxin Zhou Initial Version 6.1.3 */
41 /* 12-31-2023 Tiejun Zhou Modified comment(s), and */
42 /* supported gPTP profile, */
43 /* supported master clock, */
44 /* resulting in version 6.4.0 */
45 /* */
46 /**************************************************************************/
47
48
49 /* Force error checking to be disabled in this module */
50
51 #ifndef NX_DISABLE_ERROR_CHECKING
52 #define NX_DISABLE_ERROR_CHECKING
53 #endif
54
55 #define NX_PTP_SOURCE_CODE
56
57 #include "nxd_ptp_client.h"
58 #if NX_PTP_CLIENT_TRANSPORT_UDP
59 #include "nx_udp.h"
60 #include "nx_ipv4.h"
61 #if defined(NX_ENABLE_IPV6_MULTICAST) && defined(FEATURE_NX_IPV6)
62 #include "nx_ipv6.h"
63 #endif
64 #endif
65 #include "tx_timer.h"
66
67 /* #define NX_PTP_DEBUG */
68 /* #define NX_PTP_DEBUG_OFFSET */
69 /* #define NX_PTP_DEBUG_DELAY */
70 /* #define NX_PTP_DEBUG_RATE_RATIO */
71 #if defined(NX_PTP_DEBUG) || defined(NX_PTP_DEBUG_OFFSET) || defined(NX_PTP_DEBUG_DELAY) || defined(NX_PTP_DEBUG_RATE_RATIO)
72 #include <stdio.h>
73 #endif
74 #ifdef NX_PTP_DEBUG
75 #ifndef NX_PTP_DEBUG_PRINTF
76 #define NX_PTP_DEBUG_PRINTF(x) printf x
77 #endif
78 #else
79 #define NX_PTP_DEBUG_PRINTF(x)
80 #endif
81
82 /* Bring in externs for caller checking code. */
83
84 NX_CALLER_CHECKING_EXTERNS
85
86 /* number of nanoseconds per second */
87 #define NX_PTP_NANOSECONDS_PER_SEC 1000000000L
88
89 /* Define the PTP version */
90 #define NX_PTP_VERSION 2
91
92 /* Define the UDP ports */
93 #define NX_PTP_EVENT_UDP_PORT 319
94 #define NX_PTP_GENERAL_UDP_PORT 320
95
96 /* Define the TTL of PTP packets */
97 #define NX_PTP_TIME_TO_LIVE 1
98
99 /* Define the IPv4 multicast address "224.0.1.129" */
100 #define NX_PTP_IPV4_MULTICAST_ADDR IP_ADDRESS(224, 0, 1, 129)
101
102 /* Define the IPv4 P2P multicast address "224.0.0.107" */
103 #define NX_PTP_IPV4_P2P_MULTICAST_ADDR IP_ADDRESS(224, 0, 0, 107)
104
105 /* Define the IPv6 multicast address "ff0e::181" */
106 #define NX_PTP_IPV6_MULTICAST_ADDR_SET(x) { \
107 (x) -> nxd_ip_version = NX_IP_VERSION_V6; \
108 (x) -> nxd_ip_address.v6[0] = 0xff0e0000UL; \
109 (x) -> nxd_ip_address.v6[1] = 0; \
110 (x) -> nxd_ip_address.v6[2] = 0; \
111 (x) -> nxd_ip_address.v6[3] = 0x181; }
112
113 /* Define the IPv6 multicast address "ff02::6b" */
114 #define NX_PTP_IPV6_P2P_MULTICAST_ADDR_SET(x) { \
115 (x) -> nxd_ip_version = NX_IP_VERSION_V6; \
116 (x) -> nxd_ip_address.v6[0] = 0xff020000UL; \
117 (x) -> nxd_ip_address.v6[1] = 0; \
118 (x) -> nxd_ip_address.v6[2] = 0; \
119 (x) -> nxd_ip_address.v6[3] = 0x6b; }
120
121 /* Define Ethernet type for PTPv2 over Ethernet */
122 #define NX_PTP_ETHERNET_TYPE 0x88F7
123
124 /* Define Ethernet multicast address for PTPv2 over Ethernet */
125 #define NX_PTP_ETHERNET_P2P_MULTICAST_ADDR_MSB 0x0180
126 #define NX_PTP_ETHERNET_P2P_MULTICAST_ADDR_LSB 0xC200000E
127
128 /* Define Ethernet multicast address for all except peer delay messages */
129 #define NX_PTP_ETHERNET_ALL_MULTICAST_ADDR_MSB 0x011b
130 #define NX_PTP_ETHERNET_ALL_MULTICAST_ADDR_LSB 0x19000000
131
132
133 #if NX_PTP_CLIENT_TRANSPORT_UDP
134 #define NX_PTP_PACKET NX_UDP_PACKET
135 #endif /* NX_PTP_CLIENT_TRANSPORT_UDP */
136 #if NX_PTP_CLIENT_TRANSPORT_ETHERNET
137 #define NX_PTP_PACKET NX_PHYSICAL_HEADER
138 #endif /* NX_PTP_CLIENT_TRANSPORT_ETHERNET */
139
140 /* Length of PTP message header */
141 #define NX_PTP_MSG_HDR_LEN 34
142
143 /* Length of PTP messages (without header) */
144 #define NX_PTP_MSG_ANNOUNCE_LEN 30
145 #define NX_PTP_MSG_SYNC_LEN 10
146 #define NX_PTP_MSG_FOLLOW_UP_LEN 10
147 #define NX_PTP_MSG_DELAY_RESP_LEN 20
148
149 /* Length of PTP messages gPTP (without header) */
150 #define NX_PTP_MSG_PDELAY_REQ_LEN 20
151 #define NX_PTP_MSG_PDELAY_RESP_LEN 20
152 #define NX_PTP_MSG_PDELAY_RESP_FOLLOW_UP_LEN 20
153 #define NX_PTP_MSG_PDELAY_RESERVED_LEN 10
154
155 /* Length of PTP timestamp */
156 #define NX_PTP_MSG_TIMESTAMP_LEN 10
157
158 /* Length of PTP correctionField */
159 #define NX_PTP_MSG_CFIELD_TIMESTAMP_LEN 8
160
161 /* Get version number */
162 #define NX_PTP_MSG_VERSION(p_) ((p_)[1] & 0xf)
163
164 /* Get domain number */
165 #define NX_PTP_MSG_DOMAIN(p_) ((p_)[4])
166
167 /* Type of messages */
168 #define NX_PTP_MSG_TYPE_SYNC 0
169 #define NX_PTP_MSG_TYPE_DELAY_REQ 1
170 #define NX_PTP_MSG_TYPE_PDELAY_REQ 2
171 #define NX_PTP_MSG_TYPE_PDELAY_RESP 3
172 #define NX_PTP_MSG_TYPE_FOLLOW_UP 8
173 #define NX_PTP_MSG_TYPE_DELAY_RESP 9
174 #define NX_PTP_MSG_TYPE_PDELAY_RESP_FOLLOW_UP 10
175 #define NX_PTP_MSG_TYPE_ANNOUNCE 11
176
177 /* Message flags */
178 #define NX_PTP_MSG_HDR_FLAG_LEAP61 (1 << 0)
179 #define NX_PTP_MSG_HDR_FLAG_LEAP59 (1 << 1)
180 #define NX_PTP_MSG_HDR_FLAG_UTC_REASONABLE (1 << 2)
181 #define NX_PTP_MSG_HDR_FLAG_TWO_STEP (1 << 9)
182
183 /* Common Message Header */
184 typedef struct NX_PTP_MSG_HEADER_STRUCT
185 {
186 UCHAR transportSpecific;
187 UCHAR messageType;
188 UCHAR versionPTP;
189 UCHAR domainNumber;
190 USHORT messageLength;
191 USHORT flagField;
192 ULONG cFieldHigh;
193 ULONG cFieldLow;
194 UCHAR *sourcePortIdentity;
195 USHORT sequenceId;
196 UCHAR logMessageInterval;
197 } NX_PTP_MSG_HEADER;
198
199 /* Get UTC offset from announce message */
200 #define NX_PTP_MSG_UTC_OFFSET(p_) ((SHORT)((p_[10] << 8) | p_[11]))
201
202 /* Macros for reading PTP packet fields */
203 #define NX_PTP_RD16(p_, v_) { \
204 USHORT t_; \
205 t_ = *p_++; \
206 t_ = (USHORT)(t_ << 8); \
207 v_ = (USHORT)(t_ | *p_++); }
208
209 #define NX_PTP_RD32(p_, v_) { \
210 ULONG t_; \
211 t_ = *p_++; \
212 t_ <<= 8; \
213 t_ |= *p_++; \
214 t_ <<= 8; \
215 t_ |= *p_++; \
216 t_ <<= 8; \
217 v_ = t_ |= *p_++; }
218
219 #if defined(NX_ENABLE_GPTP) || defined(NX_PTP_ENABLE_MASTER) || defined(NX_PTP_ENABLE_REVERSE_SYNC)
_nx_ptp_utility_32_unsigned_write(UCHAR * dest_ptr,ULONG value)220 static VOID _nx_ptp_utility_32_unsigned_write(UCHAR *dest_ptr, ULONG value)
221 {
222
223 *(dest_ptr) = (UCHAR)((value >> 24) & 0xFF);
224 *(dest_ptr + 1) = (UCHAR)((value >> 16) & 0xFF);
225 *(dest_ptr + 2) = (UCHAR)((value >> 8) & 0xFF);
226 *(dest_ptr + 3) = (UCHAR)(value & 0xFF);
227 }
228 #endif
229
230 #define NX_PTP_TS_RESET(ts) (ts).second_high = 0; \
231 (ts).second_low = 0; \
232 (ts).nanosecond = 0; \
233
234 #define NX_PTP_TS_COPY(ts1, ts2) (ts1).second_high = (ts2).second_high; \
235 (ts1).second_low = (ts2).second_low; \
236 (ts1).nanosecond = (ts2).nanosecond; \
237
238 #define NX_PTP_TS_EQUAL(ts1, ts2) ((ts1).second_high == (ts2).second_high && \
239 (ts1).second_low == (ts2).second_low && \
240 (ts1).nanosecond == (ts2).nanosecond)
241
242 /**************************************************************************/
243 /* */
244 /* FUNCTION RELEASE */
245 /* */
246 /* _nx_ptp_msg_parse_timestamp PORTABLE C */
247 /* 6.1.3 */
248 /* AUTHOR */
249 /* */
250 /* Yuxin Zhou, Microsoft Corporation */
251 /* */
252 /* DESCRIPTION */
253 /* */
254 /* This function parses timestamp field of a PTP message. */
255 /* */
256 /* INPUT */
257 /* */
258 /* ptr Pointer to PTP message */
259 /* time_ptr Pointer to PTP time for output*/
260 /* */
261 /* OUTPUT */
262 /* */
263 /* None */
264 /* */
265 /* CALLS */
266 /* */
267 /* None */
268 /* */
269 /* CALLED BY */
270 /* */
271 /* _nx_ptp_client_sync_received Process Sync message */
272 /* _nx_ptp_client_delay_resp_received Process delay response */
273 /* */
274 /* RELEASE HISTORY */
275 /* */
276 /* DATE NAME DESCRIPTION */
277 /* */
278 /* 12-31-2020 Yuxin Zhou Initial Version 6.1.3 */
279 /* */
280 /**************************************************************************/
_nx_ptp_msg_parse_timestamp(UCHAR * ptr,NX_PTP_TIME * time_ptr)281 static VOID _nx_ptp_msg_parse_timestamp(UCHAR *ptr, NX_PTP_TIME *time_ptr)
282 {
283 ULONG nanoseconds = (ULONG)time_ptr -> nanosecond;
284
285 NX_PTP_RD16(ptr, time_ptr -> second_high);
286 NX_PTP_RD32(ptr, time_ptr -> second_low);
287 NX_PTP_RD32(ptr, nanoseconds);
288 time_ptr -> nanosecond = (LONG)nanoseconds;
289 }
290
291
292 /**************************************************************************/
293 /* */
294 /* FUNCTION RELEASE */
295 /* */
296 /* _nx_ptp_msg_parse_hdr PORTABLE C */
297 /* 6.4.0 */
298 /* AUTHOR */
299 /* */
300 /* Yuxin Zhou, Microsoft Corporation */
301 /* */
302 /* DESCRIPTION */
303 /* */
304 /* This function parses the header of a PTP packet. */
305 /* */
306 /* INPUT */
307 /* */
308 /* client_ptr Pointer to PTP client */
309 /* packet_ptr Pointer to PTP packet */
310 /* hdr Parsed PTP header for output */
311 /* */
312 /* OUTPUT */
313 /* */
314 /* status Completion status */
315 /* */
316 /* CALLS */
317 /* */
318 /* nxd_udp_packet_info_extract Extract UDP packet information*/
319 /* */
320 /* CALLED BY */
321 /* */
322 /* _nx_ptp_client_process_event_packet Process PTP event packet */
323 /* _nx_ptp_client_process_general_packet Process PTP general packet */
324 /* */
325 /* RELEASE HISTORY */
326 /* */
327 /* DATE NAME DESCRIPTION */
328 /* */
329 /* 12-31-2020 Yuxin Zhou Initial Version 6.1.3 */
330 /* 12-31-2023 Tiejun Zhou Modified comment(s), and */
331 /* supported gPTP profile, */
332 /* resulting in version 6.4.0 */
333 /* */
334 /**************************************************************************/
_nx_ptp_msg_parse_hdr(NX_PTP_CLIENT * client_ptr,NX_PACKET * packet_ptr,NX_PTP_MSG_HEADER * hdr)335 static UINT _nx_ptp_msg_parse_hdr(NX_PTP_CLIENT *client_ptr, NX_PACKET *packet_ptr, NX_PTP_MSG_HEADER *hdr)
336 {
337 UCHAR b;
338 UCHAR *ptr;
339 UINT len;
340 #if NX_PTP_CLIENT_TRANSPORT_UDP
341 UINT status;
342 NXD_ADDRESS src_addr;
343 UINT interface_index;
344 #endif
345
346 #ifndef NX_DISABLE_PACKET_CHAIN
347 if (packet_ptr -> nx_packet_next)
348 {
349
350 /* Chained packet is not supported */
351 return(NX_NOT_SUPPORTED);
352 }
353 #endif /* NX_DISABLE_PACKET_CHAIN */
354
355 /* get pointer to PTP message */
356 ptr = packet_ptr -> nx_packet_prepend_ptr;
357
358 /* get length of PTP message */
359 len = packet_ptr -> nx_packet_length;
360
361 /* check packet validity: */
362 /* - length >= PTP header length */
363 /* - PTP version */
364 /* - domain number */
365 if ((len < NX_PTP_MSG_HDR_LEN) ||
366 (NX_PTP_MSG_VERSION(ptr) != NX_PTP_VERSION) ||
367 (NX_PTP_MSG_DOMAIN(ptr) != client_ptr -> nx_ptp_client_domain))
368 {
369
370 /* discard invalid packet */
371 return(NX_INVALID_PACKET);
372 }
373
374 #if NX_PTP_CLIENT_TRANSPORT_UDP
375 /* get info about sender and check packet validity: */
376 /* - network interface */
377 /* - IP version */
378 status = nxd_udp_packet_info_extract(packet_ptr, &src_addr, NX_NULL, NX_NULL, &interface_index);
379 if ((status != NX_SUCCESS) ||
380 (interface_index != client_ptr -> nx_ptp_client_interface_index)
381 #if defined(NX_ENABLE_IPV6_MULTICAST) && defined(FEATURE_NX_IPV6)
382 || ((src_addr.nxd_ip_version == NX_IP_VERSION_V4) &&
383 !client_ptr -> nx_ptp_client_ipv4_group_joined) ||
384 ((src_addr.nxd_ip_version == NX_IP_VERSION_V6) &&
385 !client_ptr -> nx_ptp_client_ipv6_group_joined)
386 #endif
387 )
388 {
389
390 /* discard invalid packet */
391 return(NX_INVALID_PACKET);
392 }
393
394 /* Save source address in listening state */
395 if (client_ptr -> nx_ptp_client_state == NX_PTP_CLIENT_STATE_LISTENING)
396 {
397 client_ptr -> nx_ptp_client_master_addr = src_addr;
398 }
399 #endif /* NX_PTP_CLIENT_TRANSPORT_UDP */
400
401 b = *ptr++;
402 hdr -> transportSpecific = b >> 4;
403 hdr -> messageType = b & 0xf;
404 b = *ptr++;
405 hdr -> versionPTP = b & 0xf;
406 NX_PTP_RD16(ptr, hdr -> messageLength);
407 hdr -> domainNumber = *ptr++;
408 ptr++; /* reserved */
409 NX_PTP_RD16(ptr, hdr -> flagField);
410 NX_PTP_RD32(ptr, hdr -> cFieldHigh);
411 NX_PTP_RD32(ptr, hdr -> cFieldLow);
412 ptr += 4; /* reserved */
413 hdr -> sourcePortIdentity = ptr;
414 ptr += NX_PTP_CLOCK_PORT_IDENTITY_SIZE;
415 NX_PTP_RD16(ptr, hdr -> sequenceId);
416 ptr++; /* controlField - ignore */
417 hdr -> logMessageInterval = *ptr;
418
419 /* adjust message length */
420 if (len > hdr -> messageLength)
421 {
422 if (hdr -> messageLength < NX_PTP_MSG_HDR_LEN)
423 {
424
425 /* invalid length */
426 return(NX_INVALID_PACKET);
427 }
428 len = hdr -> messageLength;
429 }
430
431 /* Adjust packet. */
432 packet_ptr -> nx_packet_prepend_ptr += NX_PTP_MSG_HDR_LEN;
433 packet_ptr -> nx_packet_length = len - NX_PTP_MSG_HDR_LEN;
434
435 return(NX_SUCCESS);
436 }
437
438
439 /**************************************************************************/
440 /* */
441 /* FUNCTION RELEASE */
442 /* */
443 /* _nx_ptp_msg_parse_announce PORTABLE C */
444 /* 6.1.3 */
445 /* AUTHOR */
446 /* */
447 /* Yuxin Zhou, Microsoft Corporation */
448 /* */
449 /* DESCRIPTION */
450 /* */
451 /* This function parses PTP Announce message. */
452 /* */
453 /* INPUT */
454 /* */
455 /* ptr Pointer to PTP message */
456 /* master_ptr Parsed PTP master for output */
457 /* */
458 /* OUTPUT */
459 /* */
460 /* None */
461 /* */
462 /* CALLS */
463 /* */
464 /* None */
465 /* */
466 /* CALLED BY */
467 /* */
468 /* _nx_ptp_client_init_packet_received Process Announce message */
469 /* */
470 /* RELEASE HISTORY */
471 /* */
472 /* DATE NAME DESCRIPTION */
473 /* */
474 /* 12-31-2020 Yuxin Zhou Initial Version 6.1.3 */
475 /* */
476 /**************************************************************************/
_nx_ptp_msg_parse_announce(UCHAR * ptr,NX_PTP_CLIENT_MASTER * master)477 static VOID _nx_ptp_msg_parse_announce(UCHAR *ptr, NX_PTP_CLIENT_MASTER *master)
478 {
479 ptr += NX_PTP_MSG_TIMESTAMP_LEN + 2 + 1; /* originTimestamp, utcOffset, reserved */
480 master -> nx_ptp_client_master_priority1 = *ptr++;
481 master -> nx_ptp_client_master_clock_class = *ptr++;
482 master -> nx_ptp_client_master_clock_accuracy = *ptr++;
483 NX_PTP_RD16(ptr, master -> nx_ptp_client_master_offset_scaled_log_variance);
484 master -> nx_ptp_client_master_priority2 = *ptr++;
485 master -> nx_ptp_client_master_grandmaster_identity = ptr;
486 ptr += NX_PTP_CLOCK_IDENTITY_SIZE;
487 NX_PTP_RD16(ptr, master -> nx_ptp_client_master_steps_removed);
488 master -> nx_ptp_client_master_time_source = *ptr;
489 }
490
491 #ifdef NX_PTP_ENABLE_MASTER
492 /**************************************************************************/
493 /* */
494 /* FUNCTION RELEASE */
495 /* */
496 /* _nx_ptp_client_master_clock_compare PORTABLE C */
497 /* 6.4.0 */
498 /* AUTHOR */
499 /* */
500 /* Tiejun Zhou, Microsoft Corporation */
501 /* */
502 /* DESCRIPTION */
503 /* */
504 /* This function compares two clocks for master1 and master2. */
505 /* */
506 /* INPUT */
507 /* */
508 /* master1 Pointer to first master clock */
509 /* master2 Pointer to second master clock*/
510 /* */
511 /* OUTPUT */
512 /* */
513 /* Compare result. */
514 /* Return positive if master1 is better than master2. */
515 /* Return zero if master1 is identical to master2. */
516 /* Return negative if master1 is worse than master2. */
517 /* */
518 /* CALLS */
519 /* */
520 /* memcmp Compare memory */
521 /* */
522 /* CALLED BY */
523 /* */
524 /* _nx_ptp_client_init_packet_received Process PTP announce message */
525 /* */
526 /* RELEASE HISTORY */
527 /* */
528 /* DATE NAME DESCRIPTION */
529 /* */
530 /* 12-31-2020 Yuxin Zhou Initial Version 6.1.3 */
531 /* */
532 /**************************************************************************/
_nx_ptp_client_master_clock_compare(NX_PTP_CLIENT_MASTER * master1,NX_PTP_CLIENT_MASTER * master2)533 static INT _nx_ptp_client_master_clock_compare(NX_PTP_CLIENT_MASTER *master1, NX_PTP_CLIENT_MASTER *master2)
534 {
535 INT result;
536 INT gm_compare;
537
538 gm_compare = memcmp(master2 -> nx_ptp_client_master_grandmaster_identity,
539 master1 -> nx_ptp_client_master_grandmaster_identity,
540 NX_PTP_CLOCK_IDENTITY_SIZE);
541 if (gm_compare == 0)
542 {
543
544 /* Clock identical. */
545 return(0);
546 }
547
548 result = (INT)master2 -> nx_ptp_client_master_priority1 -
549 (INT)master1 -> nx_ptp_client_master_priority1;
550 if (result != 0)
551 {
552 return(result);
553 }
554
555 result = (INT)master2 -> nx_ptp_client_master_clock_class -
556 (INT)master1 -> nx_ptp_client_master_clock_class;
557 if (result != 0)
558 {
559 return(result);
560 }
561
562 result = (INT)master2 -> nx_ptp_client_master_clock_accuracy -
563 (INT)master1 -> nx_ptp_client_master_clock_accuracy;
564 if (result != 0)
565 {
566 return(result);
567 }
568
569 result = (INT)master2 -> nx_ptp_client_master_offset_scaled_log_variance -
570 (INT)master1 -> nx_ptp_client_master_offset_scaled_log_variance;
571 if (result != 0)
572 {
573 return(result);
574 }
575
576 result = (INT)master2 -> nx_ptp_client_master_priority2 -
577 (INT)master1 -> nx_ptp_client_master_priority2;
578 if (result != 0)
579 {
580 return(result);
581 }
582
583 return(gm_compare);
584 }
585 #endif /* NX_PTP_ENABLE_MASTER */
586
587
588 /**************************************************************************/
589 /* */
590 /* FUNCTION RELEASE */
591 /* */
592 /* _nx_ptp_client_soft_clock_adjust PORTABLE C */
593 /* 6.1.3 */
594 /* AUTHOR */
595 /* */
596 /* Yuxin Zhou, Microsoft Corporation */
597 /* */
598 /* DESCRIPTION */
599 /* */
600 /* This function adjusts the value of the soft PTP clock. */
601 /* */
602 /* INPUT */
603 /* */
604 /* ptp_instance Pointer to PTP client */
605 /* offset_ns Signed number of nanoseconds */
606 /* to add to the PTP clock */
607 /* */
608 /* OUTPUT */
609 /* */
610 /* None */
611 /* */
612 /* CALLS */
613 /* */
614 /* _nx_ptp_client_utility_inc64 Increment a 64-bit number */
615 /* _nx_ptp_client_utility_dec64 Decrement a 64-bit number */
616 /* */
617 /* CALLED BY */
618 /* */
619 /* _nx_ptp_client_soft_clock_callback Soft PTP clock */
620 /* */
621 /* RELEASE HISTORY */
622 /* */
623 /* DATE NAME DESCRIPTION */
624 /* */
625 /* 12-31-2020 Yuxin Zhou Initial Version 6.1.3 */
626 /* */
627 /**************************************************************************/
_nx_ptp_client_soft_clock_adjust(VOID * ptp_instance,LONG offset_ns)628 static VOID _nx_ptp_client_soft_clock_adjust(VOID *ptp_instance, LONG offset_ns)
629 {
630 NX_PTP_CLIENT *client_ptr = (NX_PTP_CLIENT *)ptp_instance;
631 TX_INTERRUPT_SAVE_AREA
632
633 /* enforce min/max values of offset */
634 if (offset_ns > NX_PTP_NANOSECONDS_PER_SEC)
635 {
636 offset_ns = NX_PTP_NANOSECONDS_PER_SEC;
637 }
638 else if (offset_ns < -NX_PTP_NANOSECONDS_PER_SEC)
639 {
640 offset_ns = -NX_PTP_NANOSECONDS_PER_SEC;
641 }
642
643 /* add the number of nanosecond to the current time */
644 TX_DISABLE
645 client_ptr -> nx_ptp_client_soft_clock.nanosecond += offset_ns;
646 if (client_ptr -> nx_ptp_client_soft_clock.nanosecond >= NX_PTP_NANOSECONDS_PER_SEC)
647 {
648 client_ptr -> nx_ptp_client_soft_clock.nanosecond -= NX_PTP_NANOSECONDS_PER_SEC;
649 _nx_ptp_client_utility_inc64(&client_ptr -> nx_ptp_client_soft_clock.second_high,
650 &client_ptr -> nx_ptp_client_soft_clock.second_low);
651 }
652 else if (client_ptr -> nx_ptp_client_soft_clock.nanosecond < 0)
653 {
654 client_ptr -> nx_ptp_client_soft_clock.nanosecond += NX_PTP_NANOSECONDS_PER_SEC;
655 _nx_ptp_client_utility_dec64(&client_ptr -> nx_ptp_client_soft_clock.second_high,
656 &client_ptr -> nx_ptp_client_soft_clock.second_low);
657 }
658 TX_RESTORE
659 }
660
661
662 /**************************************************************************/
663 /* */
664 /* FUNCTION RELEASE */
665 /* */
666 /* _nx_ptp_client_timer_handler PORTABLE C */
667 /* 6.1.3 */
668 /* AUTHOR */
669 /* */
670 /* Yuxin Zhou, Microsoft Corporation */
671 /* */
672 /* DESCRIPTION */
673 /* */
674 /* This function implements the PTP client timer handler. */
675 /* */
676 /* INPUT */
677 /* */
678 /* ptp_instance Pointer to PTP client */
679 /* */
680 /* OUTPUT */
681 /* */
682 /* None */
683 /* */
684 /* CALLS */
685 /* */
686 /* tx_event_flags_set Set PTP timer event */
687 /* */
688 /* CALLED BY */
689 /* */
690 /* ThreadX Timer */
691 /* */
692 /* RELEASE HISTORY */
693 /* */
694 /* DATE NAME DESCRIPTION */
695 /* */
696 /* 12-31-2020 Yuxin Zhou Initial Version 6.1.3 */
697 /* */
698 /**************************************************************************/
_nx_ptp_client_timer_handler(ULONG ptp_instance)699 static VOID _nx_ptp_client_timer_handler(ULONG ptp_instance)
700 {
701 NX_PTP_CLIENT *client_ptr = (NX_PTP_CLIENT *)ptp_instance;
702
703 /* Update soft timer. */
704 client_ptr -> nx_ptp_client_clock_callback(client_ptr, NX_PTP_CLIENT_CLOCK_SOFT_TIMER_UPDATE,
705 &client_ptr -> nx_ptp_client_soft_clock, NX_NULL,
706 client_ptr -> nx_ptp_client_clock_callback_data);
707
708 /* set timer event */
709 tx_event_flags_set(&(client_ptr -> nx_ptp_client_events), NX_PTP_CLIENT_TIMER_EVENT, TX_OR);
710 }
711
712
713 #if NX_PTP_CLIENT_TRANSPORT_UDP
714 /**************************************************************************/
715 /* */
716 /* FUNCTION RELEASE */
717 /* */
718 /* _nx_ptp_client_socket_receive_notify PORTABLE C */
719 /* 6.1.3 */
720 /* AUTHOR */
721 /* */
722 /* Yuxin Zhou, Microsoft Corporation */
723 /* */
724 /* DESCRIPTION */
725 /* */
726 /* This function is invoked when UDP packet is received. */
727 /* */
728 /* INPUT */
729 /* */
730 /* socket_ptr Pointer to general socket */
731 /* */
732 /* OUTPUT */
733 /* */
734 /* None */
735 /* */
736 /* CALLS */
737 /* */
738 /* tx_event_flags_set Set UDP receive event */
739 /* */
740 /* CALLED BY */
741 /* */
742 /* NetX UDP */
743 /* */
744 /* RELEASE HISTORY */
745 /* */
746 /* DATE NAME DESCRIPTION */
747 /* */
748 /* 12-31-2020 Yuxin Zhou Initial Version 6.1.3 */
749 /* */
750 /**************************************************************************/
_nx_ptp_client_socket_receive_notify(NX_UDP_SOCKET * socket_ptr)751 static VOID _nx_ptp_client_socket_receive_notify(NX_UDP_SOCKET *socket_ptr)
752 {
753 NX_PTP_CLIENT *client_ptr = (NX_PTP_CLIENT *)(socket_ptr -> nx_udp_socket_reserved_ptr);
754
755 /* set timer event */
756 tx_event_flags_set(&(client_ptr -> nx_ptp_client_events), NX_PTP_CLIENT_RX_EVENT, TX_OR);
757 }
758 #endif /* NX_PTP_CLIENT_TRANSPORT_UDP */
759
760
761 #if NX_PTP_CLIENT_TRANSPORT_ETHERNET
762 /**************************************************************************/
763 /* */
764 /* FUNCTION RELEASE */
765 /* */
766 /* _nx_ptp_client_ethernet_receive_notify PORTABLE C */
767 /* 6.4.0 */
768 /* AUTHOR */
769 /* */
770 /* Tiejun Zhou, Microsoft Corporation */
771 /* */
772 /* DESCRIPTION */
773 /* */
774 /* This function is invoked when a packet is received. */
775 /* */
776 /* INPUT */
777 /* */
778 /* */
779 /* */
780 /* OUTPUT */
781 /* */
782 /* None */
783 /* */
784 /* CALLS */
785 /* */
786 /* tx_event_flags_set Set receive event */
787 /* */
788 /* CALLED BY */
789 /* */
790 /* NetX link layer */
791 /* */
792 /* RELEASE HISTORY */
793 /* */
794 /* DATE NAME DESCRIPTION */
795 /* */
796 /* 12-31-2023 Tiejun Zhou Initial Version 6.4.0 */
797 /* */
798 /**************************************************************************/
_nx_ptp_client_ethernet_receive_notify(NX_IP * ip_ptr,UINT interface_index,NX_PACKET * packet_ptr,ULONG physical_address_msw,ULONG physical_address_lsw,UINT packet_type,UINT header_size,VOID * context,struct NX_LINK_TIME_STRUCT * time_ptr)799 static UINT _nx_ptp_client_ethernet_receive_notify(NX_IP *ip_ptr, UINT interface_index, NX_PACKET *packet_ptr,
800 ULONG physical_address_msw, ULONG physical_address_lsw,
801 UINT packet_type, UINT header_size, VOID *context,
802 struct NX_LINK_TIME_STRUCT *time_ptr)
803 {
804 TX_INTERRUPT_SAVE_AREA
805 NX_PTP_CLIENT *client_ptr = (NX_PTP_CLIENT *)context;
806
807 NX_PARAMETER_NOT_USED(ip_ptr);
808 NX_PARAMETER_NOT_USED(interface_index);
809 NX_PARAMETER_NOT_USED(physical_address_msw);
810 NX_PARAMETER_NOT_USED(physical_address_lsw);
811 NX_PARAMETER_NOT_USED(packet_type);
812 NX_PARAMETER_NOT_USED(time_ptr);
813
814 /* Clean off the Ethernet header. */
815 packet_ptr -> nx_packet_prepend_ptr = packet_ptr -> nx_packet_prepend_ptr + header_size;
816
817 /* Adjust the packet length. */
818 packet_ptr -> nx_packet_length = packet_ptr -> nx_packet_length - header_size;
819
820 /* Disable interrupts. */
821 TX_DISABLE
822
823 /* Check to see if the receive queue is empty. */
824 if (client_ptr -> nx_ptp_client_received_packet_head)
825 {
826
827 /* Not empty, just place the packet at the end of the queue. */
828 (client_ptr -> nx_ptp_client_received_packet_tail) -> nx_packet_queue_next = packet_ptr;
829 packet_ptr -> nx_packet_queue_next = NX_NULL;
830 client_ptr -> nx_ptp_client_received_packet_tail = packet_ptr;
831
832 /* Restore interrupts. */
833 TX_RESTORE
834 }
835 else
836 {
837
838 /* Empty receive processing queue. */
839 client_ptr -> nx_ptp_client_received_packet_head = packet_ptr;
840 client_ptr -> nx_ptp_client_received_packet_tail = packet_ptr;
841 packet_ptr -> nx_packet_queue_next = NX_NULL;
842
843 /* Restore interrupts. */
844 TX_RESTORE
845
846 /* set timer event */
847 tx_event_flags_set(&(client_ptr -> nx_ptp_client_events), NX_PTP_CLIENT_RX_EVENT, TX_OR);
848 }
849 return(NX_SUCCESS);
850 }
851 #endif /* NX_PTP_CLIENT_TRANSPORT_UDP */
852
853
854 #ifndef NX_PTP_DISABLE_SLAVE
855 /**************************************************************************/
856 /* */
857 /* FUNCTION RELEASE */
858 /* */
859 /* _nx_ptp_client_clock_adjust PORTABLE C */
860 /* 6.4.0 */
861 /* AUTHOR */
862 /* */
863 /* Yuxin Zhou, Microsoft Corporation */
864 /* */
865 /* DESCRIPTION */
866 /* */
867 /* Adjust the PTP clock with the given offset */
868 /* If the offset is greater than one second, the clock is updated, */
869 /* otherwise it is adjusted with the number of nanoseconds. */
870 /* */
871 /* INPUT */
872 /* */
873 /* client_ptr Pointer to PTP client */
874 /* offset_ptr Pointer to time offset */
875 /* */
876 /* OUTPUT */
877 /* */
878 /* None */
879 /* */
880 /* CALLS */
881 /* */
882 /* _nx_ptp_client_utility_inc64 Increment a 64-bit number */
883 /* _nx_ptp_client_utility_dec64 Decrement a 64-bit number */
884 /* _nx_ptp_client_utility_add64 Add two 64-bit number */
885 /* */
886 /* CALLED BY */
887 /* */
888 /* _nx_ptp_client_delay_resp_received Process delay response */
889 /* */
890 /* RELEASE HISTORY */
891 /* */
892 /* DATE NAME DESCRIPTION */
893 /* */
894 /* 12-31-2020 Yuxin Zhou Initial Version 6.1.3 */
895 /* 12-31-2023 Tiejun Zhou Modified comment(s), and */
896 /* supported master clock, */
897 /* resulting in version 6.4.0 */
898 /* */
899 /**************************************************************************/
_nx_ptp_client_clock_adjust(NX_PTP_CLIENT * client_ptr,NX_PTP_TIME * offset_ptr)900 static VOID _nx_ptp_client_clock_adjust(NX_PTP_CLIENT *client_ptr, NX_PTP_TIME *offset_ptr)
901 {
902 NX_PTP_TIME current;
903
904 if ((offset_ptr -> second_high == 0) && (offset_ptr -> second_low == 0))
905 {
906
907 /* offset less than 1s, adjust clock */
908 client_ptr -> nx_ptp_client_clock_callback(client_ptr, NX_PTP_CLIENT_CLOCK_ADJUST, offset_ptr, NX_NULL,
909 client_ptr -> nx_ptp_client_clock_callback_data);
910 NX_PTP_DEBUG_PRINTF(("PTP: adjust clock %d ns\r\n", (INT)offset_ptr -> nanosecond));
911 }
912 else
913 {
914
915 /* offset greater than 1s, set new clock value */
916 /* get current clock value */
917 client_ptr -> nx_ptp_client_clock_callback(client_ptr, NX_PTP_CLIENT_CLOCK_GET, ¤t, NX_NULL,
918 client_ptr -> nx_ptp_client_clock_callback_data);
919
920 /* add nanoseconds offset */
921 current.nanosecond += offset_ptr -> nanosecond;
922
923 /* ensure nanosecond field is in range 0-999999999 */
924 if (current.nanosecond < 0)
925 {
926 current.nanosecond += NX_PTP_NANOSECONDS_PER_SEC;
927 _nx_ptp_client_utility_dec64(¤t.second_high, ¤t.second_low);
928 }
929 else if (current.nanosecond >= NX_PTP_NANOSECONDS_PER_SEC)
930 {
931 current.nanosecond -= NX_PTP_NANOSECONDS_PER_SEC;
932 _nx_ptp_client_utility_inc64(¤t.second_high, ¤t.second_low);
933 }
934
935 /* add seconds offset */
936 _nx_ptp_client_utility_add64(¤t.second_high, ¤t.second_low,
937 offset_ptr -> second_high, offset_ptr -> second_low);
938
939 /* set new clock value */
940 client_ptr -> nx_ptp_client_clock_callback(client_ptr, NX_PTP_CLIENT_CLOCK_SET, ¤t, NX_NULL,
941 client_ptr -> nx_ptp_client_clock_callback_data);
942
943 NX_PTP_DEBUG_PRINTF(("PTP: set clock %u.%d\r\n",
944 (UINT)current.second_low,
945 (INT)current.nanosecond));
946 }
947
948 #if defined(NX_PTP_ENABLE_MASTER) || defined(NX_PTP_ENABLE_REVERSE_SYNC)
949 if (client_ptr -> nx_ptp_client_sync_timer == 0)
950 {
951
952 /* Set timer values */
953 client_ptr -> nx_ptp_client_sync_timer = NX_PTP_CLIENT_SYNC_INTERVAL;
954 }
955 #endif /* defined(NX_PTP_ENABLE_MASTER) || defined(NX_PTP_ENABLE_REVERSE_SYNC) */
956 }
957 #endif
958
959 #if NX_PTP_CLIENT_TRANSPORT_UDP
960 /**************************************************************************/
961 /* */
962 /* FUNCTION RELEASE */
963 /* */
964 /* _nx_ptp_client_send_delay_req PORTABLE C */
965 /* 6.4.0 */
966 /* AUTHOR */
967 /* */
968 /* Yuxin Zhou, Microsoft Corporation */
969 /* */
970 /* DESCRIPTION */
971 /* */
972 /* This function sends a PTP Delay Request message. */
973 /* */
974 /* INPUT */
975 /* */
976 /* client_ptr Pointer to PTP client */
977 /* */
978 /* OUTPUT */
979 /* */
980 /* None */
981 /* */
982 /* CALLS */
983 /* */
984 /* nx_packet_allocate Allocate a packet */
985 /* nxd_udp_socket_source_send Send a UDP packet */
986 /* nx_packet_release Release a packet */
987 /* */
988 /* CALLED BY */
989 /* */
990 /* _nx_ptp_client_sync_received Process Sync message */
991 /* */
992 /* RELEASE HISTORY */
993 /* */
994 /* DATE NAME DESCRIPTION */
995 /* */
996 /* 12-31-2020 Yuxin Zhou Initial Version 6.1.3 */
997 /* 12-31-2023 Tiejun Zhou Modified comment(s), and */
998 /* supported gPTP profile, */
999 /* supported master clock, */
1000 /* resulting in version 6.4.0 */
1001 /* */
1002 /**************************************************************************/
_nx_ptp_client_send_delay_req(NX_PTP_CLIENT * client_ptr)1003 static VOID _nx_ptp_client_send_delay_req(NX_PTP_CLIENT *client_ptr)
1004 {
1005 NX_PACKET *packet_ptr;
1006 UINT status = NX_NOT_SUCCESSFUL;
1007 UCHAR *ptr;
1008 #if NX_PTP_CLIENT_TRANSPORT_UDP
1009 NXD_ADDRESS addr;
1010 UINT addr_index = 0;
1011 #if defined(NX_ENABLE_IPV6_MULTICAST) && defined(FEATURE_NX_IPV6)
1012 NXD_IPV6_ADDRESS *ipv6_addr;
1013 NX_IP *ip_ptr;
1014 NX_INTERFACE *if_ptr;
1015 #endif
1016 #endif /* NX_PTP_CLIENT_TRANSPORT_UDP */
1017
1018 /* allocate a packet from the pool */
1019 status = nx_packet_allocate(client_ptr -> nx_ptp_client_packet_pool_ptr, &packet_ptr, NX_PTP_PACKET, NX_NO_WAIT);
1020 if (status != NX_SUCCESS)
1021 {
1022 /* Failed to allocate the packet */
1023 return;
1024 }
1025
1026 /* start of message */
1027 ptr = packet_ptr -> nx_packet_prepend_ptr;
1028
1029 #define PTP_MSG_DELAY_REQ_TOTAL_LEN (NX_PTP_MSG_HDR_LEN + NX_PTP_MSG_TIMESTAMP_LEN)
1030 #define PTP_MSG_DELAY_REQ_ZERO1_LEN (1 + 2 + 8 + 4) /* reserved(1) | flagField(2) | correctionField(8) | reserved(4) */
1031
1032 /* write header */
1033 *ptr++ = NX_PTP_MSG_TYPE_DELAY_REQ;
1034 *ptr++ = NX_PTP_VERSION;
1035 *ptr++ = PTP_MSG_DELAY_REQ_TOTAL_LEN >> 8;
1036 *ptr++ = (UCHAR)PTP_MSG_DELAY_REQ_TOTAL_LEN;
1037 *ptr++ = (UCHAR)(client_ptr -> nx_ptp_client_transport_specific << 4) | client_ptr -> nx_ptp_client_domain;
1038 memset(ptr, 0, PTP_MSG_DELAY_REQ_ZERO1_LEN); /* reserved/flags/correction/reserved */
1039 ptr += PTP_MSG_DELAY_REQ_ZERO1_LEN;
1040 memcpy(ptr, client_ptr -> nx_ptp_client_port_identity,
1041 NX_PTP_CLOCK_PORT_IDENTITY_SIZE); /* use case of memcpy is verified. */
1042 ptr += NX_PTP_CLOCK_PORT_IDENTITY_SIZE;
1043 client_ptr -> nx_ptp_client_delay_req_id++;
1044 *ptr++ = (UCHAR)(client_ptr -> nx_ptp_client_delay_req_id >> 8);
1045 *ptr++ = (UCHAR)client_ptr -> nx_ptp_client_delay_req_id;
1046 *ptr++ = 0; /* control */
1047 *ptr++ = 0; /* XXX */
1048
1049 /* write timestamp (0) */
1050 memset(ptr, 0, NX_PTP_MSG_TIMESTAMP_LEN);
1051 ptr += NX_PTP_MSG_TIMESTAMP_LEN;
1052
1053 /* set final length of message */
1054 packet_ptr -> nx_packet_length = (ULONG)(ptr - packet_ptr -> nx_packet_prepend_ptr);
1055 packet_ptr -> nx_packet_append_ptr = ptr;
1056
1057 #if NX_PTP_CLIENT_TRANSPORT_UDP
1058 /* set source and destination addresses */
1059 #if defined(NX_ENABLE_IPV6_MULTICAST) && defined(FEATURE_NX_IPV6)
1060 if (client_ptr -> nx_ptp_client_master_addr.nxd_ip_version == NX_IP_VERSION_V6)
1061 {
1062 NX_PTP_IPV6_MULTICAST_ADDR_SET(&addr);
1063
1064 /* Use first IPv6 address as source address. */
1065 ip_ptr = client_ptr -> nx_ptp_client_ip_ptr;
1066 if_ptr = &ip_ptr -> nx_ip_interface[client_ptr -> nx_ptp_client_interface_index];
1067 ipv6_addr = if_ptr -> nxd_interface_ipv6_address_list_head;
1068 if (ipv6_addr == NX_NULL)
1069 {
1070
1071 /* No available IPv6 address. */
1072 /* Release packet. */
1073 nx_packet_release(packet_ptr);
1074
1075 /* Reset state. */
1076 client_ptr -> nx_ptp_client_delay_state = NX_PTP_CLIENT_DELAY_IDLE;
1077 client_ptr -> nx_ptp_client_delay_req_packet_ptr = NX_NULL;
1078
1079 return;
1080 }
1081 addr_index = ipv6_addr -> nxd_ipv6_address_index;
1082 }
1083 else
1084 #endif
1085 {
1086 #ifndef NX_DISABLE_IPV4
1087 addr.nxd_ip_version = NX_IP_VERSION_V4;
1088 addr.nxd_ip_address.v4 = NX_PTP_IPV4_MULTICAST_ADDR;
1089 addr_index = client_ptr -> nx_ptp_client_interface_index;
1090 #endif
1091 }
1092 #endif /* NX_PTP_CLIENT_TRANSPORT_UDP */
1093
1094 /* Prepare timestamp for current packet */
1095 client_ptr -> nx_ptp_client_delay_state = NX_PTP_CLIENT_DELAY_WAIT_REQ_TS;
1096 client_ptr -> nx_ptp_client_delay_req_packet_ptr = packet_ptr;
1097 client_ptr -> nx_ptp_client_clock_callback(client_ptr, NX_PTP_CLIENT_CLOCK_PACKET_TS_PREPARE,
1098 &client_ptr -> nx_ptp_client_delay_ts, packet_ptr,
1099 client_ptr -> nx_ptp_client_clock_callback_data);
1100
1101 /* Send delay request */
1102 #if NX_PTP_CLIENT_TRANSPORT_UDP
1103 status = nxd_udp_socket_source_send((NX_UDP_SOCKET *)&client_ptr -> nx_ptp_client_event_socket,
1104 packet_ptr, &addr, NX_PTP_EVENT_UDP_PORT, addr_index);
1105 #endif /* NX_PTP_CLIENT_TRANSPORT_UDP */
1106 #if NX_PTP_CLIENT_TRANSPORT_ETHERNET
1107 nx_link_ethernet_packet_send(client_ptr -> nx_ptp_client_ip_ptr,
1108 client_ptr -> nx_ptp_client_interface_index, packet_ptr,
1109 NX_PTP_ETHERNET_ALL_MULTICAST_ADDR_MSB,
1110 NX_PTP_ETHERNET_ALL_MULTICAST_ADDR_LSB,
1111 NX_PTP_ETHERNET_TYPE);
1112 #endif /* NX_PTP_CLIENT_TRANSPORT_ETHERNET */
1113 if (status)
1114 {
1115
1116 /* release packet in case of error */
1117 nx_packet_release(packet_ptr);
1118
1119 /* reset state */
1120 client_ptr -> nx_ptp_client_delay_state = NX_PTP_CLIENT_DELAY_IDLE;
1121 client_ptr -> nx_ptp_client_delay_req_packet_ptr = NX_NULL;
1122
1123 return;
1124 }
1125
1126 /* rearm delay req timer */
1127 client_ptr -> nx_ptp_client_delay_req_timer = NX_PTP_CLIENT_DELAY_REQ_INTERVAL;
1128 client_ptr -> nx_ptp_client_delay_req_flag = 0;
1129 }
1130 #endif
1131
1132 /**************************************************************************/
1133 /* */
1134 /* FUNCTION RELEASE */
1135 /* */
1136 /* _nx_ptp_client_sync_received PORTABLE C */
1137 /* 6.4.0 */
1138 /* AUTHOR */
1139 /* */
1140 /* Yuxin Zhou, Microsoft Corporation */
1141 /* */
1142 /* DESCRIPTION */
1143 /* */
1144 /* This function processes a received PTP Sync message. */
1145 /* */
1146 /* INPUT */
1147 /* */
1148 /* client_ptr Pointer to PTP client */
1149 /* ts_ptr Pointer to the timestamp */
1150 /* delivered by the Sync message*/
1151 /* hdr Pointer to PTP header */
1152 /* */
1153 /* OUTPUT */
1154 /* */
1155 /* None */
1156 /* */
1157 /* CALLS */
1158 /* */
1159 /* _nx_ptp_msg_parse_timestamp Parse timestamp field */
1160 /* _nx_ptp_client_send_delay_req Send delay request */
1161 /* */
1162 /* CALLED BY */
1163 /* */
1164 /* _nx_ptp_client_process_event_packet Process PTP event packet */
1165 /* _nx_ptp_client_process_general_packet Process PTP general packet */
1166 /* */
1167 /* RELEASE HISTORY */
1168 /* */
1169 /* DATE NAME DESCRIPTION */
1170 /* */
1171 /* 12-31-2020 Yuxin Zhou Initial Version 6.1.3 */
1172 /* 12-31-2023 Tiejun Zhou Modified comment(s), and */
1173 /* supported gPTP profile, */
1174 /* supported master clock, */
1175 /* resulting in version 6.4.0 */
1176 /* */
1177 /**************************************************************************/
_nx_ptp_client_sync_received(NX_PTP_CLIENT * client_ptr,VOID * ts_ptr,NX_PTP_MSG_HEADER * hdr)1178 static VOID _nx_ptp_client_sync_received(NX_PTP_CLIENT *client_ptr, VOID *ts_ptr, NX_PTP_MSG_HEADER *hdr)
1179 {
1180 #if defined NX_ENABLE_GPTP
1181 NX_PTP_TIME offset;
1182 #ifndef NX_PTP_DISABLE_SLAVE
1183 NX_PTP_CLIENT_SYNC sync;
1184 #endif /* NX_PTP_DISABLE_SLAVE */
1185 #if defined(NX_PTP_DEBUG) || defined(NX_PTP_DEBUG_OFFSET)
1186 double rate_ratio;
1187 NX_PTP_TIME delta_t1, delta_t2;
1188 #endif
1189 #endif /* NX_ENABLE_GPTP */
1190 NX_PTP_TIME correction;
1191 ULONG64 correctionNS = (hdr -> cFieldHigh << 16) | (hdr -> cFieldLow >> 16);
1192
1193 /* store Sync master timestamp */
1194 _nx_ptp_msg_parse_timestamp(ts_ptr, &client_ptr -> nx_ptp_client_sync);
1195
1196 if (correctionNS != 0)
1197 {
1198
1199 /* add correction field to offset. */
1200 correction.second_high = 0;
1201 correction.second_low = (ULONG)(correctionNS / 1000000000);
1202 correction.nanosecond = (LONG)(correctionNS % 1000000000);
1203 _nx_ptp_client_utility_time_sum(&client_ptr -> nx_ptp_client_sync, &correction,
1204 &client_ptr -> nx_ptp_client_sync);
1205 }
1206
1207 #if defined NX_ENABLE_GPTP
1208
1209 if ((client_ptr -> nx_ptp_client_delay.nanosecond > NX_PTP_CLIENT_DELAY_THRESH) ||
1210 (client_ptr -> nx_ptp_client_delay.second_low != 0) ||
1211 (client_ptr -> nx_ptp_client_delay.second_high != 0))
1212 {
1213
1214 /* Not as capable. IEEE802.1AS-202, 11.2.2. */
1215 return;
1216 }
1217
1218 #if defined(NX_PTP_DEBUG) || defined(NX_PTP_DEBUG_OFFSET)
1219 /* Compute neighbor rate ratio.
1220 neighborRateRatio = (t1 - prev_t1) / (t2 - prev_t2) */
1221 _nx_ptp_client_utility_time_diff(&client_ptr -> nx_ptp_client_sync,
1222 &client_ptr -> nx_ptp_client_prev_sync, &delta_t1);
1223 _nx_ptp_client_utility_time_diff(&client_ptr -> nx_ptp_client_sync_ts,
1224 &client_ptr -> nx_ptp_client_prev_sync_ts, &delta_t2);
1225 if ((delta_t1.second_low == 0) && (delta_t1.second_high == 0) &&
1226 (delta_t2.second_low == 0) && (delta_t2.second_high == 0))
1227 {
1228 rate_ratio = (double)delta_t1.nanosecond / (double)delta_t2.nanosecond;
1229 }
1230 else
1231 {
1232 rate_ratio = 1.0;
1233 }
1234 NX_PTP_DEBUG_PRINTF(("PTP: neighborRateRatio = %lu/%lu = %f\n",
1235 delta_t1.nanosecond, delta_t2.nanosecond, rate_ratio));
1236 #endif
1237
1238 /* compute offset = sync_ts - sync_received_ts + delay */
1239 _nx_ptp_client_utility_time_diff(&client_ptr -> nx_ptp_client_sync, &client_ptr -> nx_ptp_client_sync_ts, &offset);
1240 _nx_ptp_client_utility_time_sum(&offset, &client_ptr -> nx_ptp_client_delay, &offset);
1241
1242 #if defined(NX_PTP_DEBUG) || defined(NX_PTP_DEBUG_OFFSET)
1243 if ((offset.second_low == 0) && (offset.second_high == 0))
1244 {
1245 if ((offset.nanosecond > -1000) && (offset.nanosecond < 1000))
1246 {
1247 NX_PTP_DEBUG_PRINTF(("PTP: offset = %ld ns\n", offset.nanosecond));
1248 }
1249 else if ((offset.nanosecond > -1000000) && (offset.nanosecond < 1000000))
1250 {
1251 NX_PTP_DEBUG_PRINTF(("PTP: offset = %ld us\n", offset.nanosecond / 1000));
1252 }
1253 else
1254 {
1255 NX_PTP_DEBUG_PRINTF(("PTP: offset = %ld ms\n", offset.nanosecond / 1000000));
1256 }
1257 }
1258 else
1259 {
1260 NX_PTP_DEBUG_PRINTF(("PTP: offset > 1s\n"));
1261 }
1262 #endif
1263
1264 #ifndef NX_PTP_DISABLE_SLAVE
1265 if (client_ptr -> nx_ptp_client_state == NX_PTP_CLIENT_STATE_SLAVE)
1266 {
1267
1268 /* add the time offset the client clock */
1269 _nx_ptp_client_clock_adjust(client_ptr, &offset);
1270
1271 /* set calibrated flag */
1272 if (!(client_ptr -> nx_ptp_client_sync_flags & NX_PTP_CLIENT_SYNC_CALIBRATED))
1273 {
1274 client_ptr -> nx_ptp_client_sync_flags |= NX_PTP_CLIENT_SYNC_CALIBRATED;
1275
1276 /* application callback */
1277 if (client_ptr -> nx_ptp_client_event_callback)
1278 {
1279 sync.nx_ptp_client_sync_flags = client_ptr -> nx_ptp_client_sync_flags;
1280 sync.nx_ptp_client_sync_utc_offset = client_ptr -> nx_ptp_client_utc_offset;
1281 client_ptr -> nx_ptp_client_event_callback(client_ptr, NX_PTP_CLIENT_EVENT_SYNC, &sync,
1282 client_ptr -> nx_ptp_client_event_callback_data);
1283 }
1284 }
1285 }
1286 #endif /* NX_PTP_DISABLE_SLAVE */
1287
1288 /* update pdelay responder state */
1289 client_ptr -> nx_ptp_client_pdelay_responder_state = NX_PTP_CLIENT_PDELAY_WAIT_REQ;
1290 #else
1291 /* delay and offset determination */
1292 if (client_ptr -> nx_ptp_client_delay_req_flag)
1293 {
1294
1295 /* send delay request message */
1296 /* (delay_req_flag is cleared by this function) */
1297 _nx_ptp_client_send_delay_req(client_ptr);
1298 }
1299 #endif
1300 }
1301
1302 #if NX_PTP_CLIENT_TRANSPORT_UDP
1303 /**************************************************************************/
1304 /* */
1305 /* FUNCTION RELEASE */
1306 /* */
1307 /* _nx_ptp_client_delay_resp_received PORTABLE C */
1308 /* 6.4.0 */
1309 /* AUTHOR */
1310 /* */
1311 /* Yuxin Zhou, Microsoft Corporation */
1312 /* */
1313 /* DESCRIPTION */
1314 /* */
1315 /* This function processes a received PTP Delay Response message. */
1316 /* */
1317 /* INPUT */
1318 /* */
1319 /* client_ptr Pointer to PTP client */
1320 /* ts_ptr Pointer to the timestamp */
1321 /* delivered by the Delay Resp */
1322 /* message */
1323 /* */
1324 /* OUTPUT */
1325 /* */
1326 /* None */
1327 /* */
1328 /* CALLS */
1329 /* */
1330 /* _nx_ptp_client_clock_adjust Adjust PTP clock */
1331 /* _nx_ptp_msg_parse_timestamp Parse timestamp field */
1332 /* _nx_ptp_client_utility_time_diff Diff two PTP times */
1333 /* _nx_ptp_client_utility_time_div_by_2 Divide a PTP time by 2 */
1334 /* */
1335 /* CALLED BY */
1336 /* */
1337 /* _nx_ptp_client_process_general_packet Process PTP general packet */
1338 /* */
1339 /* RELEASE HISTORY */
1340 /* */
1341 /* DATE NAME DESCRIPTION */
1342 /* */
1343 /* 12-31-2020 Yuxin Zhou Initial Version 6.1.3 */
1344 /* 03-02-2021 Yuxin Zhou Modified comment(s), and */
1345 /* fixed compiler warnings, */
1346 /* resulting in version 6.1.5 */
1347 /* 12-31-2023 Tiejun Zhou Modified comment(s), and */
1348 /* simplified debug output, */
1349 /* resulting in version 6.4.0 */
1350 /* */
1351 /**************************************************************************/
_nx_ptp_client_delay_resp_received(NX_PTP_CLIENT * client_ptr,VOID * ts_ptr)1352 static VOID _nx_ptp_client_delay_resp_received(NX_PTP_CLIENT *client_ptr, VOID *ts_ptr)
1353 {
1354 NX_PTP_TIME t4, a, b;
1355 NX_PTP_CLIENT_SYNC sync;
1356
1357 /*
1358 * The following timestamps are used for delay/offset determination:
1359 *
1360 * t1 = nx_ptp_client_sync
1361 * t2 = nx_ptp_client_sync_ts
1362 * t3 = nx_ptp_client_delay_ts
1363 * t4 = timestamp in Delay_Resp message (ts_ptr)
1364 *
1365 * A = t2 - t1
1366 * B = t4 - t3
1367 *
1368 * delay = (A + B) / 2
1369 * offset = (B - A) / 2
1370 */
1371
1372 /* check for valid timestamp t1 */
1373 if ((client_ptr -> nx_ptp_client_sync.second_low == 0) &&
1374 (client_ptr -> nx_ptp_client_sync.second_high == 0))
1375 {
1376 return;
1377 }
1378
1379 /* get master clock timestamp */
1380 _nx_ptp_msg_parse_timestamp(ts_ptr, &t4);
1381
1382 /* compute A = t2 - t1 */
1383 _nx_ptp_client_utility_time_diff(&client_ptr -> nx_ptp_client_sync_ts, &client_ptr -> nx_ptp_client_sync, &a);
1384
1385 /* compute B = t4 - t3 */
1386 _nx_ptp_client_utility_time_diff(&t4, &client_ptr -> nx_ptp_client_delay_ts, &b);
1387
1388 /* compute offset = (B - A) / 2 */
1389 _nx_ptp_client_utility_time_diff(&b, &a, &a);
1390 _nx_ptp_client_utility_time_div_by_2(&a);
1391
1392 #if defined(NX_PTP_DEBUG) || defined(NX_PTP_DEBUG_OFFSET)
1393 if ((a.second_low == 0) && (a.second_high == 0))
1394 {
1395 if ((a.nanosecond > -1000) && (a.nanosecond < 1000))
1396 {
1397 NX_PTP_DEBUG_PRINTF(("PTP: offset = %ld ns\n", a.nanosecond));
1398 }
1399 else if ((a.nanosecond > -1000000) && (a.nanosecond < 1000000))
1400 {
1401 NX_PTP_DEBUG_PRINTF(("PTP: offset = %ld us\n", a.nanosecond / 1000));
1402 }
1403 else
1404 {
1405 NX_PTP_DEBUG_PRINTF(("PTP: offset = %ld ms\n", a.nanosecond / 1000000));
1406 }
1407 }
1408 else
1409 {
1410 NX_PTP_DEBUG_PRINTF(("PTP: offset > 1s\n"));
1411 }
1412 #endif
1413
1414 /* add the time offset the client clock */
1415 _nx_ptp_client_clock_adjust(client_ptr, &a);
1416
1417 /* set calibrated flag */
1418 if (!(client_ptr -> nx_ptp_client_sync_flags & NX_PTP_CLIENT_SYNC_CALIBRATED))
1419 {
1420
1421 client_ptr -> nx_ptp_client_sync_flags |= NX_PTP_CLIENT_SYNC_CALIBRATED;
1422
1423 /* application callback */
1424 if (client_ptr -> nx_ptp_client_event_callback)
1425 {
1426 sync.nx_ptp_client_sync_flags = client_ptr -> nx_ptp_client_sync_flags;
1427 sync.nx_ptp_client_sync_utc_offset = client_ptr -> nx_ptp_client_utc_offset;
1428 client_ptr -> nx_ptp_client_event_callback(client_ptr, NX_PTP_CLIENT_EVENT_SYNC, &sync,
1429 client_ptr -> nx_ptp_client_event_callback_data);
1430 }
1431 }
1432
1433 /* update delay req state */
1434 client_ptr -> nx_ptp_client_delay_state = NX_PTP_CLIENT_DELAY_IDLE;
1435 }
1436 #endif
1437
1438 /**************************************************************************/
1439 /* */
1440 /* FUNCTION RELEASE */
1441 /* */
1442 /* _nx_ptp_client_init_packet_received PORTABLE C */
1443 /* 6.4.0 */
1444 /* AUTHOR */
1445 /* */
1446 /* Yuxin Zhou, Microsoft Corporation */
1447 /* */
1448 /* DESCRIPTION */
1449 /* */
1450 /* This function processes a received PTP Announce message. */
1451 /* */
1452 /* INPUT */
1453 /* */
1454 /* client_ptr Pointer to PTP client */
1455 /* hdr Pointer to PTP header */
1456 /* ptr Pointer to PTP message */
1457 /* */
1458 /* OUTPUT */
1459 /* */
1460 /* None */
1461 /* */
1462 /* CALLS */
1463 /* */
1464 /* _nx_ptp_msg_parse_announce Parse Announce message */
1465 /* memcpy Copy memory */
1466 /* */
1467 /* CALLED BY */
1468 /* */
1469 /* _nx_ptp_client_process_general_packet Process PTP general packet */
1470 /* _nx_ptp_client_master_clock_compare Compare two master clocks */
1471 /* */
1472 /* RELEASE HISTORY */
1473 /* */
1474 /* DATE NAME DESCRIPTION */
1475 /* */
1476 /* 12-31-2020 Yuxin Zhou Initial Version 6.1.3 */
1477 /* 12-31-2023 Tiejun Zhou Modified comment(s), and */
1478 /* supported gPTP profile, */
1479 /* supported master clock, */
1480 /* resulting in version 6.4.0 */
1481 /* */
1482 /**************************************************************************/
_nx_ptp_client_init_packet_received(NX_PTP_CLIENT * client_ptr,NX_PTP_MSG_HEADER * hdr,UCHAR * ptr)1483 static VOID _nx_ptp_client_init_packet_received(NX_PTP_CLIENT *client_ptr,
1484 NX_PTP_MSG_HEADER *hdr,
1485 UCHAR *ptr)
1486 {
1487 NX_PTP_CLIENT_SYNC sync;
1488 NX_PTP_CLIENT_MASTER master;
1489 #ifdef NX_PTP_ENABLE_MASTER
1490 INT compare_result;
1491
1492 if (client_ptr -> nx_ptp_client_role == NX_PTP_CLIENT_ROLE_MASTER_ONLY)
1493 {
1494
1495 /* ignore announce packet for master only mode */
1496 return;
1497 }
1498 #endif /* NX_PTP_ENABLE_MASTER */
1499
1500 /* parse Sync information */
1501 sync.nx_ptp_client_sync_flags = 0;
1502 if (hdr -> flagField & NX_PTP_MSG_HDR_FLAG_UTC_REASONABLE)
1503 {
1504 sync.nx_ptp_client_sync_flags |= NX_PTP_CLIENT_SYNC_UTC_REASONABLE;
1505 }
1506 if (hdr -> flagField & NX_PTP_MSG_HDR_FLAG_LEAP59)
1507 {
1508 sync.nx_ptp_client_sync_flags |= NX_PTP_CLIENT_SYNC_LEAP59;
1509 }
1510 if (hdr -> flagField & NX_PTP_MSG_HDR_FLAG_LEAP61)
1511 {
1512 sync.nx_ptp_client_sync_flags |= NX_PTP_CLIENT_SYNC_LEAP61;
1513 }
1514 sync.nx_ptp_client_sync_utc_offset = NX_PTP_MSG_UTC_OFFSET(ptr);
1515
1516 /* parse announce message */
1517 _nx_ptp_msg_parse_announce(ptr, &master);
1518
1519 #ifdef NX_PTP_ENABLE_MASTER
1520 if (client_ptr -> nx_ptp_client_role == NX_PTP_CLIENT_ROLE_SLAVE_AND_MASTER)
1521 {
1522
1523 /* compare local clock with incoming master */
1524 compare_result = _nx_ptp_client_master_clock_compare(&client_ptr -> ptp_master, &master);
1525 if (compare_result == 0)
1526 {
1527
1528 /* error, ignore current announce message */
1529 return;
1530 }
1531 else if (compare_result > 0)
1532 {
1533
1534 /* recommend local clock to be master */
1535 if (client_ptr -> nx_ptp_client_state != NX_PTP_CLIENT_STATE_MASTER)
1536 {
1537
1538 /* set timeout for announce and sync */
1539 client_ptr -> ptp_master.nx_ptp_client_master_announce_timer = NX_PTP_CLIENT_ANNOUNCE_INTERVAL;
1540 client_ptr -> nx_ptp_client_sync_timer = NX_PTP_CLIENT_SYNC_INTERVAL;
1541 client_ptr -> nx_ptp_client_state = NX_PTP_CLIENT_STATE_MASTER;
1542 NX_PTP_DEBUG_PRINTF(("PTP: recommend local clock to be master\r\n"));
1543
1544 client_ptr -> nx_ptp_client_event_callback(client_ptr, NX_PTP_CLIENT_EVENT_MASTER,
1545 &client_ptr -> ptp_master,
1546 client_ptr -> nx_ptp_client_event_callback_data);
1547 }
1548 return;
1549 }
1550 else
1551 {
1552 /* recommend local clock to be slave */
1553 if (client_ptr -> nx_ptp_client_state == NX_PTP_CLIENT_STATE_MASTER)
1554 {
1555
1556 /* disable timers for announce and sync */
1557 client_ptr -> ptp_master.nx_ptp_client_master_announce_timer = -1;
1558 client_ptr -> nx_ptp_client_sync_timer = -1;
1559
1560 /* change the state to listening and then slave */
1561 client_ptr -> nx_ptp_client_state = NX_PTP_CLIENT_STATE_LISTENING;
1562 }
1563 }
1564 }
1565 #endif /* NX_PTP_ENABLE_MASTER */
1566
1567 /* check for new master */
1568 if (client_ptr -> nx_ptp_client_state == NX_PTP_CLIENT_STATE_LISTENING)
1569 {
1570
1571 /* first announce message, save master clock parameters */
1572 client_ptr -> nx_ptp_client_sync_flags = sync.nx_ptp_client_sync_flags;
1573 client_ptr -> nx_ptp_client_utc_offset = sync.nx_ptp_client_sync_utc_offset;
1574 memcpy(client_ptr -> nx_ptp_client_master_port_identity, hdr -> sourcePortIdentity,
1575 NX_PTP_CLOCK_PORT_IDENTITY_SIZE); /* use case of memcpy is verified. */
1576
1577 /* wait for Sync message */
1578 client_ptr -> nx_ptp_client_state = NX_PTP_CLIENT_STATE_SLAVE;
1579 client_ptr -> nx_ptp_client_delay_state = NX_PTP_CLIENT_DELAY_IDLE;
1580 #ifdef NX_ENABLE_GPTP
1581 client_ptr -> nx_ptp_client_pdelay_initiator_state = NX_PTP_CLIENT_PDELAY_IDLE;
1582 client_ptr -> nx_ptp_client_pdelay_responder_state = NX_PTP_CLIENT_PDELAY_WAIT_SYNC;
1583 #endif
1584 client_ptr -> nx_ptp_client_delay_req_timer = -1;
1585 client_ptr -> nx_ptp_client_delay_req_flag = 1;
1586
1587 if (hdr -> messageType == NX_PTP_MSG_TYPE_ANNOUNCE)
1588 {
1589 /* call application callback */
1590 if (client_ptr -> nx_ptp_client_event_callback)
1591 {
1592 master.nx_ptp_client_master_address = &(client_ptr -> nx_ptp_client_master_addr);
1593 master.nx_ptp_client_master_port_identity = hdr -> sourcePortIdentity;
1594 client_ptr -> nx_ptp_client_event_callback(client_ptr, NX_PTP_CLIENT_EVENT_MASTER, &master,
1595 client_ptr -> nx_ptp_client_event_callback_data);
1596 }
1597 }
1598
1599 /* Reset previous sync timestamp. */
1600 NX_PTP_TS_RESET(client_ptr -> nx_ptp_client_prev_sync);
1601 NX_PTP_TS_RESET(client_ptr -> nx_ptp_client_prev_sync_ts);
1602 NX_PTP_TS_RESET(client_ptr -> nx_ptp_client_sync);
1603 NX_PTP_TS_RESET(client_ptr -> nx_ptp_client_sync_ts);
1604 }
1605 else
1606 {
1607
1608 /* check for UTC offset update or flags changes */
1609 if (((client_ptr -> nx_ptp_client_sync_flags & ~NX_PTP_CLIENT_SYNC_CALIBRATED) !=
1610 sync.nx_ptp_client_sync_flags) ||
1611 (client_ptr -> nx_ptp_client_utc_offset != sync.nx_ptp_client_sync_utc_offset))
1612 {
1613 client_ptr -> nx_ptp_client_sync_flags =
1614 (USHORT)((client_ptr -> nx_ptp_client_sync_flags & NX_PTP_CLIENT_SYNC_CALIBRATED) |
1615 sync.nx_ptp_client_sync_flags);
1616 client_ptr -> nx_ptp_client_utc_offset = sync.nx_ptp_client_sync_utc_offset;
1617
1618 /* call application callback */
1619 if ((client_ptr -> nx_ptp_client_sync_flags & NX_PTP_CLIENT_SYNC_CALIBRATED) &&
1620 (client_ptr -> nx_ptp_client_event_callback))
1621 {
1622 client_ptr -> nx_ptp_client_event_callback(client_ptr, NX_PTP_CLIENT_EVENT_SYNC, &sync,
1623 client_ptr -> nx_ptp_client_event_callback_data);
1624 }
1625 }
1626 }
1627
1628 /* reset announce timer */
1629 client_ptr -> nx_ptp_client_announce_timeout = NX_PTP_CLIENT_ANNOUNCE_EXPIRATION;
1630 }
1631
1632 #ifdef NX_ENABLE_GPTP
1633 /**************************************************************************/
1634 /* */
1635 /* FUNCTION RELEASE */
1636 /* */
1637 /* _nx_ptp_client_send_pdelay_req PORTABLE C */
1638 /* 6.4.0 */
1639 /* AUTHOR */
1640 /* */
1641 /* Tiejun Zhou, Microsoft Corporation */
1642 /* */
1643 /* DESCRIPTION */
1644 /* */
1645 /* This function sends a PTP Pdelay Request message. */
1646 /* */
1647 /* INPUT */
1648 /* */
1649 /* client_ptr Pointer to PTP client */
1650 /* */
1651 /* OUTPUT */
1652 /* */
1653 /* None */
1654 /* */
1655 /* CALLS */
1656 /* */
1657 /* nx_packet_allocate Allocate a packet */
1658 /* nxd_udp_socket_source_send Send a UDP packet */
1659 /* nx_packet_release Release a packet */
1660 /* */
1661 /* CALLED BY */
1662 /* */
1663 /* _nx_ptp_client_thread_entry PTP thread entry */
1664 /* */
1665 /* RELEASE HISTORY */
1666 /* */
1667 /* DATE NAME DESCRIPTION */
1668 /* */
1669 /* 12-31-2023 Tiejun Zhou Initial Version 6.4.0 */
1670 /* */
1671 /**************************************************************************/
_nx_ptp_client_send_pdelay_req(NX_PTP_CLIENT * client_ptr)1672 static VOID _nx_ptp_client_send_pdelay_req(NX_PTP_CLIENT *client_ptr)
1673 {
1674 NX_PACKET *packet_ptr;
1675 UINT status = NX_NOT_SUCCESSFUL;
1676 UCHAR *ptr;
1677 #if NX_PTP_CLIENT_TRANSPORT_UDP
1678 NXD_ADDRESS addr;
1679 UINT addr_index = 0;
1680 #if defined(NX_ENABLE_IPV6_MULTICAST) && defined(FEATURE_NX_IPV6)
1681 NXD_IPV6_ADDRESS *ipv6_addr;
1682 NX_IP *ip_ptr;
1683 NX_INTERFACE *if_ptr;
1684 #endif
1685 #endif /* NX_PTP_CLIENT_TRANSPORT_UDP */
1686
1687 /* Allocate a packet from the pool */
1688 status = nx_packet_allocate(client_ptr -> nx_ptp_client_packet_pool_ptr, &packet_ptr, NX_PTP_PACKET, NX_NO_WAIT);
1689 if (status != NX_SUCCESS)
1690 {
1691 /* Failed to allocate the packet */
1692 return;
1693 }
1694
1695 /* Start of message */
1696 ptr = packet_ptr -> nx_packet_prepend_ptr;
1697
1698 #define PTP_MSG_PDELAY_REQ_TOTAL_LEN (NX_PTP_MSG_HDR_LEN + NX_PTP_MSG_TIMESTAMP_LEN + NX_PTP_MSG_PDELAY_RESERVED_LEN)
1699
1700 /* Write header IEEE Std 1588-2008 Section 13.3.1*/
1701 /* messageType */
1702 *ptr++ = (UCHAR)(client_ptr -> nx_ptp_client_transport_specific << 4) | NX_PTP_MSG_TYPE_PDELAY_REQ;
1703 /* versionPTP */
1704 *ptr++ = NX_PTP_VERSION;
1705 /* messageLength */
1706 *ptr++ = PTP_MSG_PDELAY_REQ_TOTAL_LEN >> 8;
1707 *ptr++ = (UCHAR)PTP_MSG_PDELAY_REQ_TOTAL_LEN;
1708 /* domainNumber */
1709 *ptr++ = client_ptr -> nx_ptp_client_domain;
1710
1711 /* reserved 1 octets */
1712 *ptr++ = 0;
1713
1714 /* flags 2 octets */
1715 *ptr++ = 0;
1716 *ptr++ = 0;
1717
1718 /* correction + reserved 8 + 4 */
1719 memset(ptr, 0, 12);
1720 ptr += 12;
1721
1722 /* sourcePortIdentity */
1723 memcpy(ptr, client_ptr -> nx_ptp_client_port_identity, NX_PTP_CLOCK_PORT_IDENTITY_SIZE); /* use case of memcpy is verified. */
1724 ptr += NX_PTP_CLOCK_PORT_IDENTITY_SIZE;
1725 /* sequenceID */
1726 client_ptr -> nx_ptp_client_pdelay_req_id++;
1727 *ptr++ = (UCHAR)(client_ptr -> nx_ptp_client_pdelay_req_id >> 8);
1728 *ptr++ = (UCHAR)(client_ptr -> nx_ptp_client_pdelay_req_id);
1729 /* control */
1730 *ptr++ = 5; /* other message */
1731 /* XXX */
1732 *ptr++ = 0;
1733
1734 /* write timestamp */
1735 memset(ptr, 0, NX_PTP_MSG_TIMESTAMP_LEN);
1736 ptr += NX_PTP_MSG_TIMESTAMP_LEN;
1737
1738 /* write space for reserved space to align size with pdelay_resp */
1739 memset(ptr, 0, NX_PTP_MSG_PDELAY_RESERVED_LEN);
1740 ptr += NX_PTP_MSG_PDELAY_RESERVED_LEN;
1741
1742 /* set final message length */
1743 packet_ptr -> nx_packet_length = (ULONG)(ptr - (packet_ptr -> nx_packet_prepend_ptr));
1744 packet_ptr -> nx_packet_append_ptr = ptr;
1745
1746 #if NX_PTP_CLIENT_TRANSPORT_UDP
1747 /* set source and destination addresses */
1748 #if defined(NX_ENABLE_IPV6_MULTICAST) && defined(FEATURE_NX_IPV6)
1749 if (client_ptr -> nx_ptp_client_master_addr.nxd_ip_version == NX_IP_VERSION_V6)
1750 {
1751 NX_PTP_IPV6_P2P_MULTICAST_ADDR_SET(&addr);
1752
1753 /* Use first IPv6 address as source address. */
1754 ip_ptr = client_ptr -> nx_ptp_client_ip_ptr;
1755 if_ptr = &ip_ptr -> nx_ip_interface[client_ptr -> nx_ptp_client_interface_index];
1756 ipv6_addr = if_ptr -> nxd_interface_ipv6_address_list_head;
1757 if (ipv6_addr == NX_NULL)
1758 {
1759
1760 /* No available IPv6 address. */
1761 /* Release packet. */
1762 nx_packet_release(packet_ptr);
1763
1764 /* Reset state. */
1765 client_ptr -> nx_ptp_client_pdelay_initiator_state = NX_PTP_CLIENT_PDELAY_IDLE;
1766 client_ptr -> nx_ptp_client_pdelay_req_packet_ptr = NX_NULL;
1767
1768 return;
1769 }
1770 addr_index = ipv6_addr -> nxd_ipv6_address_index;
1771 }
1772 else
1773 #endif
1774 {
1775 #ifndef NX_DISABLE_IPV4
1776 addr.nxd_ip_version = NX_IP_VERSION_V4;
1777 addr.nxd_ip_address.v4 = NX_PTP_IPV4_P2P_MULTICAST_ADDR;
1778 addr_index = client_ptr -> nx_ptp_client_interface_index;
1779 #endif
1780 }
1781 #endif /* NX_PTP_CLIENT_TRANSPORT_UDP */
1782
1783 /* Prepare timestamp for current packet */
1784 client_ptr -> nx_ptp_client_pdelay_initiator_state = NX_PTP_CLIENT_PDELAY_WAIT_REQ_TS;
1785 client_ptr -> nx_ptp_client_pdelay_req_packet_ptr = packet_ptr;
1786 client_ptr -> nx_ptp_client_clock_callback(client_ptr, NX_PTP_CLIENT_CLOCK_PACKET_TS_PREPARE,
1787 &client_ptr -> nx_ptp_client_pdelay_req_ts, packet_ptr,
1788 client_ptr -> nx_ptp_client_clock_callback_data);
1789
1790 /* Send Pdelay_Req */
1791 #if NX_PTP_CLIENT_TRANSPORT_UDP
1792 status = nxd_udp_socket_source_send((NX_UDP_SOCKET *)&client_ptr -> nx_ptp_client_event_socket,
1793 packet_ptr, &addr, NX_PTP_EVENT_UDP_PORT, addr_index);
1794 #endif /* NX_PTP_CLIENT_TRANSPORT_UDP */
1795 #if NX_PTP_CLIENT_TRANSPORT_ETHERNET
1796 nx_link_ethernet_packet_send(client_ptr -> nx_ptp_client_ip_ptr,
1797 client_ptr -> nx_ptp_client_interface_index, packet_ptr,
1798 NX_PTP_ETHERNET_P2P_MULTICAST_ADDR_MSB,
1799 NX_PTP_ETHERNET_P2P_MULTICAST_ADDR_LSB,
1800 NX_PTP_ETHERNET_TYPE);
1801 #endif /* NX_PTP_CLIENT_TRANSPORT_ETHERNET */
1802 if (status)
1803 {
1804
1805 /* release packet in case of error */
1806 nx_packet_release(packet_ptr);
1807
1808 /* reset state */
1809 client_ptr -> nx_ptp_client_pdelay_initiator_state = NX_PTP_CLIENT_PDELAY_IDLE;
1810 client_ptr -> nx_ptp_client_pdelay_req_packet_ptr = NX_NULL;
1811
1812 return;
1813 }
1814
1815 /* rearm delay req timer (use the client timer) */
1816 client_ptr -> nx_ptp_client_pdelay_req_timer = NX_PTP_CLIENT_PDELAY_REQ_INTERVAL;
1817 }
1818
1819
1820 /**************************************************************************/
1821 /* */
1822 /* FUNCTION RELEASE */
1823 /* */
1824 /* _nx_ptp_client_pdelay_resp_received PORTABLE C */
1825 /* 6.4.0 */
1826 /* AUTHOR */
1827 /* */
1828 /* Tiejun Zhou, Microsoft Corporation */
1829 /* */
1830 /* DESCRIPTION */
1831 /* */
1832 /* This function processes a received PTP Pdelay Response message. */
1833 /* */
1834 /* INPUT */
1835 /* */
1836 /* client_ptr Pointer to PTP client */
1837 /* ts_ptr Pointer to the timestamp */
1838 /* delivered by the Pdelay Resp */
1839 /* message */
1840 /* */
1841 /* OUTPUT */
1842 /* */
1843 /* None */
1844 /* */
1845 /* CALLS */
1846 /* */
1847 /* _nx_ptp_client_clock_adjust Adjust PTP clock */
1848 /* _nx_ptp_msg_parse_timestamp Parse timestamp field */
1849 /* _nx_ptp_client_utility_time_diff Diff two PTP times */
1850 /* _nx_ptp_client_utility_time_div_by_2 Divide a PTP time by 2 */
1851 /* */
1852 /* CALLED BY */
1853 /* */
1854 /* _nx_ptp_client_process_general_packet Process PTP general packet */
1855 /* _nx_ptp_client_process_event_packet Process PTP event packet */
1856 /* */
1857 /* RELEASE HISTORY */
1858 /* */
1859 /* DATE NAME DESCRIPTION */
1860 /* */
1861 /* 12-31-2023 Tiejun Zhou Initial Version 6.4.0 */
1862 /* */
1863 /**************************************************************************/
_nx_ptp_client_pdelay_resp_received(NX_PTP_CLIENT * client_ptr,VOID * ts_ptr)1864 static VOID _nx_ptp_client_pdelay_resp_received(NX_PTP_CLIENT *client_ptr, VOID *ts_ptr)
1865 {
1866 NX_PTP_TIME a, b, c, d, t3;
1867
1868 /*
1869 * The following timestamps are used to calculate the mean link delay using P2P
1870 * t1 = nx_ptp_client_pdelay_req_ts
1871 * t2 = nx_ptp_client_pdelay_req_receipt_ts (within pdelay_resp)
1872 * t3 = nx_ptp_client_pdelay_resp_origin_ts (within pdelay_resp_follow_up or ts_ptr)
1873 * t4 = (onestep: nx_ptp_client_pdelay_req_receipt_ts)/(twostep:nx_ptp_client_pdelay_resp_ts)
1874 *
1875 * C = t2 - t1
1876 * D = t4 - t3
1877 *
1878 * <meanLinkDelay> = [(t2 – t1) + (t4 – t3)]/2
1879 *
1880 * A = t1 - t2
1881 * B = t3 - t4
1882 *
1883 * offset = [(t1 - t2) - (t3 - t4)]/2
1884 * = [B - A]/2
1885 *
1886 *
1887 * onestep: <meanLinkDelay> = [(t4 − t1) − <correctedPdelayRespCorrectionField>]/2
1888 * correctedPDelayRespCorrectionField = t3-t2 (turnaround time)
1889 *
1890 * onestep offset = (t4 + t1 - (nx_ptp_client_pdelay_req_receipt_ts * 2))/2
1891 * - the multiply by 2 is here because we are not yet parsing the correction field
1892 *
1893 * twostep offset = (t4 + t1 - (nx_ptp_client_pdelay_req_receipt_ts + ts_ptr))/2
1894 *
1895 * We will set <delayAsymmetry> to 0 unless a value is provided by the user
1896 *
1897 * delay_asymmetry = 0;
1898 * corrected_pdelay_resp = ingress <delayAsymmetry> + pdelay_resp_correction_field
1899 * corrected_pdelay_resp = delay_asymmetry + pdelay_resp_correction_field
1900 */
1901
1902 /* get message timestamp */
1903 _nx_ptp_msg_parse_timestamp(ts_ptr, &t3);
1904
1905 /* compute A = t1 - t2 */
1906 _nx_ptp_client_utility_time_diff(&client_ptr -> nx_ptp_client_pdelay_req_ts, &client_ptr -> nx_ptp_client_pdelay_req_receipt_ts, &a);
1907
1908 /* compute B = t3 - t4 */
1909 _nx_ptp_client_utility_time_diff(&t3, &client_ptr -> nx_ptp_client_pdelay_resp_ts, &b);
1910
1911 /* compute C = t2 - t1 */
1912 _nx_ptp_client_utility_time_diff(&client_ptr -> nx_ptp_client_pdelay_req_receipt_ts, &client_ptr -> nx_ptp_client_pdelay_req_ts, &c);
1913
1914 /* compute D = t4 - t3 */
1915 _nx_ptp_client_utility_time_diff(&client_ptr -> nx_ptp_client_pdelay_resp_ts, &t3, &d);
1916
1917 /* compute delay = (D + C) / 2 */
1918 _nx_ptp_client_utility_time_sum(&d, &c, &client_ptr -> nx_ptp_client_delay);
1919 _nx_ptp_client_utility_time_div_by_2(&client_ptr -> nx_ptp_client_delay);
1920
1921 #if defined(NX_PTP_DEBUG) || defined(NX_PTP_DEBUG_DELAY)
1922 if ((client_ptr -> nx_ptp_client_delay.second_low == 0) && (client_ptr -> nx_ptp_client_delay.second_high == 0))
1923 {
1924 if ((client_ptr -> nx_ptp_client_delay.nanosecond > -1000) &&
1925 (client_ptr -> nx_ptp_client_delay.nanosecond < 1000))
1926 {
1927 NX_PTP_DEBUG_PRINTF(("PTP: delay = %ld ns", client_ptr -> nx_ptp_client_delay.nanosecond));
1928 }
1929 else if ((client_ptr -> nx_ptp_client_delay.nanosecond > -1000000) &&
1930 (client_ptr -> nx_ptp_client_delay.nanosecond < 1000000))
1931 {
1932 NX_PTP_DEBUG_PRINTF(("PTP: delay = %ld us", client_ptr -> nx_ptp_client_delay.nanosecond / 1000));
1933 }
1934 else
1935 {
1936 NX_PTP_DEBUG_PRINTF(("PTP: delay = %ld ms", client_ptr -> nx_ptp_client_delay.nanosecond / 1000000));
1937 }
1938 }
1939 else
1940 {
1941 NX_PTP_DEBUG_PRINTF(("PTP: delay > 1s"));
1942 }
1943
1944 if (client_ptr -> nx_ptp_client_delay.nanosecond > NX_PTP_CLIENT_DELAY_THRESH)
1945 {
1946 NX_PTP_DEBUG_PRINTF((", asCapable is FALSE\n"));
1947 }
1948 else
1949 {
1950 NX_PTP_DEBUG_PRINTF((", asCapable is TRUE\n"));
1951 }
1952 #endif
1953
1954 /* update pdelay req state */
1955 client_ptr -> nx_ptp_client_pdelay_initiator_state = NX_PTP_CLIENT_PDELAY_IDLE;
1956 }
1957
1958
1959 /**************************************************************************/
1960 /* */
1961 /* FUNCTION RELEASE */
1962 /* */
1963 /* _nx_ptp_client_send_pdelay_resp_follow_up PORTABLE C */
1964 /* 6.4.0 */
1965 /* AUTHOR */
1966 /* */
1967 /* Tiejun Zhou, Microsoft Corporation */
1968 /* */
1969 /* DESCRIPTION */
1970 /* */
1971 /* This function sends a PTP Pdelay response follow up message. */
1972 /* */
1973 /* INPUT */
1974 /* */
1975 /* client_ptr Pointer to PTP client */
1976 /* */
1977 /* OUTPUT */
1978 /* */
1979 /* None */
1980 /* */
1981 /* CALLS */
1982 /* */
1983 /* nx_packet_allocate Allocate a packet */
1984 /* nxd_udp_socket_source_send Send a UDP packet */
1985 /* nx_packet_release Release a packet */
1986 /* */
1987 /* CALLED BY */
1988 /* */
1989 /* _nx_ptp_client_thread_entry PTP thread entry */
1990 /* */
1991 /* RELEASE HISTORY */
1992 /* */
1993 /* DATE NAME DESCRIPTION */
1994 /* */
1995 /* 12-31-2023 Tiejun Zhou Initial Version 6.4.0 */
1996 /* */
1997 /**************************************************************************/
_nx_ptp_client_send_pdelay_resp_follow_up(NX_PTP_CLIENT * client_ptr)1998 static VOID _nx_ptp_client_send_pdelay_resp_follow_up(NX_PTP_CLIENT *client_ptr)
1999 {
2000 NX_PACKET *packet_ptr;
2001 UINT status = NX_NOT_SUCCESSFUL;
2002 UCHAR *ptr;
2003 #if NX_PTP_CLIENT_TRANSPORT_UDP
2004 NXD_ADDRESS addr;
2005 UINT addr_index = 0;
2006 #if defined(NX_ENABLE_IPV6_MULTICAST) && defined(FEATURE_NX_IPV6)
2007 NXD_IPV6_ADDRESS *ipv6_addr;
2008 NX_IP *ip_ptr;
2009 NX_INTERFACE *if_ptr;
2010 #endif
2011 #endif /* NX_PTP_CLIENT_TRANSPORT_UDP */
2012
2013 /* Verify state */
2014 if (client_ptr -> nx_ptp_client_pdelay_responder_state != NX_PTP_CLIENT_PDELAY_SEND_FOLLOW_UP)
2015 {
2016 return;
2017 }
2018
2019 /* Allocate a packet from the pool */
2020 status = nx_packet_allocate(client_ptr -> nx_ptp_client_packet_pool_ptr, &packet_ptr, NX_PTP_PACKET, NX_NO_WAIT);
2021 if (status != NX_SUCCESS)
2022 {
2023 /* Failed to allocate the packet */
2024 return;
2025 }
2026
2027 /* Start of message */
2028 ptr = packet_ptr -> nx_packet_prepend_ptr;
2029
2030 #define PTP_MSG_PDELAY_RESP_TOTAL_LEN (NX_PTP_MSG_HDR_LEN + NX_PTP_MSG_TIMESTAMP_LEN + NX_PTP_MSG_PDELAY_RESERVED_LEN)
2031
2032 /* Write header IEEE Std 1588-2008 Section 13.3.1*/
2033 /* messageType */
2034 *ptr++ = (UCHAR)(client_ptr -> nx_ptp_client_transport_specific << 4) | NX_PTP_MSG_TYPE_PDELAY_RESP_FOLLOW_UP;
2035 /* versionPTP */
2036 *ptr++ = NX_PTP_VERSION;
2037 /* messageLength */
2038 *ptr++ = PTP_MSG_PDELAY_RESP_TOTAL_LEN >> 8;
2039 *ptr++ = (UCHAR)PTP_MSG_PDELAY_RESP_TOTAL_LEN;
2040 /* domainNumber */
2041 *ptr++ = client_ptr -> nx_ptp_client_domain;
2042 /* reserved 1 octets */
2043 *ptr++ = 0;
2044 /* flags 2 octets */
2045 *ptr++ = 0;
2046 *ptr++ = 0;
2047 /* correction + reserved 8 + 4 (correction field to be updated with t3-t2 later) */
2048 memset(ptr, 0, 12);
2049 ptr += 12;
2050 /* sourcePortIdentity */
2051 memcpy(ptr, client_ptr -> nx_ptp_client_port_identity, NX_PTP_CLOCK_PORT_IDENTITY_SIZE); /* use case of memcpy is verified. */
2052 ptr += NX_PTP_CLOCK_PORT_IDENTITY_SIZE;
2053 /* sequenceID */
2054 *ptr++ = (UCHAR)(client_ptr -> nx_ptp_client_pdelay_responder_id >> 8);
2055 *ptr++ = (UCHAR)(client_ptr -> nx_ptp_client_pdelay_responder_id);
2056 /* control */
2057 *ptr++ = 5; /* other message */
2058 /* XXX */
2059 *ptr++ = 0;
2060
2061 /* write timestamp t3 */
2062 *ptr++ = (UCHAR)((client_ptr -> nx_ptp_client_pdelay_resp_origin).second_high >> 8);
2063 *ptr++ = (UCHAR)((client_ptr -> nx_ptp_client_pdelay_resp_origin).second_high);
2064 _nx_ptp_utility_32_unsigned_write(ptr, (client_ptr -> nx_ptp_client_pdelay_resp_origin).second_low);
2065 ptr += 4;
2066 _nx_ptp_utility_32_unsigned_write(ptr, (ULONG)(client_ptr -> nx_ptp_client_pdelay_resp_origin.nanosecond));
2067 ptr += 4;
2068
2069 /* write requestingPortIdentity */
2070 memcpy(ptr, client_ptr -> nx_ptp_client_request_port_identity, NX_PTP_CLOCK_PORT_IDENTITY_SIZE); /* use case of memcpy is verified. */
2071 ptr += NX_PTP_CLOCK_PORT_IDENTITY_SIZE;
2072
2073 /* set final message length */
2074 packet_ptr -> nx_packet_length = (ULONG)(ptr - (packet_ptr -> nx_packet_prepend_ptr));
2075 packet_ptr -> nx_packet_append_ptr = ptr;
2076
2077 #if NX_PTP_CLIENT_TRANSPORT_UDP
2078 /* set source and destination addresses */
2079 #if defined(NX_ENABLE_IPV6_MULTICAST) && defined(FEATURE_NX_IPV6)
2080 if (client_ptr -> nx_ptp_client_master_addr.nxd_ip_version == NX_IP_VERSION_V6)
2081 {
2082 NX_PTP_IPV6_P2P_MULTICAST_ADDR_SET(&addr);
2083
2084 /* Use first IPv6 address as source address. */
2085 ip_ptr = client_ptr -> nx_ptp_client_ip_ptr;
2086 if_ptr = &ip_ptr -> nx_ip_interface[client_ptr -> nx_ptp_client_interface_index];
2087 ipv6_addr = if_ptr -> nxd_interface_ipv6_address_list_head;
2088 if (ipv6_addr == NX_NULL)
2089 {
2090
2091 /* No available IPv6 address. */
2092 /* Release packet. */
2093 nx_packet_release(packet_ptr);
2094
2095 /* Reset state. */
2096 client_ptr -> nx_ptp_client_pdelay_responder_state = NX_PTP_CLIENT_PDELAY_WAIT_REQ;
2097 client_ptr -> nx_ptp_client_pdelay_req_packet_ptr = NX_NULL;
2098
2099 return;
2100 }
2101 addr_index = ipv6_addr -> nxd_ipv6_address_index;
2102 }
2103 else
2104 #endif
2105 {
2106 #ifndef NX_DISABLE_IPV4
2107 addr.nxd_ip_version = NX_IP_VERSION_V4;
2108 addr.nxd_ip_address.v4 = NX_PTP_IPV4_P2P_MULTICAST_ADDR;
2109 addr_index = client_ptr -> nx_ptp_client_interface_index;
2110 #endif
2111 }
2112
2113 /* Send Pdelay_Resp */
2114 status = nxd_udp_socket_source_send((NX_UDP_SOCKET *)&client_ptr -> nx_ptp_client_general_socket,
2115 packet_ptr, &addr, NX_PTP_GENERAL_UDP_PORT, addr_index);
2116 #endif /* NX_PTP_CLIENT_TRANSPORT_UDP */
2117 #if NX_PTP_CLIENT_TRANSPORT_ETHERNET
2118 nx_link_ethernet_packet_send(client_ptr -> nx_ptp_client_ip_ptr,
2119 client_ptr -> nx_ptp_client_interface_index, packet_ptr,
2120 NX_PTP_ETHERNET_P2P_MULTICAST_ADDR_MSB,
2121 NX_PTP_ETHERNET_P2P_MULTICAST_ADDR_LSB,
2122 NX_PTP_ETHERNET_TYPE);
2123 #endif /* NX_PTP_CLIENT_TRANSPORT_ETHERNET */
2124 if (status)
2125 {
2126 /* release packet in case of error */
2127 nx_packet_release(packet_ptr);
2128
2129 /* reset state */
2130 client_ptr -> nx_ptp_client_pdelay_responder_state = NX_PTP_CLIENT_PDELAY_WAIT_REQ;
2131 client_ptr -> nx_ptp_client_pdelay_req_packet_ptr = NX_NULL;
2132
2133 return;
2134 }
2135
2136 client_ptr -> nx_ptp_client_pdelay_responder_state = NX_PTP_CLIENT_PDELAY_WAIT_REQ;
2137 }
2138
2139
2140 /**************************************************************************/
2141 /* */
2142 /* FUNCTION RELEASE */
2143 /* */
2144 /* _nx_ptp_client_send_pdelay_resp PORTABLE C */
2145 /* 6.4.0 */
2146 /* AUTHOR */
2147 /* */
2148 /* Tiejun Zhou, Microsoft Corporation */
2149 /* */
2150 /* DESCRIPTION */
2151 /* */
2152 /* This function sends a PTP Pdelay response message. */
2153 /* */
2154 /* INPUT */
2155 /* */
2156 /* client_ptr Pointer to PTP client */
2157 /* */
2158 /* OUTPUT */
2159 /* */
2160 /* None */
2161 /* */
2162 /* CALLS */
2163 /* */
2164 /* nx_packet_allocate Allocate a packet */
2165 /* nxd_udp_socket_source_send Send a UDP packet */
2166 /* nx_packet_release Release a packet */
2167 /* */
2168 /* CALLED BY */
2169 /* */
2170 /* _nx_ptp_client_thread_entry PTP thread entry */
2171 /* _nx_ptp_client_process_event_packet Process PTP event packet */
2172 /* */
2173 /* RELEASE HISTORY */
2174 /* */
2175 /* DATE NAME DESCRIPTION */
2176 /* */
2177 /* 12-31-2023 Tiejun Zhou Initial Version 6.4.0 */
2178 /* */
2179 /**************************************************************************/
_nx_ptp_client_send_pdelay_resp(NX_PTP_CLIENT * client_ptr)2180 static VOID _nx_ptp_client_send_pdelay_resp(NX_PTP_CLIENT *client_ptr)
2181 {
2182 NX_PACKET *packet_ptr;
2183 UINT status = NX_NOT_SUCCESSFUL;
2184 UCHAR *ptr;
2185 #if NX_PTP_CLIENT_TRANSPORT_UDP
2186 NXD_ADDRESS addr;
2187 UINT addr_index = 0;
2188 #if defined(NX_ENABLE_IPV6_MULTICAST) && defined(FEATURE_NX_IPV6)
2189 NXD_IPV6_ADDRESS *ipv6_addr;
2190 NX_IP *ip_ptr;
2191 NX_INTERFACE *if_ptr;
2192 #endif
2193 #endif /* NX_PTP_CLIENT_TRANSPORT_UDP */
2194
2195 /* Verify state */
2196 if (client_ptr -> nx_ptp_client_pdelay_responder_state != NX_PTP_CLIENT_PDELAY_SEND_RESP_TWOSTEP)
2197 {
2198 return;
2199 }
2200
2201 /* Allocate a packet from the pool */
2202 status = nx_packet_allocate(client_ptr -> nx_ptp_client_packet_pool_ptr, &packet_ptr, NX_PTP_PACKET, NX_NO_WAIT);
2203 if (status != NX_SUCCESS)
2204 {
2205 /* Failed to allocate the packet */
2206 return;
2207 }
2208
2209 /* Start of message */
2210 ptr = packet_ptr -> nx_packet_prepend_ptr;
2211
2212 #define PTP_MSG_PDELAY_RESP_TOTAL_LEN (NX_PTP_MSG_HDR_LEN + NX_PTP_MSG_TIMESTAMP_LEN + NX_PTP_MSG_PDELAY_RESERVED_LEN)
2213
2214 /* Write header IEEE Std 1588-2008 Section 13.3.1*/
2215 /* messageType */
2216 *ptr++ = (UCHAR)(client_ptr -> nx_ptp_client_transport_specific << 4) | NX_PTP_MSG_TYPE_PDELAY_RESP;
2217 /* versionPTP */
2218 *ptr++ = NX_PTP_VERSION;
2219 /* messageLength */
2220 *ptr++ = PTP_MSG_PDELAY_REQ_TOTAL_LEN >> 8;
2221 *ptr++ = (UCHAR)PTP_MSG_PDELAY_REQ_TOTAL_LEN;
2222 /* domainNumber */
2223 *ptr++ = client_ptr -> nx_ptp_client_domain;
2224 /* reserved 1 octets */
2225 *ptr++ = 0;
2226 /* flags 2 octets */
2227 *ptr++ = 0x02;
2228 *ptr++ = 0x8;
2229 /* correction + reserved 8 + 4 */
2230 memset(ptr, 0, 12);
2231 ptr += 12;
2232 /* sourcePortIdentity */
2233 memcpy(ptr, client_ptr -> nx_ptp_client_port_identity, NX_PTP_CLOCK_PORT_IDENTITY_SIZE); /* use case of memcpy is verified. */
2234 ptr += NX_PTP_CLOCK_PORT_IDENTITY_SIZE;
2235 /* sequenceID */
2236 *ptr++ = (UCHAR)(client_ptr -> nx_ptp_client_pdelay_responder_id >> 8);
2237 *ptr++ = (UCHAR)(client_ptr -> nx_ptp_client_pdelay_responder_id);
2238 /* control */
2239 *ptr++ = 5; /* other message */
2240 /* XXX */
2241 *ptr++ = 0;
2242
2243 /* write timestamp t2 */
2244 *ptr++ = (UCHAR)((client_ptr -> nx_ptp_client_pdelay_req_receipt).second_high >> 8);
2245 *ptr++ = (UCHAR)((client_ptr -> nx_ptp_client_pdelay_req_receipt).second_high);
2246 /* 4 octets for second low */
2247 _nx_ptp_utility_32_unsigned_write(ptr, (client_ptr -> nx_ptp_client_pdelay_req_receipt).second_low);
2248 ptr += 4;
2249 /* 4 for nanosecond */
2250 _nx_ptp_utility_32_unsigned_write(ptr, (ULONG)(client_ptr -> nx_ptp_client_pdelay_req_receipt.nanosecond));
2251 ptr += 4;
2252
2253 /* write requestingPortIdentity */
2254 memcpy(ptr, client_ptr -> nx_ptp_client_request_port_identity, NX_PTP_CLOCK_PORT_IDENTITY_SIZE); /* use case of memcpy is verified. */
2255 ptr += NX_PTP_CLOCK_PORT_IDENTITY_SIZE;
2256
2257 /* set final message length */
2258 packet_ptr -> nx_packet_length = (ULONG)(ptr - (packet_ptr -> nx_packet_prepend_ptr));
2259 packet_ptr -> nx_packet_append_ptr = ptr;
2260
2261 #if NX_PTP_CLIENT_TRANSPORT_UDP
2262 /* set source and destination addresses */
2263 #if defined(NX_ENABLE_IPV6_MULTICAST) && defined(FEATURE_NX_IPV6)
2264 if (client_ptr -> nx_ptp_client_master_addr.nxd_ip_version == NX_IP_VERSION_V6)
2265 {
2266 NX_PTP_IPV6_P2P_MULTICAST_ADDR_SET(&addr);
2267
2268 /* Use first IPv6 address as source address. */
2269 ip_ptr = client_ptr -> nx_ptp_client_ip_ptr;
2270 if_ptr = &ip_ptr -> nx_ip_interface[client_ptr -> nx_ptp_client_interface_index];
2271 ipv6_addr = if_ptr -> nxd_interface_ipv6_address_list_head;
2272 if (ipv6_addr == NX_NULL)
2273 {
2274
2275 /* No available IPv6 address. */
2276 /* Release packet. */
2277 nx_packet_release(packet_ptr);
2278
2279 /* Reset state. */
2280 client_ptr -> nx_ptp_client_pdelay_responder_state = NX_PTP_CLIENT_PDELAY_WAIT_REQ;
2281 client_ptr -> nx_ptp_client_pdelay_req_packet_ptr = NX_NULL;
2282
2283 return;
2284 }
2285 addr_index = ipv6_addr -> nxd_ipv6_address_index;
2286 }
2287 else
2288 #endif
2289 {
2290 #ifndef NX_DISABLE_IPV4
2291 addr.nxd_ip_version = NX_IP_VERSION_V4;
2292 addr.nxd_ip_address.v4 = NX_PTP_IPV4_P2P_MULTICAST_ADDR;
2293 addr_index = client_ptr -> nx_ptp_client_interface_index;
2294 #endif
2295 }
2296 #endif /* NX_PTP_CLIENT_TRANSPORT_UDP */
2297
2298 client_ptr -> nx_ptp_client_pdelay_resp_packet_ptr = packet_ptr;
2299
2300 /* Prepare timestamp for current packet (generate t3) */
2301 client_ptr -> nx_ptp_client_clock_callback(client_ptr, NX_PTP_CLIENT_CLOCK_PACKET_TS_PREPARE,
2302 &client_ptr -> nx_ptp_client_pdelay_resp_origin, packet_ptr,
2303 client_ptr -> nx_ptp_client_clock_callback_data);
2304
2305
2306 #if NX_PTP_CLIENT_TRANSPORT_UDP
2307 /* Send Pdelay_Resp */
2308 status = nxd_udp_socket_source_send((NX_UDP_SOCKET *)&client_ptr -> nx_ptp_client_general_socket,
2309 packet_ptr, &addr, NX_PTP_GENERAL_UDP_PORT, addr_index);
2310 #endif /* NX_PTP_CLIENT_TRANSPORT_UDP */
2311 #if NX_PTP_CLIENT_TRANSPORT_ETHERNET
2312 nx_link_ethernet_packet_send(client_ptr -> nx_ptp_client_ip_ptr,
2313 client_ptr -> nx_ptp_client_interface_index, packet_ptr,
2314 NX_PTP_ETHERNET_P2P_MULTICAST_ADDR_MSB,
2315 NX_PTP_ETHERNET_P2P_MULTICAST_ADDR_LSB,
2316 NX_PTP_ETHERNET_TYPE);
2317 #endif /* NX_PTP_CLIENT_TRANSPORT_ETHERNET */
2318 if (status)
2319 {
2320 /* release packet in case of error */
2321 nx_packet_release(packet_ptr);
2322
2323 /* reset state */
2324 client_ptr -> nx_ptp_client_pdelay_responder_state = NX_PTP_CLIENT_PDELAY_WAIT_REQ;
2325 client_ptr -> nx_ptp_client_pdelay_req_packet_ptr = NX_NULL;
2326
2327 return;
2328 }
2329 }
2330 #endif /* NX_ENABLE_GPTP*/
2331
2332
2333 #if defined(NX_PTP_ENABLE_MASTER) || defined(NX_PTP_ENABLE_REVERSE_SYNC)
2334 /**************************************************************************/
2335 /* */
2336 /* FUNCTION RELEASE */
2337 /* */
2338 /* _nx_ptp_client_send_follow_up PORTABLE C */
2339 /* 6.4.0 */
2340 /* AUTHOR */
2341 /* */
2342 /* Tiejun Zhou, Microsoft Corporation */
2343 /* */
2344 /* DESCRIPTION */
2345 /* */
2346 /* This function sends a PTP follow up message. */
2347 /* */
2348 /* INPUT */
2349 /* */
2350 /* client_ptr Pointer to PTP client */
2351 /* */
2352 /* OUTPUT */
2353 /* */
2354 /* None */
2355 /* */
2356 /* CALLS */
2357 /* */
2358 /* nx_packet_allocate Allocate a packet */
2359 /* nxd_udp_socket_source_send Send a UDP packet */
2360 /* nx_packet_release Release a packet */
2361 /* */
2362 /* CALLED BY */
2363 /* */
2364 /* _nx_ptp_client_thread_entry PTP thread entry */
2365 /* */
2366 /* RELEASE HISTORY */
2367 /* */
2368 /* DATE NAME DESCRIPTION */
2369 /* */
2370 /* 12-31-2023 Tiejun Zhou Initial Version 6.4.0 */
2371 /* */
2372 /**************************************************************************/
_nx_ptp_client_send_follow_up(NX_PTP_CLIENT * client_ptr)2373 static VOID _nx_ptp_client_send_follow_up(NX_PTP_CLIENT *client_ptr)
2374 {
2375 NX_PACKET *packet_ptr;
2376 UINT status = NX_NOT_SUCCESSFUL;
2377 UCHAR *ptr;
2378 #if NX_PTP_CLIENT_TRANSPORT_UDP
2379 NXD_ADDRESS addr;
2380 UINT addr_index = 0;
2381 #if defined(NX_ENABLE_IPV6_MULTICAST) && defined(FEATURE_NX_IPV6)
2382 NXD_IPV6_ADDRESS *ipv6_addr;
2383 NX_IP *ip_ptr;
2384 NX_INTERFACE *if_ptr;
2385 #endif
2386 #endif /* NX_PTP_CLIENT_TRANSPORT_UDP */
2387
2388 /* allocate a packet from the pool */
2389 status = nx_packet_allocate(client_ptr -> nx_ptp_client_packet_pool_ptr, &packet_ptr, NX_PTP_PACKET, NX_NO_WAIT);
2390 if (status != NX_SUCCESS)
2391 {
2392 /* Failed to allocate the packet */
2393 return;
2394 }
2395
2396 /* start of message */
2397 ptr = packet_ptr -> nx_packet_prepend_ptr;
2398
2399 #define PTP_FOLLOW_UP_TLV_LENGTH 32
2400 #define PTP_MSG_FOLLOW_UP_TOTAL_LEN (NX_PTP_MSG_HDR_LEN + NX_PTP_MSG_TIMESTAMP_LEN + PTP_FOLLOW_UP_TLV_LENGTH)
2401
2402 /* write header */
2403 /* messageType */
2404 *ptr++ = (UCHAR)(client_ptr -> nx_ptp_client_transport_specific << 4) | NX_PTP_MSG_TYPE_FOLLOW_UP;
2405 /* versionPTP */
2406 *ptr++ = NX_PTP_VERSION;
2407 /* messageLength */
2408 *ptr++ = PTP_MSG_FOLLOW_UP_TOTAL_LEN >> 8;
2409 *ptr++ = (UCHAR)PTP_MSG_FOLLOW_UP_TOTAL_LEN;
2410 /* domainNumber */
2411 *ptr++ = client_ptr -> nx_ptp_client_domain;
2412 /* reserved 1 octets */
2413 *ptr++ = 0;
2414 /* flags 2 octets */
2415 *ptr++ = 0;
2416 *ptr++ = 0x08;
2417 /* correction + reserved 8 + 4 */
2418 memset(ptr, 0, 12);
2419 ptr += 12;
2420 /* sourcePortIdentity */
2421 memcpy(ptr, client_ptr -> nx_ptp_client_port_identity, NX_PTP_CLOCK_PORT_IDENTITY_SIZE); /* use case of memcpy is verified. */
2422 ptr += NX_PTP_CLOCK_PORT_IDENTITY_SIZE;
2423 /* sequenceID */
2424 *ptr++ = (UCHAR)(client_ptr -> nx_ptp_client_sync_sequenceId >> 8);
2425 *ptr++ = (UCHAR)(client_ptr -> nx_ptp_client_sync_sequenceId);
2426 /* control */
2427 *ptr++ = 2; /* follow up message */
2428 /* XXX */
2429 *ptr++ = 0;
2430
2431 /* write preciseOriginTimestamp */
2432 *ptr++ = (UCHAR)((client_ptr -> nx_ptp_client_sync_ts_local).second_high >> 8);
2433 *ptr++ = (UCHAR)((client_ptr -> nx_ptp_client_sync_ts_local).second_high);
2434 /* 4 octets for second low */
2435 _nx_ptp_utility_32_unsigned_write(ptr, (client_ptr -> nx_ptp_client_sync_ts_local).second_low);
2436 ptr += 4;
2437 /* 4 for nanosecond */
2438 _nx_ptp_utility_32_unsigned_write(ptr, (ULONG)(client_ptr -> nx_ptp_client_sync_ts_local.nanosecond));
2439 ptr += 4;
2440
2441 /* Follow_Up information TLV definition 801AS-2020 11.4.4.3. Required by 801AS-2020 Section 7.5 g) */
2442 /* tlvType */
2443 *ptr++ = 0;
2444 *ptr++ = 0x3;
2445 /* lengthField */
2446 *ptr++ = 0;
2447 *ptr++ = 28;
2448 /* organizationId(3): 00-80-C2 from 801AS-2020 11.4.4.3.4 */
2449 *ptr++ = 0x0;
2450 *ptr++ = 0x80;
2451 *ptr++ = 0xC2;
2452 /* organizationSubType(3): 1 */
2453 *ptr++ = 0x0;
2454 *ptr++ = 0x0;
2455 *ptr++ = 0x1;
2456 /* cumulativeScaledRateOffset(4) */
2457 /* gmTimeBaseIndicator(2) */
2458 /* lastGmPhaseChange(12) */
2459 /* scaledLastGmFreqChange(4) */
2460 #define PTP_FOLLOW_UP_TLV_ZEROES 4 + 2 + 12 + 4
2461 memset(ptr, 0, PTP_FOLLOW_UP_TLV_ZEROES);
2462 ptr += PTP_FOLLOW_UP_TLV_ZEROES;
2463
2464 /* set final length of message */
2465 packet_ptr -> nx_packet_length = (ULONG)(ptr - packet_ptr -> nx_packet_prepend_ptr);
2466 packet_ptr -> nx_packet_append_ptr = ptr;
2467
2468 #if NX_PTP_CLIENT_TRANSPORT_UDP
2469 /* set source and destination addresses */
2470 #if defined(NX_ENABLE_IPV6_MULTICAST) && defined(FEATURE_NX_IPV6)
2471 if (client_ptr -> nx_ptp_client_master_addr.nxd_ip_version == NX_IP_VERSION_V6)
2472 {
2473 NX_PTP_IPV6_MULTICAST_ADDR_SET(&addr);
2474
2475 /* Use first IPv6 address as source address. */
2476 ip_ptr = client_ptr -> nx_ptp_client_ip_ptr;
2477 if_ptr = &ip_ptr -> nx_ip_interface[client_ptr -> nx_ptp_client_interface_index];
2478 ipv6_addr = if_ptr -> nxd_interface_ipv6_address_list_head;
2479 if (ipv6_addr == NX_NULL)
2480 {
2481
2482 /* No available IPv6 address. */
2483 /* Release packet. */
2484 nx_packet_release(packet_ptr);
2485
2486 /* Reset state. */
2487 client_ptr -> nx_ptp_client_sync_timer = NX_PTP_CLIENT_SYNC_INTERVAL;
2488
2489 return;
2490 }
2491 addr_index = ipv6_addr -> nxd_ipv6_address_index;
2492 }
2493 else
2494 #endif
2495 {
2496 #ifndef NX_DISABLE_IPV4
2497 addr.nxd_ip_version = NX_IP_VERSION_V4;
2498 addr.nxd_ip_address.v4 = NX_PTP_IPV4_MULTICAST_ADDR;
2499 addr_index = client_ptr -> nx_ptp_client_interface_index;
2500 #endif
2501 }
2502 #endif /* NX_PTP_CLIENT_TRANSPORT_UDP */
2503
2504 #if NX_PTP_CLIENT_TRANSPORT_UDP
2505 /* Send Pdelay_Resp */
2506 status = nxd_udp_socket_source_send((NX_UDP_SOCKET *)&client_ptr -> nx_ptp_client_general_socket,
2507 packet_ptr, &addr, NX_PTP_GENERAL_UDP_PORT, addr_index);
2508 #endif /* NX_PTP_CLIENT_TRANSPORT_UDP */
2509 #if NX_PTP_CLIENT_TRANSPORT_ETHERNET
2510 nx_link_ethernet_packet_send(client_ptr -> nx_ptp_client_ip_ptr,
2511 client_ptr -> nx_ptp_client_interface_index, packet_ptr,
2512 NX_PTP_ETHERNET_P2P_MULTICAST_ADDR_MSB,
2513 NX_PTP_ETHERNET_P2P_MULTICAST_ADDR_LSB,
2514 NX_PTP_ETHERNET_TYPE);
2515 #endif /* NX_PTP_CLIENT_TRANSPORT_ETHERNET */
2516
2517 if (status)
2518 {
2519
2520 /* release packet in case of error */
2521 nx_packet_release(packet_ptr);
2522 }
2523 }
2524
2525
2526 /**************************************************************************/
2527 /* */
2528 /* FUNCTION RELEASE */
2529 /* */
2530 /* _nx_ptp_client_send_sync PORTABLE C */
2531 /* 6.4.0 */
2532 /* AUTHOR */
2533 /* */
2534 /* Tiejun Zhou, Microsoft Corporation */
2535 /* */
2536 /* DESCRIPTION */
2537 /* */
2538 /* This function sends a PTP sync message. */
2539 /* */
2540 /* INPUT */
2541 /* */
2542 /* client_ptr Pointer to PTP client */
2543 /* */
2544 /* OUTPUT */
2545 /* */
2546 /* None */
2547 /* */
2548 /* CALLS */
2549 /* */
2550 /* nx_packet_allocate Allocate a packet */
2551 /* nxd_udp_socket_source_send Send a UDP packet */
2552 /* nx_packet_release Release a packet */
2553 /* */
2554 /* CALLED BY */
2555 /* */
2556 /* _nx_ptp_client_thread_entry PTP thread entry */
2557 /* */
2558 /* RELEASE HISTORY */
2559 /* */
2560 /* DATE NAME DESCRIPTION */
2561 /* */
2562 /* 12-31-2023 Tiejun Zhou Initial Version 6.4.0 */
2563 /* */
2564 /**************************************************************************/
_nx_ptp_client_send_sync(NX_PTP_CLIENT * client_ptr)2565 static VOID _nx_ptp_client_send_sync(NX_PTP_CLIENT *client_ptr)
2566 {
2567 NX_PACKET *packet_ptr;
2568 UINT status = NX_NOT_SUCCESSFUL;
2569 UCHAR *ptr;
2570 #if NX_PTP_CLIENT_TRANSPORT_UDP
2571 NXD_ADDRESS addr;
2572 UINT addr_index = 0;
2573 #if defined(NX_ENABLE_IPV6_MULTICAST) && defined(FEATURE_NX_IPV6)
2574 NXD_IPV6_ADDRESS *ipv6_addr;
2575 NX_IP *ip_ptr;
2576 NX_INTERFACE *if_ptr;
2577 #endif
2578 #endif /* NX_PTP_CLIENT_TRANSPORT_UDP */
2579
2580 /* allocate a packet from the pool */
2581 status = nx_packet_allocate(client_ptr -> nx_ptp_client_packet_pool_ptr, &packet_ptr, NX_PTP_PACKET, NX_NO_WAIT);
2582 if (status != NX_SUCCESS)
2583 {
2584 /* Failed to allocate the packet */
2585 return;
2586 }
2587
2588 /* start of message */
2589 ptr = packet_ptr -> nx_packet_prepend_ptr;
2590
2591 #define PTP_MSG_SYNC_TOTAL_LEN (NX_PTP_MSG_HDR_LEN + NX_PTP_MSG_TIMESTAMP_LEN)
2592
2593 /* write header */
2594 /* messageType */
2595 *ptr++ = (UCHAR)(client_ptr -> nx_ptp_client_transport_specific << 4) | NX_PTP_MSG_TYPE_SYNC;
2596 /* versionPTP */
2597 *ptr++ = NX_PTP_VERSION;
2598 /* messageLength */
2599 *ptr++ = PTP_MSG_SYNC_TOTAL_LEN >> 8;
2600 *ptr++ = (UCHAR)PTP_MSG_SYNC_TOTAL_LEN;
2601 /* domainNumber */
2602 *ptr++ = client_ptr -> nx_ptp_client_domain;
2603 /* reserved 1 octets */
2604 *ptr++ = 0;
2605 /* flags 2 octets */
2606 *ptr++ = 0x02;
2607 *ptr++ = 0x08;
2608 /* correction + reserved 8 + 4 */
2609 memset(ptr, 0, 12);
2610 ptr += 12;
2611 /* sourcePortIdentity */
2612 memcpy(ptr, client_ptr -> nx_ptp_client_port_identity, NX_PTP_CLOCK_PORT_IDENTITY_SIZE); /* use case of memcpy is verified. */
2613 ptr += NX_PTP_CLOCK_PORT_IDENTITY_SIZE;
2614 /* sequenceID */
2615 client_ptr -> nx_ptp_client_sync_sequenceId++;
2616 *ptr++ = (UCHAR)(client_ptr -> nx_ptp_client_sync_sequenceId >> 8);
2617 *ptr++ = (UCHAR)(client_ptr -> nx_ptp_client_sync_sequenceId);
2618 /* control */
2619 *ptr++ = 0; /* sync message */
2620 /* XXX */
2621 *ptr++ = (UCHAR)(NX_PTP_CLIENT_LOG_SYNC_INTERVAL);
2622
2623 /* write timestamp (0) */
2624 memset(ptr, 0, NX_PTP_MSG_TIMESTAMP_LEN);
2625 ptr += NX_PTP_MSG_TIMESTAMP_LEN;
2626
2627 /* set final length of message */
2628 packet_ptr -> nx_packet_length = (ULONG)(ptr - packet_ptr -> nx_packet_prepend_ptr);
2629 packet_ptr -> nx_packet_append_ptr = ptr;
2630
2631 #if NX_PTP_CLIENT_TRANSPORT_UDP
2632 /* set source and destination addresses */
2633 #if defined(NX_ENABLE_IPV6_MULTICAST) && defined(FEATURE_NX_IPV6)
2634 if (client_ptr -> nx_ptp_client_master_addr.nxd_ip_version == NX_IP_VERSION_V6)
2635 {
2636 NX_PTP_IPV6_MULTICAST_ADDR_SET(&addr);
2637
2638 /* Use first IPv6 address as source address. */
2639 ip_ptr = client_ptr -> nx_ptp_client_ip_ptr;
2640 if_ptr = &ip_ptr -> nx_ip_interface[client_ptr -> nx_ptp_client_interface_index];
2641 ipv6_addr = if_ptr -> nxd_interface_ipv6_address_list_head;
2642 if (ipv6_addr == NX_NULL)
2643 {
2644
2645 /* No available IPv6 address. */
2646 /* Release packet. */
2647 nx_packet_release(packet_ptr);
2648
2649 return;
2650 }
2651 addr_index = ipv6_addr -> nxd_ipv6_address_index;
2652 }
2653 else
2654 #endif
2655 {
2656 #ifndef NX_DISABLE_IPV4
2657 addr.nxd_ip_version = NX_IP_VERSION_V4;
2658 addr.nxd_ip_address.v4 = NX_PTP_IPV4_MULTICAST_ADDR;
2659 addr_index = client_ptr -> nx_ptp_client_interface_index;
2660 #endif
2661 }
2662 #endif /* NX_PTP_CLIENT_TRANSPORT_UDP */
2663
2664 /* Prepare timestamp for current packet */
2665 client_ptr -> nx_ptp_client_sync_packet_ptr = packet_ptr;
2666 client_ptr -> nx_ptp_client_clock_callback(client_ptr, NX_PTP_CLIENT_CLOCK_PACKET_TS_PREPARE,
2667 &client_ptr -> nx_ptp_client_sync_ts_local, packet_ptr,
2668 client_ptr -> nx_ptp_client_clock_callback_data);
2669
2670 #if NX_PTP_CLIENT_TRANSPORT_UDP
2671 status = nxd_udp_socket_source_send((NX_UDP_SOCKET *)&client_ptr -> nx_ptp_client_event_socket,
2672 packet_ptr, &addr, NX_PTP_EVENT_UDP_PORT, addr_index);
2673 #endif /* NX_PTP_CLIENT_TRANSPORT_UDP */
2674 #if NX_PTP_CLIENT_TRANSPORT_ETHERNET
2675 nx_link_ethernet_packet_send(client_ptr -> nx_ptp_client_ip_ptr,
2676 client_ptr -> nx_ptp_client_interface_index, packet_ptr,
2677 NX_PTP_ETHERNET_P2P_MULTICAST_ADDR_MSB,
2678 NX_PTP_ETHERNET_P2P_MULTICAST_ADDR_LSB,
2679 NX_PTP_ETHERNET_TYPE);
2680 #endif /* NX_PTP_CLIENT_TRANSPORT_ETHERNET */
2681
2682 if (status)
2683 {
2684
2685 /* release packet in case of error */
2686 nx_packet_release(packet_ptr);
2687 }
2688 }
2689 #endif /* defined(NX_PTP_ENABLE_MASTER) || defined(NX_PTP_ENABLE_REVERSE_SYNC) */
2690
2691
2692 #ifdef NX_PTP_ENABLE_MASTER
2693 /**************************************************************************/
2694 /* */
2695 /* FUNCTION RELEASE */
2696 /* */
2697 /* _nx_ptp_client_send_announce PORTABLE C */
2698 /* 6.4.0 */
2699 /* AUTHOR */
2700 /* */
2701 /* Tiejun Zhou, Microsoft Corporation */
2702 /* */
2703 /* DESCRIPTION */
2704 /* */
2705 /* This function sends a PTP announce message. */
2706 /* */
2707 /* INPUT */
2708 /* */
2709 /* client_ptr Pointer to PTP client */
2710 /* */
2711 /* OUTPUT */
2712 /* */
2713 /* None */
2714 /* */
2715 /* CALLS */
2716 /* */
2717 /* nx_packet_allocate Allocate a packet */
2718 /* nxd_udp_socket_source_send Send a UDP packet */
2719 /* nx_packet_release Release a packet */
2720 /* */
2721 /* CALLED BY */
2722 /* */
2723 /* _nx_ptp_client_thread_entry PTP thread entry */
2724 /* */
2725 /* RELEASE HISTORY */
2726 /* */
2727 /* DATE NAME DESCRIPTION */
2728 /* */
2729 /* 12-31-2023 Tiejun Zhou Initial Version 6.4.0 */
2730 /* */
2731 /**************************************************************************/
_nx_ptp_client_send_announce(NX_PTP_CLIENT * client_ptr)2732 static VOID _nx_ptp_client_send_announce(NX_PTP_CLIENT *client_ptr)
2733 {
2734 NX_PACKET *packet_ptr;
2735 UINT status = NX_NOT_SUCCESSFUL;
2736 UCHAR *ptr;
2737 #if NX_PTP_CLIENT_TRANSPORT_UDP
2738 NXD_ADDRESS addr;
2739 UINT addr_index = 0;
2740 #if defined(NX_ENABLE_IPV6_MULTICAST) && defined(FEATURE_NX_IPV6)
2741 NXD_IPV6_ADDRESS *ipv6_addr;
2742 NX_IP *ip_ptr;
2743 NX_INTERFACE *if_ptr;
2744 #endif
2745 #endif /* NX_PTP_CLIENT_TRANSPORT_UDP */
2746
2747 /* Verify state */
2748
2749 /* Allocate a packet from the pool */
2750 status = nx_packet_allocate(client_ptr -> nx_ptp_client_packet_pool_ptr, &packet_ptr, NX_PTP_PACKET, NX_NO_WAIT);
2751 if (status != NX_SUCCESS)
2752 {
2753 /* Failed to allocate the packet */
2754 return;
2755 }
2756
2757 /* Start of message */
2758 ptr = packet_ptr -> nx_packet_prepend_ptr;
2759
2760 #define PTP_MSG_ANNOUNCE_PATH_TLV_LEN (2 + 2 + NX_PTP_CLOCK_IDENTITY_SIZE)
2761 #define PTP_MSG_ANNOUNCE_TOTAL_LEN (NX_PTP_MSG_HDR_LEN + NX_PTP_MSG_ANNOUNCE_LEN + PTP_MSG_ANNOUNCE_PATH_TLV_LEN)
2762
2763 /* Write header IEEE Std 1588-2008 Section 13.3.1*/
2764 /* messageType */
2765 *ptr++ = (UCHAR)(client_ptr -> nx_ptp_client_transport_specific << 4) | NX_PTP_MSG_TYPE_ANNOUNCE;
2766 /* versionPTP */
2767 *ptr++ = NX_PTP_VERSION;
2768 /* messageLength */
2769 *ptr++ = PTP_MSG_ANNOUNCE_TOTAL_LEN >> 8;
2770 *ptr++ = (UCHAR)PTP_MSG_ANNOUNCE_TOTAL_LEN;
2771 /* domainNumber */
2772 *ptr++ = client_ptr -> nx_ptp_client_domain;
2773 /* reserved 1 octets */
2774 *ptr++ = 0;
2775 /* flags 2 octets */
2776 *ptr++ = 0;
2777 *ptr++ = 0x08;
2778 /* correction + reserved 8 + 4 */
2779 memset(ptr, 0, 12);
2780 ptr += 12;
2781 /* sourcePortIdentity */
2782 memcpy(ptr, client_ptr -> nx_ptp_client_port_identity, NX_PTP_CLOCK_PORT_IDENTITY_SIZE); /* use case of memcpy is verified. */
2783 ptr += NX_PTP_CLOCK_PORT_IDENTITY_SIZE;
2784 /* sequenceID */
2785 client_ptr -> nx_ptp_client_sync_sequenceId++;
2786 *ptr++ = (UCHAR)(client_ptr -> nx_ptp_client_sync_sequenceId >> 8);
2787 *ptr++ = (UCHAR)(client_ptr -> nx_ptp_client_sync_sequenceId);
2788 /* control */
2789 *ptr++ = 5; /* other message */
2790 /* XXX */ /* 13.3.2.14 logMessageInterval */
2791 *ptr++ = 0x0;
2792
2793 /* Write announce message field IEEE Std 1588-2019 Section 13.5.2 */
2794 /* write originTimestamp */
2795 memset(ptr, 0, NX_PTP_MSG_TIMESTAMP_LEN);
2796 ptr += NX_PTP_MSG_TIMESTAMP_LEN;
2797 /* currentUtcOffset */
2798 *ptr++ = 0;
2799 *ptr++ = 0;
2800 /* reserved */
2801 *ptr++ = 0;
2802 /* grandmasterPriority1 */
2803 *ptr++ = (client_ptr -> ptp_master).nx_ptp_client_master_priority1;
2804 /* grandmasterClockQuality(4) = grandmasterClockClass(1) + grandmasterClockAccuracy(1) + grandmasterClockVariance(2) */
2805 *ptr++ = (client_ptr -> ptp_master).nx_ptp_client_master_clock_class;
2806 *ptr++ = (client_ptr -> ptp_master).nx_ptp_client_master_clock_accuracy;
2807 *ptr++ = (UCHAR)((client_ptr -> ptp_master).nx_ptp_client_master_offset_scaled_log_variance >> 8);
2808 *ptr++ = (UCHAR)((client_ptr -> ptp_master).nx_ptp_client_master_offset_scaled_log_variance);
2809 /* grandmasterPriority2 */
2810 *ptr++ = (client_ptr -> ptp_master).nx_ptp_client_master_priority2;
2811 /* grandmasterIdentity. Setting to client_port_identity because grandmaster */
2812 memcpy(ptr, client_ptr -> nx_ptp_client_port_identity, NX_PTP_CLOCK_IDENTITY_SIZE); /* use case of memcpy is verified. */
2813 ptr += NX_PTP_CLOCK_IDENTITY_SIZE;
2814 /* stepsRemoved */
2815 *ptr++ = 0;
2816 *ptr++ = 0;
2817 /* timeSource */
2818 *ptr++ = (client_ptr -> ptp_master).nx_ptp_client_master_time_source;
2819
2820 /* Path trace TLV */
2821 /* tlvType */
2822 *ptr++ = 0;
2823 *ptr++ = 0x8;
2824 /* lengthField */
2825 *ptr++ = 0;
2826 *ptr++ = 0x8;
2827 /* pathSequence */
2828 memcpy(ptr, client_ptr -> nx_ptp_client_port_identity, NX_PTP_CLOCK_IDENTITY_SIZE); /* use case of memcpy is verified. */
2829 ptr += NX_PTP_CLOCK_IDENTITY_SIZE;
2830
2831 /* set final message length */
2832 packet_ptr -> nx_packet_length = (ULONG)(ptr - (packet_ptr -> nx_packet_prepend_ptr));
2833 packet_ptr -> nx_packet_append_ptr = ptr;
2834
2835 #if NX_PTP_CLIENT_TRANSPORT_UDP
2836 /* set source and destination addresses */
2837 #if defined(NX_ENABLE_IPV6_MULTICAST) && defined(FEATURE_NX_IPV6)
2838 if (client_ptr -> nx_ptp_client_master_addr.nxd_ip_version == NX_IP_VERSION_V6)
2839 {
2840 NX_PTP_IPV6_MULTICAST_ADDR_SET(&addr);
2841
2842 /* Use first IPv6 address as source address. */
2843 ip_ptr = client_ptr -> nx_ptp_client_ip_ptr;
2844 if_ptr = &ip_ptr -> nx_ip_interface[client_ptr -> nx_ptp_client_interface_index];
2845 ipv6_addr = if_ptr -> nxd_interface_ipv6_address_list_head;
2846 if (ipv6_addr == NX_NULL)
2847 {
2848
2849 /* No available IPv6 address. */
2850 /* Release packet. */
2851 nx_packet_release(packet_ptr);
2852
2853 return;
2854 }
2855 addr_index = ipv6_addr -> nxd_ipv6_address_index;
2856 }
2857 else
2858 #endif
2859 {
2860 #ifndef NX_DISABLE_IPV4
2861 addr.nxd_ip_version = NX_IP_VERSION_V4;
2862 addr.nxd_ip_address.v4 = NX_PTP_IPV4_MULTICAST_ADDR;
2863 addr_index = client_ptr -> nx_ptp_client_interface_index;
2864 #endif
2865 }
2866 #endif /* NX_PTP_CLIENT_TRANSPORT_UDP */
2867
2868 #if NX_PTP_CLIENT_TRANSPORT_UDP
2869 status = nxd_udp_socket_source_send((NX_UDP_SOCKET *)&client_ptr -> nx_ptp_client_event_socket,
2870 packet_ptr, &addr, NX_PTP_GENERAL_UDP_PORT, addr_index);
2871 #endif /* NX_PTP_CLIENT_TRANSPORT_UDP */
2872 #if NX_PTP_CLIENT_TRANSPORT_ETHERNET
2873 nx_link_ethernet_packet_send(client_ptr -> nx_ptp_client_ip_ptr,
2874 client_ptr -> nx_ptp_client_interface_index, packet_ptr,
2875 NX_PTP_ETHERNET_P2P_MULTICAST_ADDR_MSB,
2876 NX_PTP_ETHERNET_P2P_MULTICAST_ADDR_LSB,
2877 NX_PTP_ETHERNET_TYPE);
2878 #endif /* NX_PTP_CLIENT_TRANSPORT_ETHERNET */
2879 if (status)
2880 {
2881 /* release packet in case of error */
2882 nx_packet_release(packet_ptr);
2883 }
2884 }
2885 #endif /* NX_PTP_ENABLE_MASTER */
2886
2887 /**************************************************************************/
2888 /* */
2889 /* FUNCTION RELEASE */
2890 /* */
2891 /* _nx_ptp_client_process_event_packet PORTABLE C */
2892 /* 6.4.0 */
2893 /* AUTHOR */
2894 /* */
2895 /* Yuxin Zhou, Microsoft Corporation */
2896 /* */
2897 /* DESCRIPTION */
2898 /* */
2899 /* This function processes PTP packet received through event socket. */
2900 /* */
2901 /* INPUT */
2902 /* */
2903 /* client_ptr Pointer to PTP client */
2904 /* packet_ptr Pointer to PTP packet */
2905 /* hdr Pointer to PTP header */
2906 /* */
2907 /* OUTPUT */
2908 /* */
2909 /* None */
2910 /* */
2911 /* CALLS */
2912 /* */
2913 /* _nx_ptp_client_sync_received Process Sync message */
2914 /* _nx_ptp_msg_parse_hdr Parse PTP header */
2915 /* memcmp Compare memory */
2916 /* */
2917 /* CALLED BY */
2918 /* */
2919 /* _nx_ptp_client_thread_entry PTP thread entry */
2920 /* _nx_ptp_client_send_pdelay_resp Send pdelay response */
2921 /* */
2922 /* RELEASE HISTORY */
2923 /* */
2924 /* DATE NAME DESCRIPTION */
2925 /* */
2926 /* 12-31-2020 Yuxin Zhou Initial Version 6.1.3 */
2927 /* 12-31-2023 Tiejun Zhou Modified comment(s), and */
2928 /* supported gPTP profile, */
2929 /* supported master clock, */
2930 /* resulting in version 6.4.0 */
2931 /* */
2932 /**************************************************************************/
_nx_ptp_client_process_event_packet(NX_PTP_CLIENT * client_ptr,NX_PACKET * packet_ptr,NX_PTP_MSG_HEADER * hdr)2933 static VOID _nx_ptp_client_process_event_packet(NX_PTP_CLIENT *client_ptr, NX_PACKET *packet_ptr,
2934 NX_PTP_MSG_HEADER *hdr)
2935 {
2936
2937 #if defined(NX_ENABLE_GPTP)
2938 if (hdr -> messageType == NX_PTP_MSG_TYPE_PDELAY_REQ)
2939 {
2940
2941 if (packet_ptr -> nx_packet_length < NX_PTP_MSG_PDELAY_REQ_LEN)
2942 {
2943 /* not waiting for Pdelay_Req or invalid message */
2944 return;
2945 }
2946
2947 /* record timestamp of received message (t2) */
2948 client_ptr -> nx_ptp_client_clock_callback(client_ptr, NX_PTP_CLIENT_CLOCK_TS_EXTRACT_ETHERNET,
2949 &client_ptr -> nx_ptp_client_pdelay_req_receipt, packet_ptr,
2950 client_ptr -> nx_ptp_client_clock_callback_data);
2951
2952 /* update request_id */
2953 client_ptr -> nx_ptp_client_pdelay_responder_id = hdr -> sequenceId;
2954
2955 /* update nx_ptp_client_request_port_identity */
2956 memcpy(client_ptr -> nx_ptp_client_request_port_identity, hdr -> sourcePortIdentity,
2957 NX_PTP_CLOCK_PORT_IDENTITY_SIZE); /* use case of memcpy is verified. */
2958
2959 client_ptr -> nx_ptp_client_pdelay_responder_state = NX_PTP_CLIENT_PDELAY_SEND_RESP_TWOSTEP;
2960 _nx_ptp_client_send_pdelay_resp(client_ptr);
2961 }
2962 else if (hdr -> messageType == NX_PTP_MSG_TYPE_PDELAY_RESP)
2963 {
2964 if ((client_ptr -> nx_ptp_client_pdelay_initiator_state != NX_PTP_CLIENT_PDELAY_WAIT_RESP) ||
2965 (client_ptr -> nx_ptp_client_pdelay_req_id != hdr -> sequenceId) ||
2966 (packet_ptr -> nx_packet_length < NX_PTP_MSG_PDELAY_RESP_LEN))
2967 {
2968
2969 /* not waiting for Pdelay_resp or invalid message */
2970 return;
2971 }
2972
2973 /* retrieve timestamp of event message */
2974 client_ptr -> nx_ptp_client_clock_callback(client_ptr, NX_PTP_CLIENT_CLOCK_TS_EXTRACT_ETHERNET,
2975 &client_ptr -> nx_ptp_client_pdelay_resp_ts, packet_ptr,
2976 client_ptr -> nx_ptp_client_clock_callback_data);
2977
2978 /* get t2 timestamp */
2979 _nx_ptp_msg_parse_timestamp(packet_ptr -> nx_packet_prepend_ptr, &client_ptr -> nx_ptp_client_pdelay_req_receipt_ts);
2980
2981 /* two-step message? */
2982 if (hdr -> flagField & NX_PTP_MSG_HDR_FLAG_TWO_STEP)
2983 {
2984 client_ptr -> nx_ptp_client_pdelay_initiator_state = NX_PTP_CLIENT_PDELAY_WAIT_RESP_FOLLOW_UP;
2985 }
2986 else
2987 {
2988 /* process Pdelay_Resp event */
2989 _nx_ptp_client_pdelay_resp_received(client_ptr, packet_ptr -> nx_packet_prepend_ptr);
2990 }
2991 }
2992 #endif
2993
2994 if (hdr -> messageType == NX_PTP_MSG_TYPE_SYNC)
2995 {
2996 if ((client_ptr -> nx_ptp_client_state != NX_PTP_CLIENT_STATE_SLAVE) ||
2997 (packet_ptr -> nx_packet_length < NX_PTP_MSG_SYNC_LEN))
2998 {
2999
3000 /* not waiting for Sync or invalid message */
3001 return;
3002 }
3003
3004 /* Store previous sync timestamp. */
3005 NX_PTP_TS_COPY(client_ptr -> nx_ptp_client_prev_sync, client_ptr -> nx_ptp_client_sync);
3006 NX_PTP_TS_COPY(client_ptr -> nx_ptp_client_prev_sync_ts, client_ptr -> nx_ptp_client_sync_ts);
3007
3008 /* retrieve timestamp of event message */
3009 client_ptr -> nx_ptp_client_clock_callback(client_ptr, NX_PTP_CLIENT_CLOCK_PACKET_TS_EXTRACT,
3010 &client_ptr -> nx_ptp_client_sync_ts, packet_ptr,
3011 client_ptr -> nx_ptp_client_clock_callback_data);
3012
3013 /* two-step message? */
3014 if (hdr -> flagField & NX_PTP_MSG_HDR_FLAG_TWO_STEP)
3015 {
3016
3017 /* wait for follow up message */
3018 client_ptr -> nx_ptp_client_sync_id = hdr -> sequenceId;
3019 }
3020 else
3021 {
3022
3023 /* process Sync event */
3024 _nx_ptp_client_sync_received(client_ptr, packet_ptr -> nx_packet_prepend_ptr, hdr);
3025 }
3026 }
3027 }
3028
3029
3030 /**************************************************************************/
3031 /* */
3032 /* FUNCTION RELEASE */
3033 /* */
3034 /* _nx_ptp_client_process_general_packet PORTABLE C */
3035 /* 6.4.0 */
3036 /* AUTHOR */
3037 /* */
3038 /* Yuxin Zhou, Microsoft Corporation */
3039 /* */
3040 /* DESCRIPTION */
3041 /* */
3042 /* This function processes PTP packet received through general socket. */
3043 /* */
3044 /* INPUT */
3045 /* */
3046 /* client_ptr Pointer to PTP client */
3047 /* packet_ptr Pointer to PTP packet */
3048 /* hdr Pointer to PTP header */
3049 /* */
3050 /* OUTPUT */
3051 /* */
3052 /* None */
3053 /* */
3054 /* CALLS */
3055 /* */
3056 /* _nx_ptp_client_sync_received Process Sync message */
3057 /* _nx_ptp_msg_parse_hdr Parse PTP header */
3058 /* _nx_ptp_client_delay_resp_received Process delay response */
3059 /* _nx_ptp_client_init_packet_received Process Announce message */
3060 /* memcmp Compare memory */
3061 /* */
3062 /* CALLED BY */
3063 /* */
3064 /* _nx_ptp_client_thread_entry PTP thread entry */
3065 /* */
3066 /* RELEASE HISTORY */
3067 /* */
3068 /* DATE NAME DESCRIPTION */
3069 /* */
3070 /* 12-31-2020 Yuxin Zhou Initial Version 6.1.3 */
3071 /* 12-31-2023 Tiejun Zhou Modified comment(s), and */
3072 /* supported gPTP profile, */
3073 /* supported master clock, */
3074 /* resulting in version 6.4.0 */
3075 /* */
3076 /**************************************************************************/
_nx_ptp_client_process_general_packet(NX_PTP_CLIENT * client_ptr,NX_PACKET * packet_ptr,NX_PTP_MSG_HEADER * hdr)3077 static VOID _nx_ptp_client_process_general_packet(NX_PTP_CLIENT *client_ptr, NX_PACKET *packet_ptr,
3078 NX_PTP_MSG_HEADER *hdr)
3079 {
3080
3081 /* process ANNOUNCE message */
3082 if (hdr -> messageType == NX_PTP_MSG_TYPE_ANNOUNCE)
3083 {
3084 if (packet_ptr -> nx_packet_length < NX_PTP_MSG_ANNOUNCE_LEN)
3085 {
3086
3087 /* invalid message */
3088 return;
3089 }
3090
3091 /* process announce message */
3092 _nx_ptp_client_init_packet_received(client_ptr, hdr, packet_ptr -> nx_packet_prepend_ptr);
3093 }
3094 /* process FOLLOW_UP message */
3095 else if (hdr -> messageType == NX_PTP_MSG_TYPE_FOLLOW_UP)
3096 {
3097 if ((client_ptr -> nx_ptp_client_state != NX_PTP_CLIENT_STATE_SLAVE) ||
3098 (client_ptr -> nx_ptp_client_sync_id != hdr -> sequenceId) ||
3099 (packet_ptr -> nx_packet_length < NX_PTP_MSG_FOLLOW_UP_LEN))
3100 {
3101
3102 /* not a follow up for a previous Sync or invalid message */
3103 return;
3104 }
3105
3106 /* process Sync message */
3107 _nx_ptp_client_sync_received(client_ptr, packet_ptr -> nx_packet_prepend_ptr, hdr);
3108 }
3109 #if defined(NX_ENABLE_GPTP)
3110 if (hdr -> messageType == NX_PTP_MSG_TYPE_PDELAY_RESP_FOLLOW_UP)
3111 {
3112 if ((client_ptr -> nx_ptp_client_pdelay_initiator_state != NX_PTP_CLIENT_PDELAY_WAIT_RESP_FOLLOW_UP) ||
3113 (client_ptr -> nx_ptp_client_pdelay_req_id != hdr -> sequenceId) ||
3114 (packet_ptr -> nx_packet_length < NX_PTP_MSG_PDELAY_RESP_FOLLOW_UP_LEN))
3115 {
3116
3117 /* not a follow up for a previous Pdelay_resp or invalid message */
3118 return;
3119 }
3120
3121 /* process Pdelay_Resp event */
3122 _nx_ptp_client_pdelay_resp_received(client_ptr, packet_ptr -> nx_packet_prepend_ptr);
3123 }
3124 #else
3125 else if (hdr -> messageType == NX_PTP_MSG_TYPE_DELAY_RESP)
3126 {
3127 if ((client_ptr -> nx_ptp_client_delay_state != NX_PTP_CLIENT_DELAY_WAIT_RESP) ||
3128 (client_ptr -> nx_ptp_client_delay_req_id != hdr -> sequenceId) ||
3129 (packet_ptr -> nx_packet_length < NX_PTP_MSG_DELAY_RESP_LEN) ||
3130 (memcmp(client_ptr -> nx_ptp_client_port_identity,
3131 packet_ptr -> nx_packet_prepend_ptr + NX_PTP_MSG_TIMESTAMP_LEN,
3132 NX_PTP_CLOCK_PORT_IDENTITY_SIZE) != 0))
3133 {
3134
3135 /* not a delay_resp for a previous delay_req or invalid message */
3136 return;
3137 }
3138
3139 /* process delay response message */
3140 _nx_ptp_client_delay_resp_received(client_ptr, packet_ptr -> nx_packet_prepend_ptr);
3141 }
3142 #endif
3143 }
3144
3145
3146 /**************************************************************************/
3147 /* */
3148 /* FUNCTION RELEASE */
3149 /* */
3150 /* _nx_ptp_client_thread_entry PORTABLE C */
3151 /* 6.4.0 */
3152 /* AUTHOR */
3153 /* */
3154 /* Yuxin Zhou, Microsoft Corporation */
3155 /* */
3156 /* DESCRIPTION */
3157 /* */
3158 /* This function implements the PTP client processing thread. */
3159 /* */
3160 /* INPUT */
3161 /* */
3162 /* ptp_instance Pointer to PTP client */
3163 /* */
3164 /* OUTPUT */
3165 /* */
3166 /* None */
3167 /* */
3168 /* CALLS */
3169 /* */
3170 /* _nx_ptp_client_process_general_packet Process PTP general packet */
3171 /* _nx_ptp_client_process_event_packet Process PTP event packet */
3172 /* _nx_ptp_client_send_pdelay_resp_follow_up */
3173 /* Send pdelay response message */
3174 /* _nx_ptp_client_send_follow_up Send follow up message */
3175 /* _nx_ptp_client_send_sync Send sync message */
3176 /* _nx_ptp_client_send_announce Send announce message */
3177 /* tx_event_flags_get Get PTP events */
3178 /* nx_udp_socket_receive Receive a UDP packet */
3179 /* nx_packet_release Release a packet */
3180 /* */
3181 /* CALLED BY */
3182 /* */
3183 /* ThreadX */
3184 /* */
3185 /* RELEASE HISTORY */
3186 /* */
3187 /* DATE NAME DESCRIPTION */
3188 /* */
3189 /* 12-31-2020 Yuxin Zhou Initial Version 6.1.3 */
3190 /* 12-31-2023 Tiejun Zhou Modified comment(s), and */
3191 /* supported gPTP profile, */
3192 /* supported master clock, */
3193 /* resulting in version 6.4.0 */
3194 /* */
3195 /**************************************************************************/
_nx_ptp_client_thread_entry(ULONG ptp_instance)3196 static VOID _nx_ptp_client_thread_entry(ULONG ptp_instance)
3197 {
3198 TX_INTERRUPT_SAVE_AREA
3199 NX_PTP_CLIENT *client_ptr = (NX_PTP_CLIENT *)ptp_instance;
3200 ULONG ptp_events;
3201 UINT status;
3202 NX_PACKET *packet_ptr = NX_NULL;
3203 NX_PTP_MSG_HEADER hdr;
3204
3205 #ifdef NX_PTP_ENABLE_MASTER
3206 if (client_ptr -> nx_ptp_client_role == NX_PTP_CLIENT_ROLE_MASTER_ONLY)
3207 {
3208
3209 /* Set timer values */
3210 client_ptr -> ptp_master.nx_ptp_client_master_announce_timer = NX_PTP_CLIENT_ANNOUNCE_INTERVAL;
3211 client_ptr -> nx_ptp_client_sync_timer = NX_PTP_CLIENT_SYNC_INTERVAL;
3212 client_ptr -> nx_ptp_client_state = NX_PTP_CLIENT_STATE_MASTER;
3213
3214 client_ptr -> nx_ptp_client_event_callback(client_ptr, NX_PTP_CLIENT_EVENT_MASTER,
3215 &client_ptr -> ptp_master,
3216 client_ptr -> nx_ptp_client_event_callback_data);
3217 }
3218 else
3219 {
3220
3221 /* Set timer values */
3222 client_ptr -> ptp_master.nx_ptp_client_master_announce_timer = -1;
3223 client_ptr -> nx_ptp_client_sync_timer = -1;
3224 #endif /* NX_PTP_ENABLE_MASTER */
3225 client_ptr -> nx_ptp_client_delay_req_timer = -1;
3226 client_ptr -> nx_ptp_client_announce_timeout = NX_PTP_CLIENT_ANNOUNCE_EXPIRATION;
3227
3228 /* start in listening state */
3229 client_ptr -> nx_ptp_client_state = NX_PTP_CLIENT_STATE_LISTENING;
3230 #ifdef NX_PTP_ENABLE_MASTER
3231 }
3232 #endif /* NX_PTP_ENABLE_MASTER */
3233
3234 #ifdef NX_ENABLE_GPTP
3235 client_ptr -> nx_ptp_client_pdelay_initiator_state = NX_PTP_CLIENT_PDELAY_IDLE;
3236 client_ptr -> nx_ptp_client_pdelay_req_timer = NX_PTP_CLIENT_PDELAY_REQ_INTERVAL;
3237 #endif
3238
3239 /* main loop */
3240 for (;;)
3241 {
3242
3243 /* wait for message */
3244 status = tx_event_flags_get(&(client_ptr -> nx_ptp_client_events),
3245 NX_PTP_CLIENT_ALL_EVENTS, TX_OR_CLEAR,
3246 &ptp_events, TX_WAIT_FOREVER);
3247 if (status != TX_SUCCESS)
3248 {
3249
3250 /* error while reading queue, abort thread */
3251 break;
3252 }
3253
3254 if (ptp_events & NX_PTP_CLIENT_STOP_EVENT)
3255 {
3256
3257 /* terminate thread */
3258 break;
3259 }
3260
3261 #ifdef NX_ENABLE_GPTP
3262 if (ptp_events & NX_PTP_CLIENT_PDELAY_FOLLOW_EVENT)
3263 {
3264
3265 /* update state to send_pdelay_resp_follow_up */
3266 client_ptr -> nx_ptp_client_pdelay_responder_state = NX_PTP_CLIENT_PDELAY_SEND_FOLLOW_UP;
3267
3268 /* call send follow up */
3269 _nx_ptp_client_send_pdelay_resp_follow_up(client_ptr);
3270 }
3271 #endif
3272
3273 #if defined(NX_PTP_ENABLE_MASTER) || defined(NX_PTP_ENABLE_REVERSE_SYNC)
3274 if (ptp_events & NX_PTP_CLIENT_SYNC_FOLLOW_EVENT)
3275 {
3276
3277 /* call send follow up */
3278 _nx_ptp_client_send_follow_up(client_ptr);
3279 }
3280 #endif /* defined(NX_PTP_ENABLE_MASTER) || defined(NX_PTP_ENABLE_REVERSE_SYNC) */
3281
3282 /*
3283 * PTP Message Received
3284 */
3285 if (ptp_events & NX_PTP_CLIENT_RX_EVENT)
3286 {
3287
3288 /* Loop to receive all packets. */
3289 for (;;)
3290 {
3291 #if NX_PTP_CLIENT_TRANSPORT_UDP
3292 if ((nx_udp_socket_receive(&(client_ptr -> nx_ptp_client_event_socket),
3293 &packet_ptr, NX_NO_WAIT) == NX_SUCCESS) ||
3294 (nx_udp_socket_receive(&(client_ptr -> nx_ptp_client_general_socket),
3295 &packet_ptr, NX_NO_WAIT) == NX_SUCCESS))
3296 {
3297 #endif /* NX_PTP_CLIENT_TRANSPORT_UDP */
3298 #if NX_PTP_CLIENT_TRANSPORT_ETHERNET
3299 if (client_ptr -> nx_ptp_client_received_packet_head)
3300 {
3301
3302 /* Remove the first packet and process it! */
3303
3304 /* Disable interrupts. */
3305 TX_DISABLE
3306
3307 /* Pickup the first packet. */
3308 packet_ptr = client_ptr -> nx_ptp_client_received_packet_head;
3309
3310 /* Move the head pointer to the next packet. */
3311 client_ptr -> nx_ptp_client_received_packet_head = packet_ptr -> nx_packet_queue_next;
3312
3313 /* Check for end of deferred processing queue. */
3314 if (client_ptr -> nx_ptp_client_received_packet_head == NX_NULL)
3315 {
3316
3317 /* Yes, the queue is empty. Set the tail pointer to NULL. */
3318 client_ptr -> nx_ptp_client_received_packet_tail = NX_NULL;
3319 }
3320
3321 /* Restore interrupts. */
3322 TX_RESTORE
3323
3324 #endif /* NX_PTP_CLIENT_TRANSPORT_ETHERNET */
3325
3326 /* Parse header first. */
3327 if (_nx_ptp_msg_parse_hdr(client_ptr, packet_ptr, &hdr))
3328 {
3329
3330 /* Release packet. */
3331 nx_packet_release(packet_ptr);
3332 continue;
3333 }
3334
3335 /* check origin of message */
3336 if ((client_ptr -> nx_ptp_client_state == NX_PTP_CLIENT_STATE_SLAVE) &&
3337 (memcmp(&client_ptr -> nx_ptp_client_master_port_identity,
3338 hdr.sourcePortIdentity, NX_PTP_CLOCK_PORT_IDENTITY_SIZE) != 0))
3339 {
3340
3341 /* not from our master clock */
3342 nx_packet_release(packet_ptr);
3343 continue;
3344 }
3345
3346 if ((hdr.messageType == NX_PTP_MSG_TYPE_SYNC)
3347 #ifdef NX_ENABLE_GPTP
3348 || (hdr.messageType == NX_PTP_MSG_TYPE_PDELAY_REQ)
3349 || (hdr.messageType == NX_PTP_MSG_TYPE_PDELAY_RESP)
3350 #endif /* NX_ENABLE_GPTP */
3351 )
3352 {
3353 _nx_ptp_client_process_event_packet(client_ptr, packet_ptr, &hdr);
3354 }
3355 else
3356 {
3357 _nx_ptp_client_process_general_packet(client_ptr, packet_ptr, &hdr);
3358 }
3359
3360 /* Release packet. */
3361 nx_packet_release(packet_ptr);
3362 }
3363 else
3364 {
3365 break;
3366 }
3367 }
3368 }
3369
3370 /*
3371 * Timer Event
3372 */
3373 if (ptp_events & NX_PTP_CLIENT_TIMER_EVENT)
3374 {
3375 #ifdef NX_ENABLE_GPTP
3376 /* pdelay_req interval timer */
3377 if ((client_ptr -> nx_ptp_client_pdelay_req_timer > 0) &&
3378 (--client_ptr -> nx_ptp_client_pdelay_req_timer == 0))
3379 {
3380 _nx_ptp_client_send_pdelay_req(client_ptr);
3381 }
3382 #endif
3383 #if defined(NX_PTP_ENABLE_MASTER) || defined(NX_PTP_ENABLE_REVERSE_SYNC)
3384 #ifdef NX_PTP_ENABLE_MASTER
3385 /* announce messages timeout */
3386 if (((client_ptr -> ptp_master).nx_ptp_client_master_announce_timer > 0) &&
3387 (--(client_ptr -> ptp_master).nx_ptp_client_master_announce_timer == 0))
3388 {
3389 _nx_ptp_client_send_announce(client_ptr);
3390
3391 /* Reset timer. */
3392 (client_ptr -> ptp_master).nx_ptp_client_master_announce_timer = NX_PTP_CLIENT_ANNOUNCE_INTERVAL;
3393 }
3394 #endif /* NX_PTP_ENABLE_MASTER */
3395 /* Sync messages timeout */
3396 if ((client_ptr -> nx_ptp_client_sync_timer > 0) &&
3397 (--client_ptr -> nx_ptp_client_sync_timer == 0))
3398 {
3399 _nx_ptp_client_send_sync(client_ptr);
3400
3401 /* Reset timer. */
3402 client_ptr -> nx_ptp_client_sync_timer = NX_PTP_CLIENT_SYNC_INTERVAL;
3403 }
3404 #endif /* defined(NX_PTP_ENABLE_MASTER) || defined(NX_PTP_ENABLE_REVERSE_SYNC) */
3405
3406 #ifndef NX_PTP_DISABLE_SLAVE
3407 /* announce messages timeout */
3408 if ((client_ptr -> nx_ptp_client_announce_timeout > 0) &&
3409 (--client_ptr -> nx_ptp_client_announce_timeout == 0))
3410 {
3411
3412 #ifdef NX_PTP_ENABLE_MASTER
3413 if (client_ptr -> nx_ptp_client_role == NX_PTP_CLIENT_ROLE_SLAVE_ONLY)
3414 #endif /* NX_PTP_ENABLE_MASTER */
3415 {
3416
3417 /* no Announce message received from master clock, back to listening state */
3418 client_ptr -> nx_ptp_client_state = NX_PTP_CLIENT_STATE_LISTENING;
3419 client_ptr -> nx_ptp_client_delay_req_timer = -1;
3420 client_ptr -> nx_ptp_client_announce_timeout = -1;
3421
3422 /* call handler */
3423 if (client_ptr -> nx_ptp_client_event_callback)
3424 {
3425 client_ptr -> nx_ptp_client_event_callback(client_ptr, NX_PTP_CLIENT_EVENT_TIMEOUT, NX_NULL,
3426 client_ptr -> nx_ptp_client_event_callback_data);
3427 }
3428 }
3429 #ifdef NX_PTP_ENABLE_MASTER
3430 else
3431 {
3432
3433 /* no Announce message received from master clock, change to master clock. */
3434 client_ptr -> nx_ptp_client_state = NX_PTP_CLIENT_STATE_MASTER;
3435
3436 /* set timeout for announce and sync */
3437 client_ptr -> ptp_master.nx_ptp_client_master_announce_timer = NX_PTP_CLIENT_ANNOUNCE_INTERVAL;
3438 client_ptr -> nx_ptp_client_sync_timer = NX_PTP_CLIENT_SYNC_INTERVAL;
3439 NX_PTP_DEBUG_PRINTF(("PTP: recommend local clock to be master\r\n"));
3440
3441 client_ptr -> nx_ptp_client_event_callback(client_ptr, NX_PTP_CLIENT_EVENT_MASTER,
3442 &client_ptr -> ptp_master,
3443 client_ptr -> nx_ptp_client_event_callback_data);
3444 }
3445 #endif /* NX_PTP_ENABLE_MASTER */
3446 }
3447
3448 /* delay req interval timer */
3449 if ((client_ptr -> nx_ptp_client_delay_req_timer > 0) &&
3450 (--client_ptr -> nx_ptp_client_delay_req_timer == 0))
3451 {
3452
3453 /* set flag */
3454 client_ptr -> nx_ptp_client_delay_req_flag = 1;
3455 }
3456 #endif
3457 }
3458 }
3459
3460 /* set stopped state */
3461 TX_DISABLE
3462 client_ptr -> nx_ptp_client_thread_state = NX_PTP_CLIENT_THREAD_STOPPED;
3463 TX_RESTORE
3464 }
3465
3466
3467 /**************************************************************************/
3468 /* */
3469 /* FUNCTION RELEASE */
3470 /* */
3471 /* _nxe_ptp_client_create PORTABLE C */
3472 /* 6.1.3 */
3473 /* AUTHOR */
3474 /* */
3475 /* Yuxin Zhou, Microsoft Corporation */
3476 /* */
3477 /* DESCRIPTION */
3478 /* */
3479 /* This function checks for errors on the PTP client create service. */
3480 /* */
3481 /* INPUT */
3482 /* */
3483 /* client_ptr Pointer to PTP client */
3484 /* ip_ptr Pointer to client IP instance */
3485 /* interface_index Index of PTP network interface*/
3486 /* packet_pool_ptr Pointer to client packet pool */
3487 /* thread_priority Priority of PTP thread */
3488 /* thread_stack Pointer to thread stack */
3489 /* stack_size Size of thread stack */
3490 /* clock_callback PTP clock callback */
3491 /* clock_callback_data Data for the clock callback */
3492 /* */
3493 /* OUTPUT */
3494 /* */
3495 /* status Completion status */
3496 /* */
3497 /* CALLS */
3498 /* */
3499 /* _nx_ptp_client_create Actual create service */
3500 /* */
3501 /* CALLED BY */
3502 /* */
3503 /* Application */
3504 /* */
3505 /* RELEASE HISTORY */
3506 /* */
3507 /* DATE NAME DESCRIPTION */
3508 /* */
3509 /* 12-31-2020 Yuxin Zhou Initial Version 6.1.3 */
3510 /* */
3511 /**************************************************************************/
3512 UINT _nxe_ptp_client_create(NX_PTP_CLIENT *client_ptr, NX_IP *ip_ptr, UINT interface_index,
3513 NX_PACKET_POOL *packet_pool_ptr, UINT thread_priority, UCHAR *thread_stack, UINT stack_size,
3514 NX_PTP_CLIENT_CLOCK_CALLBACK clock_callback, VOID *clock_callback_data)
3515 {
3516
3517 /* Check input parameters. */
3518 if ((client_ptr == NX_NULL) || (ip_ptr == NX_NULL) || (packet_pool_ptr == NX_NULL) ||
3519 (thread_stack == NX_NULL) || (stack_size == 0) || (clock_callback == NX_NULL))
3520 {
3521
3522 /* Return error status. */
3523 return(NX_PTR_ERROR);
3524 }
3525
3526 /* Check for invalid network interface input. */
3527 if (interface_index >= NX_MAX_PHYSICAL_INTERFACES)
3528 {
3529 return(NX_INVALID_INTERFACE);
3530 }
3531
3532 /* Check for appropriate caller. */
3533 NX_THREADS_ONLY_CALLER_CHECKING
3534
3535 /* Call the actual function. */
3536 return _nx_ptp_client_create(client_ptr, ip_ptr, interface_index, packet_pool_ptr, thread_priority,
3537 thread_stack, stack_size, clock_callback, clock_callback_data);
3538 }
3539
3540
3541 /**************************************************************************/
3542 /* */
3543 /* FUNCTION RELEASE */
3544 /* */
3545 /* _nx_ptp_client_create PORTABLE C */
3546 /* 6.4.0 */
3547 /* AUTHOR */
3548 /* */
3549 /* Yuxin Zhou, Microsoft Corporation */
3550 /* */
3551 /* DESCRIPTION */
3552 /* */
3553 /* This function creates the PTP client. */
3554 /* */
3555 /* INPUT */
3556 /* */
3557 /* client_ptr Pointer to PTP client */
3558 /* ip_ptr Pointer to client IP instance */
3559 /* interface_index Index of PTP network interface*/
3560 /* packet_pool_ptr Pointer to client packet pool */
3561 /* thread_priority Priority of PTP thread */
3562 /* thread_stack Pointer to thread stack */
3563 /* stack_size Size of thread stack */
3564 /* clock_callback PTP clock callback */
3565 /* clock_callback_data Data for the clock callback */
3566 /* */
3567 /* OUTPUT */
3568 /* */
3569 /* status Completion status */
3570 /* */
3571 /* CALLS */
3572 /* */
3573 /* memset Reset memory */
3574 /* [clock_callback] Initialize clock */
3575 /* tx_event_flags_create Create PTP event flags */
3576 /* tx_event_flags_delete Delete PTP event flags */
3577 /* nx_udp_socket_create Create a UDP socket */
3578 /* nx_udp_socket_delete Delete a UDP socket */
3579 /* nx_udp_socket_receive_notify Set UDP receive notify */
3580 /* tx_timer_create Create a timer */
3581 /* tx_timer_delete Delete a timer */
3582 /* */
3583 /* CALLED BY */
3584 /* */
3585 /* Application */
3586 /* */
3587 /* RELEASE HISTORY */
3588 /* */
3589 /* DATE NAME DESCRIPTION */
3590 /* */
3591 /* 12-31-2020 Yuxin Zhou Initial Version 6.1.3 */
3592 /* 12-31-2023 Tiejun Zhou Modified comment(s), and */
3593 /* supported gPTP profile, */
3594 /* resulting in version 6.4.0 */
3595 /* */
3596 /**************************************************************************/
3597 UINT _nx_ptp_client_create(NX_PTP_CLIENT *client_ptr, NX_IP *ip_ptr, UINT interface_index,
3598 NX_PACKET_POOL *packet_pool_ptr, UINT thread_priority, UCHAR *thread_stack, UINT stack_size,
3599 NX_PTP_CLIENT_CLOCK_CALLBACK clock_callback, VOID *clock_callback_data)
3600 {
3601 UINT status;
3602
3603 /* Null the members of NX_PTP_CLIENT. */
3604 memset(client_ptr, 0, sizeof(NX_PTP_CLIENT));
3605
3606 /* Set the Client ID to indicate the PTP client thread is ready. */
3607 client_ptr -> nx_ptp_client_id = NX_PTP_CLIENT_ID;
3608
3609 /* Set the IP instance. */
3610 client_ptr -> nx_ptp_client_ip_ptr = ip_ptr;
3611
3612 /* Set the PTP network interface. */
3613 client_ptr -> nx_ptp_client_interface_index = interface_index;
3614
3615 /* Set the packet pool, check for minimal packet size requirement. */
3616 if (packet_pool_ptr -> nx_packet_pool_payload_size <
3617 (NX_PTP_PACKET + NX_PTP_CLIENT_PACKET_DATA_SIZE))
3618 {
3619 return(NX_PTP_CLIENT_INSUFFICIENT_PACKET_PAYLOAD);
3620 }
3621 client_ptr -> nx_ptp_client_packet_pool_ptr = packet_pool_ptr;
3622
3623 /* Initialize callback function. */
3624 status = clock_callback(client_ptr, NX_PTP_CLIENT_CLOCK_INIT, NX_NULL, NX_NULL, clock_callback_data);
3625 if (status)
3626 {
3627
3628 /* Fail to initialize clock in callback function. */
3629 return(NX_PTP_CLIENT_CLOCK_CALLBACK_FAILURE);
3630 }
3631
3632 /* Set the PTP clock callback */
3633 client_ptr -> nx_ptp_client_clock_callback = clock_callback;
3634 client_ptr -> nx_ptp_client_clock_callback_data = clock_callback_data;
3635
3636 /* By default, the PTP client will run in slave only mode. */
3637 client_ptr -> nx_ptp_client_role = NX_PTP_CLIENT_ROLE_SLAVE_ONLY;
3638
3639 /* create the internal PTP event flag object. */
3640 status = tx_event_flags_create(&(client_ptr -> nx_ptp_client_events), "NetX PTP event flag");
3641 if (status != TX_SUCCESS)
3642 {
3643 return(status);
3644 }
3645
3646 #if NX_PTP_CLIENT_TRANSPORT_UDP
3647 /* create the general socket */
3648 status = nx_udp_socket_create(ip_ptr, &client_ptr -> nx_ptp_client_general_socket,
3649 "NetX PTP Client general socket", NX_IP_NORMAL,
3650 NX_DONT_FRAGMENT, NX_PTP_TIME_TO_LIVE,
3651 NX_PTP_CLIENT_MAX_QUEUE_DEPTH);
3652 if (status != NX_SUCCESS)
3653 {
3654 tx_event_flags_delete(&client_ptr -> nx_ptp_client_events);
3655 return(status);
3656 }
3657 client_ptr -> nx_ptp_client_general_socket.nx_udp_socket_reserved_ptr = client_ptr;
3658 nx_udp_socket_receive_notify(&client_ptr -> nx_ptp_client_general_socket, _nx_ptp_client_socket_receive_notify);
3659
3660 /* create the event socket */
3661 status = nx_udp_socket_create(ip_ptr, &client_ptr -> nx_ptp_client_event_socket,
3662 "NetX PTP Client event socket", NX_IP_NORMAL, NX_DONT_FRAGMENT,
3663 NX_PTP_TIME_TO_LIVE,
3664 NX_PTP_CLIENT_MAX_QUEUE_DEPTH);
3665 if (status != NX_SUCCESS)
3666 {
3667 nx_udp_socket_delete(&client_ptr -> nx_ptp_client_general_socket);
3668 tx_event_flags_delete(&client_ptr -> nx_ptp_client_events);
3669 return(status);
3670 }
3671 client_ptr -> nx_ptp_client_event_socket.nx_udp_socket_reserved_ptr = client_ptr;
3672 nx_udp_socket_receive_notify(&client_ptr -> nx_ptp_client_event_socket, _nx_ptp_client_socket_receive_notify);
3673 #endif /* NX_PTP_CLIENT_TRANSPORT_UDP */
3674
3675 /* create the timer */
3676 status = tx_timer_create(&client_ptr -> nx_ptp_client_timer,
3677 "NetX PTP Client timer",
3678 _nx_ptp_client_timer_handler,
3679 (ULONG)client_ptr,
3680 TX_TIMER_TICKS_PER_SECOND / NX_PTP_CLIENT_TIMER_TICKS_PER_SECOND,
3681 TX_TIMER_TICKS_PER_SECOND / NX_PTP_CLIENT_TIMER_TICKS_PER_SECOND,
3682 TX_NO_ACTIVATE);
3683 if (status != TX_SUCCESS)
3684 {
3685 #if NX_PTP_CLIENT_TRANSPORT_UDP
3686 nx_udp_socket_delete(&client_ptr -> nx_ptp_client_general_socket);
3687 nx_udp_socket_delete(&client_ptr -> nx_ptp_client_event_socket);
3688 #endif /* NX_PTP_CLIENT_TRANSPORT_UDP */
3689 tx_event_flags_delete(&client_ptr -> nx_ptp_client_events);
3690 return(status);
3691 }
3692
3693 /* create the Client thread */
3694 status = tx_thread_create(&client_ptr -> nx_ptp_client_thread,
3695 "NetX PTP Client", _nx_ptp_client_thread_entry,
3696 (ULONG)client_ptr, thread_stack, stack_size,
3697 thread_priority, thread_priority,
3698 NX_PTP_CLIENT_THREAD_TIME_SLICE, TX_DONT_START);
3699 if (status != TX_SUCCESS)
3700 {
3701 #if NX_PTP_CLIENT_TRANSPORT_UDP
3702 nx_udp_socket_delete(&client_ptr -> nx_ptp_client_general_socket);
3703 nx_udp_socket_delete(&client_ptr -> nx_ptp_client_event_socket);
3704 #endif /* NX_PTP_CLIENT_TRANSPORT_UDP */
3705 tx_timer_delete(&client_ptr -> nx_ptp_client_timer);
3706 tx_event_flags_delete(&client_ptr -> nx_ptp_client_events);
3707 return(status);
3708 }
3709
3710 /* return Success */
3711 return(NX_SUCCESS);
3712 }
3713
3714 /**************************************************************************/
3715 /* */
3716 /* FUNCTION RELEASE */
3717 /* */
3718 /* _nxe_ptp_client_delete PORTABLE C */
3719 /* 6.1.3 */
3720 /* AUTHOR */
3721 /* */
3722 /* Yuxin Zhou, Microsoft Corporation */
3723 /* */
3724 /* DESCRIPTION */
3725 /* */
3726 /* This function checks for errors on the PTP client delete service. */
3727 /* */
3728 /* INPUT */
3729 /* */
3730 /* client_ptr Pointer to PTP client */
3731 /* */
3732 /* OUTPUT */
3733 /* */
3734 /* status Completion status */
3735 /* */
3736 /* CALLS */
3737 /* */
3738 /* _nx_ptp_client_delete Actual delete service */
3739 /* */
3740 /* CALLED BY */
3741 /* */
3742 /* Application */
3743 /* */
3744 /* RELEASE HISTORY */
3745 /* */
3746 /* DATE NAME DESCRIPTION */
3747 /* */
3748 /* 12-31-2020 Yuxin Zhou Initial Version 6.1.3 */
3749 /* */
3750 /**************************************************************************/
3751 UINT _nxe_ptp_client_delete(NX_PTP_CLIENT *client_ptr)
3752 {
3753
3754 /* Check input parameters. */
3755 if (client_ptr == NX_NULL)
3756 {
3757
3758 /* Return error status. */
3759 return(NX_PTR_ERROR);
3760 }
3761
3762 /* Check for appropriate caller. */
3763 NX_THREADS_ONLY_CALLER_CHECKING
3764
3765 /* Call the actual function. */
3766 return(_nx_ptp_client_delete(client_ptr));
3767 }
3768
3769
3770 /**************************************************************************/
3771 /* */
3772 /* FUNCTION RELEASE */
3773 /* */
3774 /* _nx_ptp_client_delete PORTABLE C */
3775 /* 6.4.0 */
3776 /* AUTHOR */
3777 /* */
3778 /* Yuxin Zhou, Microsoft Corporation */
3779 /* */
3780 /* DESCRIPTION */
3781 /* */
3782 /* This function deletes the PTP client. */
3783 /* */
3784 /* INPUT */
3785 /* */
3786 /* client_ptr Pointer to PTP client */
3787 /* */
3788 /* OUTPUT */
3789 /* */
3790 /* status Completion status */
3791 /* */
3792 /* CALLS */
3793 /* */
3794 /* _nx_ptp_client_stop Stop PTP service */
3795 /* tx_thread_suspend Suspend PTP thread */
3796 /* tx_thread_terminate Terminate PTP thread */
3797 /* tx_thread_delete Delete PTP thread */
3798 /* tx_event_flags_delete Delete PTP event flags */
3799 /* nx_udp_socket_delete Delete a UDP socket */
3800 /* tx_timer_delete Delete a timer */
3801 /* */
3802 /* CALLED BY */
3803 /* */
3804 /* Application */
3805 /* */
3806 /* RELEASE HISTORY */
3807 /* */
3808 /* DATE NAME DESCRIPTION */
3809 /* */
3810 /* 12-31-2020 Yuxin Zhou Initial Version 6.1.3 */
3811 /* 12-31-2023 Tiejun Zhou Modified comment(s), and */
3812 /* supported gPTP profile, */
3813 /* resulting in version 6.4.0 */
3814 /* */
3815 /**************************************************************************/
3816 UINT _nx_ptp_client_delete(NX_PTP_CLIENT *client_ptr)
3817 {
3818
3819 /* Ensure the Client is stopped */
3820 _nx_ptp_client_stop(client_ptr);
3821
3822 /* Suspend the Client thread. */
3823 tx_thread_suspend(&client_ptr -> nx_ptp_client_thread);
3824
3825 /* Terminate Client thread. */
3826 tx_thread_terminate(&client_ptr -> nx_ptp_client_thread);
3827
3828 /* Delete Client thread. */
3829 tx_thread_delete(&client_ptr -> nx_ptp_client_thread);
3830
3831 /* Delete the timer */
3832 tx_timer_delete(&client_ptr -> nx_ptp_client_timer);
3833
3834 #if NX_PTP_CLIENT_TRANSPORT_UDP
3835 /* Delete the general socket */
3836 nx_udp_socket_delete((NX_UDP_SOCKET *)&client_ptr -> nx_ptp_client_general_socket);
3837
3838 /* Delete the event socket */
3839 nx_udp_socket_delete((NX_UDP_SOCKET *)&client_ptr -> nx_ptp_client_event_socket);
3840 #endif /* NX_PTP_CLIENT_TRANSPORT_UDP */
3841
3842 /* Delete the event flag */
3843 tx_event_flags_delete(&client_ptr -> nx_ptp_client_events);
3844
3845 /* return Success */
3846 return(NX_SUCCESS);
3847 }
3848
3849
3850 /**************************************************************************/
3851 /* */
3852 /* FUNCTION RELEASE */
3853 /* */
3854 /* _nxe_ptp_client_start PORTABLE C */
3855 /* 6.1.3 */
3856 /* AUTHOR */
3857 /* */
3858 /* Yuxin Zhou, Microsoft Corporation */
3859 /* */
3860 /* DESCRIPTION */
3861 /* */
3862 /* This function checks for errors on the PTP client start service. */
3863 /* */
3864 /* INPUT */
3865 /* */
3866 /* client_ptr Pointer to PTP client */
3867 /* client_port_identity_ptr Pointer to client port and */
3868 /* identity */
3869 /* client_port_identity_length Length of client port and */
3870 /* identity */
3871 /* domain PTP clock domain */
3872 /* transport_specific Transport specific */
3873 /* event_callback Event callback */
3874 /* event_callback_data Data for the event callback */
3875 /* */
3876 /* OUTPUT */
3877 /* */
3878 /* status Completion status */
3879 /* */
3880 /* CALLS */
3881 /* */
3882 /* _nx_ptp_client_start Actual start service */
3883 /* */
3884 /* CALLED BY */
3885 /* */
3886 /* Application */
3887 /* */
3888 /* RELEASE HISTORY */
3889 /* */
3890 /* DATE NAME DESCRIPTION */
3891 /* */
3892 /* 12-31-2020 Yuxin Zhou Initial Version 6.1.3 */
3893 /* */
3894 /**************************************************************************/
3895 UINT _nxe_ptp_client_start(NX_PTP_CLIENT *client_ptr, UCHAR *client_port_identity_ptr, UINT client_port_identity_length,
3896 UINT domain, UINT transport_specific, NX_PTP_CLIENT_EVENT_CALLBACK event_callback,
3897 VOID *event_callback_data)
3898 {
3899
3900 /* Check input parameters. */
3901 if ((client_ptr == NX_NULL) ||
3902 ((client_port_identity_ptr == NX_NULL) && (client_port_identity_length != 0)) ||
3903 ((client_port_identity_ptr != NX_NULL) && (client_port_identity_length != NX_PTP_CLOCK_PORT_IDENTITY_SIZE)))
3904 {
3905
3906 /* Return error status. */
3907 return(NX_PTR_ERROR);
3908 }
3909
3910 /* Check for appropriate caller. */
3911 NX_THREADS_ONLY_CALLER_CHECKING
3912
3913 /* Call the actual function. */
3914 return(_nx_ptp_client_start(client_ptr, client_port_identity_ptr, client_port_identity_length,
3915 domain, transport_specific, event_callback, event_callback_data));
3916 }
3917
3918
3919 /**************************************************************************/
3920 /* */
3921 /* FUNCTION RELEASE */
3922 /* */
3923 /* _nx_ptp_client_start PORTABLE C */
3924 /* 6.4.0 */
3925 /* AUTHOR */
3926 /* */
3927 /* Yuxin Zhou, Microsoft Corporation */
3928 /* */
3929 /* DESCRIPTION */
3930 /* */
3931 /* This function starts the PTP client. */
3932 /* */
3933 /* INPUT */
3934 /* */
3935 /* client_ptr Pointer to PTP client */
3936 /* client_port_identity_ptr Pointer to client port and */
3937 /* identity */
3938 /* client_port_identity_length Length of client port and */
3939 /* identity */
3940 /* domain PTP clock domain */
3941 /* transport_specific Transport specific */
3942 /* event_callback Event callback */
3943 /* event_callback_data Data for the event callback */
3944 /* */
3945 /* OUTPUT */
3946 /* */
3947 /* status Completion status */
3948 /* */
3949 /* CALLS */
3950 /* */
3951 /* tx_thread_suspend Suspend PTP thread */
3952 /* tx_thread_terminate Terminate PTP thread */
3953 /* tx_thread_reset Reset PTP thread */
3954 /* tx_thread_resume Resume PTP thread */
3955 /* memcpy Copy memory */
3956 /* nx_ip_interface_physical_address_get Get physical address */
3957 /* nx_udp_socket_bind Bind UDP port */
3958 /* nx_ipv4_multicast_interface_join Join IPv4 multicast group */
3959 /* nxd_ipv6_multicast_interface_join Join IPv6 multicast group */
3960 /* tx_timer_activate Activate timer */
3961 /* _nx_ptp_client_stop Stop PTP service */
3962 /* */
3963 /* CALLED BY */
3964 /* */
3965 /* Application */
3966 /* */
3967 /* RELEASE HISTORY */
3968 /* */
3969 /* DATE NAME DESCRIPTION */
3970 /* */
3971 /* 12-31-2020 Yuxin Zhou Initial Version 6.1.3 */
3972 /* 12-31-2023 Tiejun Zhou Modified comment(s), and */
3973 /* supported gPTP profile, */
3974 /* supported master clock, */
3975 /* resulting in version 6.4.0 */
3976 /* */
3977 /**************************************************************************/
3978 UINT _nx_ptp_client_start(NX_PTP_CLIENT *client_ptr, UCHAR *client_port_identity_ptr, UINT client_port_identity_length,
3979 UINT domain, UINT transport_specific, NX_PTP_CLIENT_EVENT_CALLBACK event_callback,
3980 VOID *event_callback_data)
3981 {
3982 TX_INTERRUPT_SAVE_AREA
3983 UINT state;
3984 UINT status;
3985 ULONG msw, lsw;
3986 #if defined(NX_ENABLE_IPV6_MULTICAST) && defined(FEATURE_NX_IPV6)
3987 NXD_ADDRESS maddr;
3988 #endif
3989
3990 NX_PARAMETER_NOT_USED(client_port_identity_length);
3991
3992 /* Check if Client is running */
3993 TX_DISABLE
3994 state = client_ptr -> nx_ptp_client_thread_state;
3995 if (state == NX_PTP_CLIENT_THREAD_IDLE)
3996 {
3997 client_ptr -> nx_ptp_client_thread_state = NX_PTP_CLIENT_THREAD_RUNNING;
3998 }
3999 TX_RESTORE
4000 if (state != NX_PTP_CLIENT_THREAD_IDLE)
4001 {
4002
4003 /* Client is already running */
4004 return(NX_PTP_CLIENT_ALREADY_STARTED);
4005 }
4006
4007 /* ensure the thread is terminated */
4008 tx_thread_suspend(&client_ptr -> nx_ptp_client_thread);
4009 tx_thread_terminate(&client_ptr -> nx_ptp_client_thread);
4010
4011 /* save the client parameters */
4012 client_ptr -> nx_ptp_client_domain = (UCHAR)domain;
4013 client_ptr -> nx_ptp_client_transport_specific = (UCHAR)transport_specific;
4014 client_ptr -> nx_ptp_client_event_callback = event_callback;
4015 client_ptr -> nx_ptp_client_event_callback_data = event_callback_data;
4016 client_ptr -> nx_ptp_client_delay.nanosecond = NX_PTP_CLIENT_DELAY_THRESH;
4017
4018 /* reset and resume the thread */
4019 status = tx_thread_reset(&client_ptr -> nx_ptp_client_thread);
4020 if (status != TX_SUCCESS)
4021 {
4022 TX_DISABLE
4023 client_ptr -> nx_ptp_client_thread_state = NX_PTP_CLIENT_THREAD_IDLE;
4024 TX_RESTORE
4025
4026 return(status);
4027 }
4028 tx_thread_resume(&client_ptr -> nx_ptp_client_thread);
4029
4030 /* set the client port and identity */
4031 if (client_port_identity_ptr != NX_NULL)
4032 {
4033
4034 /* copy provided identifier */
4035 memcpy(client_ptr -> nx_ptp_client_port_identity, client_port_identity_ptr,
4036 NX_PTP_CLOCK_PORT_IDENTITY_SIZE); /* use case of memcpy is verified. */
4037 }
4038 else
4039 {
4040
4041 /* get MAC address of interface */
4042 status = nx_ip_interface_physical_address_get(client_ptr -> nx_ptp_client_ip_ptr,
4043 client_ptr -> nx_ptp_client_interface_index,
4044 &msw, &lsw);
4045 if (status == TX_SUCCESS)
4046 {
4047 /* convert 48-bit MAC address to 64-bit EUI */
4048 client_ptr -> nx_ptp_client_port_identity[0] = (UCHAR)(msw >> 8);
4049 client_ptr -> nx_ptp_client_port_identity[1] = (UCHAR)msw;
4050 client_ptr -> nx_ptp_client_port_identity[2] = (UCHAR)(lsw >> 24);
4051 client_ptr -> nx_ptp_client_port_identity[3] = 0xff;
4052 client_ptr -> nx_ptp_client_port_identity[4] = 0xfe;
4053 client_ptr -> nx_ptp_client_port_identity[5] = (UCHAR)(lsw >> 16);
4054 client_ptr -> nx_ptp_client_port_identity[6] = (UCHAR)(lsw >> 8);
4055 client_ptr -> nx_ptp_client_port_identity[7] = (UCHAR)lsw;
4056
4057 /* set default port number (1) */
4058 client_ptr -> nx_ptp_client_port_identity[8] = 0;
4059 client_ptr -> nx_ptp_client_port_identity[9] = 1;
4060 }
4061 }
4062
4063 #if NX_PTP_CLIENT_TRANSPORT_UDP
4064 /* bind the general socket */
4065 if (status == TX_SUCCESS)
4066 {
4067 status = nx_udp_socket_bind((NX_UDP_SOCKET *)&client_ptr -> nx_ptp_client_general_socket,
4068 NX_PTP_GENERAL_UDP_PORT, NX_NO_WAIT);
4069 }
4070
4071 /* bind the event socket */
4072 if (status == TX_SUCCESS)
4073 {
4074 status = nx_udp_socket_bind((NX_UDP_SOCKET *)&client_ptr -> nx_ptp_client_event_socket,
4075 NX_PTP_EVENT_UDP_PORT, NX_NO_WAIT);
4076 }
4077
4078 /* join the multicast groups */
4079 if (status == TX_SUCCESS)
4080 {
4081 status = nx_ipv4_multicast_interface_join(client_ptr -> nx_ptp_client_ip_ptr,
4082 NX_PTP_IPV4_MULTICAST_ADDR,
4083 client_ptr -> nx_ptp_client_interface_index);
4084 if (status == TX_SUCCESS)
4085 {
4086 status = nx_ipv4_multicast_interface_join(client_ptr -> nx_ptp_client_ip_ptr,
4087 NX_PTP_IPV4_P2P_MULTICAST_ADDR,
4088 client_ptr -> nx_ptp_client_interface_index);
4089 if (status == TX_SUCCESS)
4090 {
4091 client_ptr -> nx_ptp_client_ipv4_group_joined = NX_TRUE;
4092 }
4093 }
4094 }
4095 #if defined(NX_ENABLE_IPV6_MULTICAST) && defined(FEATURE_NX_IPV6)
4096 if (status == TX_SUCCESS)
4097 {
4098 NX_PTP_IPV6_MULTICAST_ADDR_SET(&maddr);
4099 status = nxd_ipv6_multicast_interface_join(client_ptr -> nx_ptp_client_ip_ptr,
4100 &maddr, client_ptr -> nx_ptp_client_interface_index);
4101 if (status == TX_SUCCESS)
4102 {
4103 NX_PTP_IPV6_P2P_MULTICAST_ADDR_SET(&maddr);
4104 status = nxd_ipv6_multicast_interface_join(client_ptr -> nx_ptp_client_ip_ptr,
4105 &maddr, client_ptr -> nx_ptp_client_interface_index);
4106 if (status == TX_SUCCESS)
4107 {
4108 NX_PTP_IPV6_MULTICAST_ADDR_SET(&maddr);
4109 status = nxd_ipv6_multicast_interface_join(client_ptr -> nx_ptp_client_ip_ptr,
4110 &maddr, client_ptr -> nx_ptp_client_interface_index);
4111
4112 if (status == TX_SUCCESS)
4113 {
4114 client_ptr -> nx_ptp_client_ipv6_group_joined = NX_TRUE;
4115 }
4116 }
4117 }
4118 else if ((status == NX_NOT_SUPPORTED) && (client_ptr -> nx_ptp_client_ipv4_group_joined))
4119 {
4120
4121 /* IPv6 not enabled, use IPv4 only */
4122 status = TX_SUCCESS;
4123 }
4124 }
4125 #endif
4126 #endif /* NX_PTP_CLIENT_TRANSPORT_UDP */
4127
4128 #if NX_PTP_CLIENT_TRANSPORT_ETHERNET
4129 /* set link layer receive notification */
4130 status = nx_link_packet_receive_callback_add(client_ptr -> nx_ptp_client_ip_ptr,
4131 client_ptr -> nx_ptp_client_interface_index,
4132 &(client_ptr -> nx_ptp_client_link_queue),
4133 NX_PTP_ETHERNET_TYPE,
4134 _nx_ptp_client_ethernet_receive_notify, client_ptr);
4135 if (status != NX_SUCCESS)
4136 {
4137 return(status);
4138 }
4139
4140 status = nx_link_multicast_join(client_ptr -> nx_ptp_client_ip_ptr,
4141 client_ptr -> nx_ptp_client_interface_index,
4142 NX_PTP_ETHERNET_ALL_MULTICAST_ADDR_MSB,
4143 NX_PTP_ETHERNET_ALL_MULTICAST_ADDR_LSB);
4144 if (status != NX_SUCCESS)
4145 {
4146 return(status);
4147 }
4148
4149 status = nx_link_multicast_join(client_ptr -> nx_ptp_client_ip_ptr,
4150 client_ptr -> nx_ptp_client_interface_index,
4151 NX_PTP_ETHERNET_P2P_MULTICAST_ADDR_MSB,
4152 NX_PTP_ETHERNET_P2P_MULTICAST_ADDR_LSB);
4153 if (status != NX_SUCCESS)
4154 {
4155 return(status);
4156 }
4157 #endif /* NX_PTP_CLIENT_TRANSPORT_ETHERNET */
4158
4159 /* activate the Client timer */
4160 if (status == TX_SUCCESS)
4161 {
4162
4163 /* activate the timer */
4164 status = tx_timer_activate(&client_ptr -> nx_ptp_client_timer);
4165 }
4166
4167 /* stop the client thread in case of error */
4168 if (status != TX_SUCCESS)
4169 {
4170 _nx_ptp_client_stop(client_ptr);
4171
4172 /* return failure */
4173 return(status);
4174 }
4175
4176 /* return Success */
4177 return(NX_SUCCESS);
4178 }
4179
4180
4181 /**************************************************************************/
4182 /* */
4183 /* FUNCTION RELEASE */
4184 /* */
4185 /* _nxe_ptp_client_stop PORTABLE C */
4186 /* 6.1.3 */
4187 /* AUTHOR */
4188 /* */
4189 /* Yuxin Zhou, Microsoft Corporation */
4190 /* */
4191 /* DESCRIPTION */
4192 /* */
4193 /* This function checks for errors on the PTP client stop service. */
4194 /* */
4195 /* INPUT */
4196 /* */
4197 /* client_ptr Pointer to PTP client */
4198 /* */
4199 /* OUTPUT */
4200 /* */
4201 /* status Completion status */
4202 /* */
4203 /* CALLS */
4204 /* */
4205 /* _nx_ptp_client_stop Actual stop service */
4206 /* */
4207 /* CALLED BY */
4208 /* */
4209 /* Application */
4210 /* */
4211 /* RELEASE HISTORY */
4212 /* */
4213 /* DATE NAME DESCRIPTION */
4214 /* */
4215 /* 12-31-2020 Yuxin Zhou Initial Version 6.1.3 */
4216 /* */
4217 /**************************************************************************/
4218 UINT _nxe_ptp_client_stop(NX_PTP_CLIENT *client_ptr)
4219 {
4220
4221 /* Check input parameters. */
4222 if (client_ptr == NX_NULL)
4223 {
4224
4225 /* Return error status. */
4226 return(NX_PTR_ERROR);
4227 }
4228
4229 /* Check for appropriate caller. */
4230 NX_THREADS_ONLY_CALLER_CHECKING
4231
4232 /* Call the actual function. */
4233 return(_nx_ptp_client_stop(client_ptr));
4234 }
4235
4236
4237 /**************************************************************************/
4238 /* */
4239 /* FUNCTION RELEASE */
4240 /* */
4241 /* _nx_ptp_client_stop PORTABLE C */
4242 /* 6.4.0 */
4243 /* AUTHOR */
4244 /* */
4245 /* Yuxin Zhou, Microsoft Corporation */
4246 /* */
4247 /* DESCRIPTION */
4248 /* */
4249 /* This function stops the PTP client. */
4250 /* */
4251 /* INPUT */
4252 /* */
4253 /* client_ptr Pointer to PTP client */
4254 /* */
4255 /* OUTPUT */
4256 /* */
4257 /* status Completion status */
4258 /* */
4259 /* CALLS */
4260 /* */
4261 /* tx_timer_deactivate Deactivate timer */
4262 /* nx_udp_socket_unbind Unbind UDP port */
4263 /* nx_ipv4_multicast_interface_leave Leave IPv4 multicast group */
4264 /* nxd_ipv6_multicast_interface_leave Leave IPv6 multicast group */
4265 /* tx_event_flags_set Set PTP timer event */
4266 /* tx_thread_sleep Thread sleep */
4267 /* */
4268 /* CALLED BY */
4269 /* */
4270 /* Application */
4271 /* */
4272 /* RELEASE HISTORY */
4273 /* */
4274 /* DATE NAME DESCRIPTION */
4275 /* */
4276 /* 12-31-2020 Yuxin Zhou Initial Version 6.1.3 */
4277 /* 12-31-2023 Tiejun Zhou Modified comment(s), and */
4278 /* supported gPTP profile, */
4279 /* resulting in version 6.4.0 */
4280 /* */
4281 /**************************************************************************/
4282 UINT _nx_ptp_client_stop(NX_PTP_CLIENT *client_ptr)
4283 {
4284 TX_INTERRUPT_SAVE_AREA
4285 UINT state;
4286 #if defined(NX_ENABLE_IPV6_MULTICAST) && defined(FEATURE_NX_IPV6)
4287 NXD_ADDRESS maddr;
4288 #endif
4289
4290 /* Check if Client is running */
4291 TX_DISABLE
4292 state = client_ptr -> nx_ptp_client_thread_state;
4293 if (state == NX_PTP_CLIENT_THREAD_RUNNING)
4294 {
4295 client_ptr -> nx_ptp_client_thread_state = NX_PTP_CLIENT_THREAD_STOPPING;
4296 }
4297 TX_RESTORE
4298 if ((state != NX_PTP_CLIENT_THREAD_RUNNING) &&
4299 (state != NX_PTP_CLIENT_THREAD_STOPPED))
4300 {
4301
4302 /* Client is not running */
4303 return(NX_PTP_CLIENT_NOT_STARTED);
4304 }
4305
4306 /* deactivate the timer */
4307 tx_timer_deactivate(&client_ptr -> nx_ptp_client_timer);
4308
4309 #if NX_PTP_CLIENT_TRANSPORT_UDP
4310 /* unbind the sockets */
4311 nx_udp_socket_unbind((NX_UDP_SOCKET *)&client_ptr -> nx_ptp_client_general_socket);
4312 nx_udp_socket_unbind((NX_UDP_SOCKET *)&client_ptr -> nx_ptp_client_event_socket);
4313
4314 /* leave multicast groups */
4315 if (client_ptr -> nx_ptp_client_ipv4_group_joined)
4316 {
4317 nx_ipv4_multicast_interface_leave(client_ptr -> nx_ptp_client_ip_ptr,
4318 NX_PTP_IPV4_MULTICAST_ADDR,
4319 client_ptr -> nx_ptp_client_interface_index);
4320 nx_ipv4_multicast_interface_leave(client_ptr -> nx_ptp_client_ip_ptr,
4321 NX_PTP_IPV4_P2P_MULTICAST_ADDR,
4322 client_ptr -> nx_ptp_client_interface_index);
4323 client_ptr -> nx_ptp_client_ipv4_group_joined = NX_FALSE;
4324 }
4325 #if defined(NX_ENABLE_IPV6_MULTICAST) && defined(FEATURE_NX_IPV6)
4326 if (client_ptr -> nx_ptp_client_ipv6_group_joined)
4327 {
4328 NX_PTP_IPV6_MULTICAST_ADDR_SET(&maddr);
4329 nxd_ipv6_multicast_interface_leave(client_ptr -> nx_ptp_client_ip_ptr,
4330 &maddr, client_ptr -> nx_ptp_client_interface_index);
4331 NX_PTP_IPV6_P2P_MULTICAST_ADDR_SET(&maddr);
4332 nxd_ipv6_multicast_interface_leave(client_ptr -> nx_ptp_client_ip_ptr,
4333 &maddr, client_ptr -> nx_ptp_client_interface_index);
4334 client_ptr -> nx_ptp_client_ipv6_group_joined = NX_FALSE;
4335 }
4336 #endif
4337 #endif /* NX_PTP_CLIENT_TRANSPORT_UDP */
4338
4339 #if NX_PTP_CLIENT_TRANSPORT_ETHERNET
4340 nx_link_packet_receive_callback_remove(client_ptr -> nx_ptp_client_ip_ptr,
4341 client_ptr -> nx_ptp_client_interface_index,
4342 &(client_ptr -> nx_ptp_client_link_queue));
4343 #endif /* NX_PTP_CLIENT_TRANSPORT_ETHERNET */
4344
4345 /* send STOP message */
4346 tx_event_flags_set(&(client_ptr -> nx_ptp_client_events), NX_PTP_CLIENT_STOP_EVENT, TX_OR);
4347
4348 /* wait for thread termination */
4349 while (state != NX_PTP_CLIENT_THREAD_STOPPED)
4350 {
4351 tx_thread_sleep(1);
4352 TX_DISABLE
4353 state = client_ptr -> nx_ptp_client_thread_state;
4354 TX_RESTORE
4355 }
4356
4357 /* set Idle state */
4358 TX_DISABLE
4359 client_ptr -> nx_ptp_client_thread_state = NX_PTP_CLIENT_THREAD_IDLE;
4360 TX_RESTORE
4361
4362 /* return Success */
4363 return(NX_SUCCESS);
4364 }
4365
4366 #ifdef NX_PTP_ENABLE_MASTER
4367 /**************************************************************************/
4368 /* */
4369 /* FUNCTION RELEASE */
4370 /* */
4371 /* _nxe_ptp_client_master_enable PORTABLE C */
4372 /* 6.4.0 */
4373 /* AUTHOR */
4374 /* */
4375 /* Tiejun Zhou, Microsoft Corporation */
4376 /* */
4377 /* DESCRIPTION */
4378 /* */
4379 /* This function performs error checking for enabling master feature */
4380 /* for local PTP clock. */
4381 /* */
4382 /* INPUT */
4383 /* */
4384 /* client_ptr Pointer to PTP client */
4385 /* role Role of PTP clock */
4386 /* SLAVE_ONLY, MASTER_ONLY or */
4387 /* SLAVE_AND_MASTER */
4388 /* priority1 Priority1 of master clock */
4389 /* priority2 Priority2 of master clock */
4390 /* clock_class Class of master clock */
4391 /* clock_accuracy Accuracy of master clock */
4392 /* clock_variance Variance of master clock */
4393 /* steps_removed Steps removed of master clock */
4394 /* time_source Time source of master clock */
4395 /* */
4396 /* OUTPUT */
4397 /* */
4398 /* Completion status */
4399 /* */
4400 /* CALLS */
4401 /* */
4402 /* _nx_ptp_client_master_enable Actual master enable service */
4403 /* */
4404 /* CALLED BY */
4405 /* */
4406 /* Application */
4407 /* */
4408 /* RELEASE HISTORY */
4409 /* */
4410 /* DATE NAME DESCRIPTION */
4411 /* */
4412 /* 12-31-2023 Tiejun Zhou Initial Version 6.4.0 */
4413 /* */
4414 /**************************************************************************/
4415 UINT _nxe_ptp_client_master_enable(NX_PTP_CLIENT *client_ptr, UCHAR role, UCHAR priority1, UCHAR priority2,
4416 UCHAR clock_class, UCHAR clock_accuracy, USHORT clock_variance,
4417 USHORT steps_removed, UCHAR time_source)
4418 {
4419 /* Check input parameters. */
4420 if (client_ptr == NX_NULL)
4421 {
4422
4423 /* Return error status. */
4424 return(NX_PTR_ERROR);
4425 }
4426
4427 if ((role != NX_PTP_CLIENT_ROLE_MASTER_ONLY) &&
4428 (role != NX_PTP_CLIENT_ROLE_SLAVE_AND_MASTER))
4429 {
4430
4431 /* Return error status. */
4432 return(NX_INVALID_PARAMETERS);
4433 }
4434
4435 /* Check for appropriate caller. */
4436 NX_THREADS_ONLY_CALLER_CHECKING
4437
4438 /* Call the actual function. */
4439 return(_nx_ptp_client_master_enable(client_ptr, role, priority1, priority2, clock_class,
4440 clock_accuracy, clock_variance, steps_removed, time_source));
4441 }
4442
4443 /**************************************************************************/
4444 /* */
4445 /* FUNCTION RELEASE */
4446 /* */
4447 /* _nx_ptp_client_master_enable PORTABLE C */
4448 /* 6.4.0 */
4449 /* AUTHOR */
4450 /* */
4451 /* Tiejun Zhou, Microsoft Corporation */
4452 /* */
4453 /* DESCRIPTION */
4454 /* */
4455 /* This function enables master feature for local PTP clock. */
4456 /* */
4457 /* INPUT */
4458 /* */
4459 /* client_ptr Pointer to PTP client */
4460 /* role Role of PTP clock */
4461 /* SLAVE_ONLY, MASTER_ONLY or */
4462 /* SLAVE_AND_MASTER */
4463 /* priority1 Priority1 of master clock */
4464 /* priority2 Priority2 of master clock */
4465 /* clock_class Class of master clock */
4466 /* clock_accuracy Accuracy of master clock */
4467 /* clock_variance Variance of master clock */
4468 /* steps_removed Steps removed of master clock */
4469 /* time_source Time source of master clock */
4470 /* */
4471 /* OUTPUT */
4472 /* */
4473 /* Completion status */
4474 /* */
4475 /* CALLS */
4476 /* */
4477 /* None */
4478 /* */
4479 /* CALLED BY */
4480 /* */
4481 /* Application */
4482 /* */
4483 /* RELEASE HISTORY */
4484 /* */
4485 /* DATE NAME DESCRIPTION */
4486 /* */
4487 /* 12-31-2023 Tiejun Zhou Initial Version 6.4.0 */
4488 /* */
4489 /**************************************************************************/
4490 UINT _nx_ptp_client_master_enable(NX_PTP_CLIENT *client_ptr, UCHAR role, UCHAR priority1, UCHAR priority2,
4491 UCHAR clock_class, UCHAR clock_accuracy, USHORT clock_variance,
4492 USHORT steps_removed, UCHAR time_source)
4493 {
4494
4495 /*
4496 * nx_ptp_master_priority1: 0 is reserved. Set at 1 for highest priority
4497 * nx_ptp_master_priority2: AS2020: 8.6.2.5 The default value for a PTP Relay Instance should be 247.
4498 * The default value for a PTP End Instance should be 248.
4499 * nx_ptp_master_clock_class: AS2020: 8.6.2.2 If the value that reflects the LocalClock and ClockSource entities is
4500 * not specified or not known, clockClass is set to 248
4501 * nx_ptp_master_clock_accuracy: User input.
4502 * AS2020:8.6.2.3 If the value that reflects the LocalClock and ClockSource entities is
4503 * not specified or unknown, clockAccuracy is set to 254 (FE16).
4504 * 1588-2019: 7.6.2.6 clockAccuracy reference Table 5 enumerations
4505 * nx_ptp_master_offset_scaled_log_variance: AS2020:8.6.2.4 If the value that reflects these entities is not specified or not known,
4506 * offsetScaledLogVariance is set to 17258 (436A16)
4507 * nx_ptp_master_sequenceId Sequence ID for master starts at 0
4508 */
4509
4510 client_ptr -> ptp_master.nx_ptp_client_master_address = NX_NULL; /* use client ptr */
4511 client_ptr -> ptp_master.nx_ptp_client_master_port_identity = client_ptr -> nx_ptp_client_port_identity; /* use client port */
4512 client_ptr -> ptp_master.nx_ptp_client_master_grandmaster_identity = client_ptr -> nx_ptp_client_port_identity; /* use client identity */
4513
4514 client_ptr -> ptp_master.nx_ptp_client_master_priority1 = priority1;
4515 client_ptr -> ptp_master.nx_ptp_client_master_priority2 = priority2;
4516 client_ptr -> ptp_master.nx_ptp_client_master_clock_class = clock_class;
4517 client_ptr -> ptp_master.nx_ptp_client_master_clock_accuracy = clock_accuracy;
4518 client_ptr -> ptp_master.nx_ptp_client_master_offset_scaled_log_variance = clock_variance;
4519 client_ptr -> ptp_master.nx_ptp_client_master_steps_removed = steps_removed;
4520 client_ptr -> ptp_master.nx_ptp_client_master_time_source = time_source;
4521 client_ptr -> ptp_master.nx_ptp_client_master_sequenceId = 0xFFFF;
4522 client_ptr -> ptp_master.nx_ptp_client_master_sync_sequenceId = 0xFFFF;
4523 client_ptr -> nx_ptp_client_role = role;
4524
4525 /* return Success */
4526 return(NX_SUCCESS);
4527 }
4528 #endif /* NX_PTP_ENABLE_MASTER */
4529
4530 /**************************************************************************/
4531 /* */
4532 /* FUNCTION RELEASE */
4533 /* */
4534 /* _nxe_ptp_client_time_get PORTABLE C */
4535 /* 6.1.3 */
4536 /* AUTHOR */
4537 /* */
4538 /* Yuxin Zhou, Microsoft Corporation */
4539 /* */
4540 /* DESCRIPTION */
4541 /* */
4542 /* This function checks for errors on the PTP time get service. */
4543 /* */
4544 /* INPUT */
4545 /* */
4546 /* client_ptr Pointer to PTP client */
4547 /* time_ptr Pointer to PTP time */
4548 /* */
4549 /* OUTPUT */
4550 /* */
4551 /* status Completion status */
4552 /* */
4553 /* CALLS */
4554 /* */
4555 /* _nx_ptp_client_time_get Actual time get service */
4556 /* */
4557 /* CALLED BY */
4558 /* */
4559 /* Application */
4560 /* */
4561 /* RELEASE HISTORY */
4562 /* */
4563 /* DATE NAME DESCRIPTION */
4564 /* */
4565 /* 12-31-2020 Yuxin Zhou Initial Version 6.1.3 */
4566 /* */
4567 /**************************************************************************/
4568 UINT _nxe_ptp_client_time_get(NX_PTP_CLIENT *client_ptr, NX_PTP_TIME *time_ptr)
4569 {
4570
4571 /* Check input parameters. */
4572 if ((client_ptr == NX_NULL) || (time_ptr == NX_NULL))
4573 {
4574
4575 /* Return error status. */
4576 return(NX_PTR_ERROR);
4577 }
4578
4579 /* Check for appropriate caller. */
4580 NX_THREADS_ONLY_CALLER_CHECKING
4581
4582 /* Call the actual function. */
4583 return(_nx_ptp_client_time_get(client_ptr, time_ptr));
4584 }
4585
4586
4587 /**************************************************************************/
4588 /* */
4589 /* FUNCTION RELEASE */
4590 /* */
4591 /* _nx_ptp_client_time_get PORTABLE C */
4592 /* 6.1.3 */
4593 /* AUTHOR */
4594 /* */
4595 /* Yuxin Zhou, Microsoft Corporation */
4596 /* */
4597 /* DESCRIPTION */
4598 /* */
4599 /* This function gets the current value of the PTP clock. */
4600 /* */
4601 /* INPUT */
4602 /* */
4603 /* client_ptr Pointer to PTP client */
4604 /* time_ptr Pointer to PTP time */
4605 /* */
4606 /* OUTPUT */
4607 /* */
4608 /* status Completion status */
4609 /* */
4610 /* CALLS */
4611 /* */
4612 /* None */
4613 /* */
4614 /* CALLED BY */
4615 /* */
4616 /* Application */
4617 /* */
4618 /* RELEASE HISTORY */
4619 /* */
4620 /* DATE NAME DESCRIPTION */
4621 /* */
4622 /* 12-31-2020 Yuxin Zhou Initial Version 6.1.3 */
4623 /* */
4624 /**************************************************************************/
4625 UINT _nx_ptp_client_time_get(NX_PTP_CLIENT *client_ptr, NX_PTP_TIME *time_ptr)
4626 {
4627
4628 /* Get the current PTP clock */
4629 client_ptr -> nx_ptp_client_clock_callback(client_ptr, NX_PTP_CLIENT_CLOCK_GET,
4630 time_ptr, NX_NULL,
4631 client_ptr -> nx_ptp_client_clock_callback_data);
4632
4633 /* return Success */
4634 return(NX_SUCCESS);
4635 }
4636
4637
4638 /**************************************************************************/
4639 /* */
4640 /* FUNCTION RELEASE */
4641 /* */
4642 /* _nxe_ptp_client_time_set PORTABLE C */
4643 /* 6.1.3 */
4644 /* AUTHOR */
4645 /* */
4646 /* Yuxin Zhou, Microsoft Corporation */
4647 /* */
4648 /* DESCRIPTION */
4649 /* */
4650 /* This function checks for errors on the PTP time set service. */
4651 /* */
4652 /* INPUT */
4653 /* */
4654 /* client_ptr Pointer to PTP client */
4655 /* time_ptr Pointer to PTP time */
4656 /* */
4657 /* OUTPUT */
4658 /* */
4659 /* status Completion status */
4660 /* */
4661 /* CALLS */
4662 /* */
4663 /* _nx_ptp_client_time_set Actual time set service */
4664 /* */
4665 /* CALLED BY */
4666 /* */
4667 /* Application */
4668 /* */
4669 /* RELEASE HISTORY */
4670 /* */
4671 /* DATE NAME DESCRIPTION */
4672 /* */
4673 /* 12-31-2020 Yuxin Zhou Initial Version 6.1.3 */
4674 /* */
4675 /**************************************************************************/
4676 UINT _nxe_ptp_client_time_set(NX_PTP_CLIENT *client_ptr, NX_PTP_TIME *time_ptr)
4677 {
4678
4679 /* Check input parameters. */
4680 if ((client_ptr == NX_NULL) || (time_ptr == NX_NULL))
4681 {
4682
4683 /* Return error status. */
4684 return(NX_PTR_ERROR);
4685 }
4686
4687 /* Check for appropriate caller. */
4688 NX_THREADS_ONLY_CALLER_CHECKING
4689
4690 /* Call the actual function. */
4691 return(_nx_ptp_client_time_set(client_ptr, time_ptr));
4692 }
4693
4694
4695 /**************************************************************************/
4696 /* */
4697 /* FUNCTION RELEASE */
4698 /* */
4699 /* _nx_ptp_client_time_set PORTABLE C */
4700 /* 6.1.3 */
4701 /* AUTHOR */
4702 /* */
4703 /* Yuxin Zhou, Microsoft Corporation */
4704 /* */
4705 /* DESCRIPTION */
4706 /* */
4707 /* This function sets the initial time of the PTP clock. */
4708 /* */
4709 /* INPUT */
4710 /* */
4711 /* client_ptr Pointer to PTP client */
4712 /* time_ptr Pointer to PTP time */
4713 /* */
4714 /* OUTPUT */
4715 /* */
4716 /* status Completion status */
4717 /* */
4718 /* CALLS */
4719 /* */
4720 /* None */
4721 /* */
4722 /* CALLED BY */
4723 /* */
4724 /* Application */
4725 /* */
4726 /* RELEASE HISTORY */
4727 /* */
4728 /* DATE NAME DESCRIPTION */
4729 /* */
4730 /* 12-31-2020 Yuxin Zhou Initial Version 6.1.3 */
4731 /* */
4732 /**************************************************************************/
4733 UINT _nx_ptp_client_time_set(NX_PTP_CLIENT *client_ptr, NX_PTP_TIME *time_ptr)
4734 {
4735 TX_INTERRUPT_SAVE_AREA
4736 UINT state;
4737
4738 /* Check if Client is running */
4739 TX_DISABLE
4740 state = client_ptr -> nx_ptp_client_thread_state;
4741 TX_RESTORE
4742
4743 if (state != NX_PTP_CLIENT_THREAD_IDLE)
4744 {
4745
4746 /* Cannot set the clock when the client is running */
4747 return(NX_PTP_CLIENT_ALREADY_STARTED);
4748 }
4749
4750 /* Set the current PTP clock */
4751 client_ptr -> nx_ptp_client_clock_callback(client_ptr, NX_PTP_CLIENT_CLOCK_SET,
4752 time_ptr, NX_NULL,
4753 client_ptr -> nx_ptp_client_clock_callback_data);
4754
4755 /* return Success */
4756 return(NX_SUCCESS);
4757 }
4758
4759
4760 /**************************************************************************/
4761 /* */
4762 /* FUNCTION RELEASE */
4763 /* */
4764 /* _nxe_ptp_client_master_info_get PORTABLE C */
4765 /* 6.1.3 */
4766 /* AUTHOR */
4767 /* */
4768 /* Yuxin Zhou, Microsoft Corporation */
4769 /* */
4770 /* DESCRIPTION */
4771 /* */
4772 /* This function checks for errors on the PTP master info get service. */
4773 /* */
4774 /* INPUT */
4775 /* */
4776 /* master_ptr Pointer to PTP master clock */
4777 /* address Address of master clock */
4778 /* port_identity PTP master port and identity */
4779 /* port_identity_length Length of PTP master port and */
4780 /* identity */
4781 /* priority1 Priority1 of PTP master clock */
4782 /* priority2 Priority2 of PTP master clock */
4783 /* clock_class Class of PTP master clock */
4784 /* clock_accuracy Accuracy of PTP master clock */
4785 /* clock_variance Variance of PTP master clock */
4786 /* grandmaster_identity Identity of grandmaster clock */
4787 /* grandmaster_identity_length Length of grandmaster Identity*/
4788 /* steps_removed Steps removed from PTP header */
4789 /* time_source The source of timer used by */
4790 /* grandmaster clock */
4791 /* */
4792 /* OUTPUT */
4793 /* */
4794 /* status Completion status */
4795 /* */
4796 /* CALLS */
4797 /* */
4798 /* _nx_ptp_client_master_info_get Actual master info get service*/
4799 /* */
4800 /* CALLED BY */
4801 /* */
4802 /* Application */
4803 /* */
4804 /* RELEASE HISTORY */
4805 /* */
4806 /* DATE NAME DESCRIPTION */
4807 /* */
4808 /* 12-31-2020 Yuxin Zhou Initial Version 6.1.3 */
4809 /* */
4810 /**************************************************************************/
4811 UINT _nxe_ptp_client_master_info_get(NX_PTP_CLIENT_MASTER *master_ptr, NXD_ADDRESS *address, UCHAR **port_identity,
4812 UINT *port_identity_length, UCHAR *priority1, UCHAR *priority2, UCHAR *clock_class,
4813 UCHAR *clock_accuracy, USHORT *clock_variance, UCHAR **grandmaster_identity,
4814 UINT *grandmaster_identity_length, USHORT *steps_removed, UCHAR *time_source)
4815 {
4816 if (master_ptr == NX_NULL)
4817 {
4818
4819 /* Return error status. */
4820 return(NX_PTR_ERROR);
4821 }
4822
4823 /* Check for appropriate caller. */
4824 NX_THREADS_ONLY_CALLER_CHECKING
4825
4826 return(_nx_ptp_client_master_info_get(master_ptr, address, port_identity, port_identity_length, priority1,
4827 priority2, clock_class, clock_accuracy, clock_variance, grandmaster_identity,
4828 grandmaster_identity_length, steps_removed, time_source));
4829 }
4830
4831
4832 /**************************************************************************/
4833 /* */
4834 /* FUNCTION RELEASE */
4835 /* */
4836 /* _nx_ptp_client_master_info_get PORTABLE C */
4837 /* 6.1.3 */
4838 /* AUTHOR */
4839 /* */
4840 /* Yuxin Zhou, Microsoft Corporation */
4841 /* */
4842 /* DESCRIPTION */
4843 /* */
4844 /* This function gets information of master clock. */
4845 /* */
4846 /* INPUT */
4847 /* */
4848 /* master_ptr Pointer to PTP master clock */
4849 /* address Address of master clock */
4850 /* port_identity PTP master port and identity */
4851 /* port_identity_length Length of PTP master port and */
4852 /* identity */
4853 /* priority1 Priority1 of PTP master clock */
4854 /* priority2 Priority2 of PTP master clock */
4855 /* clock_class Class of PTP master clock */
4856 /* clock_accuracy Accuracy of PTP master clock */
4857 /* clock_variance Variance of PTP master clock */
4858 /* grandmaster_identity Identity of grandmaster clock */
4859 /* grandmaster_identity_length Length of grandmaster Identity*/
4860 /* steps_removed Steps removed from PTP header */
4861 /* time_source The source of timer used by */
4862 /* grandmaster clock */
4863 /* */
4864 /* OUTPUT */
4865 /* */
4866 /* status Completion status */
4867 /* */
4868 /* CALLS */
4869 /* */
4870 /* None */
4871 /* */
4872 /* CALLED BY */
4873 /* */
4874 /* Application */
4875 /* */
4876 /* RELEASE HISTORY */
4877 /* */
4878 /* DATE NAME DESCRIPTION */
4879 /* */
4880 /* 12-31-2020 Yuxin Zhou Initial Version 6.1.3 */
4881 /* */
4882 /**************************************************************************/
4883 UINT _nx_ptp_client_master_info_get(NX_PTP_CLIENT_MASTER *master_ptr, NXD_ADDRESS *address, UCHAR **port_identity,
4884 UINT *port_identity_length, UCHAR *priority1, UCHAR *priority2, UCHAR *clock_class,
4885 UCHAR *clock_accuracy, USHORT *clock_variance, UCHAR **grandmaster_identity,
4886 UINT *grandmaster_identity_length, USHORT *steps_removed, UCHAR *time_source)
4887 {
4888
4889 /* Set master information when the output pointer is provided. */
4890 if (address)
4891 {
4892 *address = *(master_ptr -> nx_ptp_client_master_address);
4893 }
4894
4895 if (port_identity && port_identity_length)
4896 {
4897 *port_identity = master_ptr -> nx_ptp_client_master_port_identity;
4898 *port_identity_length = NX_PTP_CLOCK_PORT_IDENTITY_SIZE;
4899 }
4900
4901 if (priority1)
4902 {
4903 *priority1 = master_ptr -> nx_ptp_client_master_priority1;
4904 }
4905
4906 if (priority2)
4907 {
4908 *priority2 = master_ptr -> nx_ptp_client_master_priority2;
4909 }
4910
4911 if (clock_class)
4912 {
4913 *clock_class = master_ptr -> nx_ptp_client_master_clock_class;
4914 }
4915
4916 if (clock_accuracy)
4917 {
4918 *clock_accuracy = master_ptr -> nx_ptp_client_master_clock_accuracy;
4919 }
4920
4921 if (clock_variance)
4922 {
4923 *clock_variance = master_ptr -> nx_ptp_client_master_offset_scaled_log_variance;
4924 }
4925
4926 if (grandmaster_identity && grandmaster_identity_length)
4927 {
4928 *grandmaster_identity = master_ptr -> nx_ptp_client_master_grandmaster_identity;
4929 *grandmaster_identity_length = NX_PTP_CLOCK_IDENTITY_SIZE;
4930 }
4931
4932 if (steps_removed)
4933 {
4934 *steps_removed = master_ptr -> nx_ptp_client_master_steps_removed;
4935 }
4936
4937 if (time_source)
4938 {
4939 *time_source = master_ptr -> nx_ptp_client_master_time_source;
4940 }
4941
4942 return(NX_SUCCESS);
4943 }
4944
4945
4946 /**************************************************************************/
4947 /* */
4948 /* FUNCTION RELEASE */
4949 /* */
4950 /* _nxe_ptp_client_sync_info_get PORTABLE C */
4951 /* 6.1.3 */
4952 /* AUTHOR */
4953 /* */
4954 /* Yuxin Zhou, Microsoft Corporation */
4955 /* */
4956 /* DESCRIPTION */
4957 /* */
4958 /* This function checks for errors on the PTP Sync get service. */
4959 /* */
4960 /* INPUT */
4961 /* */
4962 /* client_ptr Pointer to PTP client */
4963 /* flags Flags in Sync message */
4964 /* utc_offset Offset between TAI and UTC */
4965 /* */
4966 /* OUTPUT */
4967 /* */
4968 /* status Completion status */
4969 /* */
4970 /* CALLS */
4971 /* */
4972 /* _nx_ptp_client_sync_info_get Actual Sync info get service */
4973 /* */
4974 /* CALLED BY */
4975 /* */
4976 /* Application */
4977 /* */
4978 /* RELEASE HISTORY */
4979 /* */
4980 /* DATE NAME DESCRIPTION */
4981 /* */
4982 /* 12-31-2020 Yuxin Zhou Initial Version 6.1.3 */
4983 /* */
4984 /**************************************************************************/
4985 UINT _nxe_ptp_client_sync_info_get(NX_PTP_CLIENT_SYNC *sync_ptr, USHORT *flags, SHORT *utc_offset)
4986 {
4987 if (sync_ptr == NX_NULL)
4988 {
4989
4990 /* Return error status. */
4991 return(NX_PTR_ERROR);
4992 }
4993
4994 /* Check for appropriate caller. */
4995 NX_THREADS_ONLY_CALLER_CHECKING
4996
4997 return(_nx_ptp_client_sync_info_get(sync_ptr, flags, utc_offset));
4998 }
4999
5000
5001 /**************************************************************************/
5002 /* */
5003 /* FUNCTION RELEASE */
5004 /* */
5005 /* _nx_ptp_client_sync_info_get PORTABLE C */
5006 /* 6.1.3 */
5007 /* AUTHOR */
5008 /* */
5009 /* Yuxin Zhou, Microsoft Corporation */
5010 /* */
5011 /* DESCRIPTION */
5012 /* */
5013 /* This function gets information of Sync message. */
5014 /* */
5015 /* INPUT */
5016 /* */
5017 /* client_ptr Pointer to PTP client */
5018 /* flags Flags in Sync message */
5019 /* utc_offset Offset between TAI and UTC */
5020 /* */
5021 /* OUTPUT */
5022 /* */
5023 /* status Completion status */
5024 /* */
5025 /* CALLS */
5026 /* */
5027 /* None */
5028 /* */
5029 /* CALLED BY */
5030 /* */
5031 /* Application */
5032 /* */
5033 /* RELEASE HISTORY */
5034 /* */
5035 /* DATE NAME DESCRIPTION */
5036 /* */
5037 /* 12-31-2020 Yuxin Zhou Initial Version 6.1.3 */
5038 /* */
5039 /**************************************************************************/
5040 UINT _nx_ptp_client_sync_info_get(NX_PTP_CLIENT_SYNC *sync_ptr, USHORT *flags, SHORT *utc_offset)
5041 {
5042
5043 /* Set SYNC information when the output pointer is provided. */
5044 if (flags)
5045 {
5046 *flags = sync_ptr -> nx_ptp_client_sync_flags;
5047 }
5048
5049 if (utc_offset)
5050 {
5051 *utc_offset = sync_ptr -> nx_ptp_client_sync_utc_offset;
5052 }
5053
5054 return(NX_SUCCESS);
5055 }
5056
5057
5058 /**************************************************************************/
5059 /* */
5060 /* FUNCTION RELEASE */
5061 /* */
5062 /* _nx_ptp_client_packet_timestamp_notify PORTABLE C */
5063 /* 6.4.0 */
5064 /* AUTHOR */
5065 /* */
5066 /* Yuxin Zhou, Microsoft Corporation */
5067 /* */
5068 /* DESCRIPTION */
5069 /* */
5070 /* This function notifies the PTP packet is transmitted with timestamp.*/
5071 /* */
5072 /* INPUT */
5073 /* */
5074 /* client_ptr Pointer to PTP client */
5075 /* packet_ptr Pointer to PTP packet */
5076 /* timestamp_ptr Pointer to timestamp */
5077 /* */
5078 /* OUTPUT */
5079 /* */
5080 /* None */
5081 /* */
5082 /* CALLS */
5083 /* */
5084 /* None */
5085 /* */
5086 /* CALLED BY */
5087 /* */
5088 /* Application */
5089 /* */
5090 /* RELEASE HISTORY */
5091 /* */
5092 /* DATE NAME DESCRIPTION */
5093 /* */
5094 /* 12-31-2020 Yuxin Zhou Initial Version 6.1.3 */
5095 /* 12-31-2023 Tiejun Zhou Modified comment(s), and */
5096 /* supported gPTP profile, */
5097 /* supported master clock, */
5098 /* resulting in version 6.4.0 */
5099 /* */
5100 /**************************************************************************/
5101 VOID _nx_ptp_client_packet_timestamp_notify(NX_PTP_CLIENT *client_ptr, NX_PACKET *packet_ptr, NX_PTP_TIME *timestamp_ptr)
5102 {
5103 #ifdef NX_ENABLE_GPTP
5104 /* process t1 send time */
5105 if (client_ptr &&
5106 (client_ptr -> nx_ptp_client_pdelay_initiator_state == NX_PTP_CLIENT_PDELAY_WAIT_REQ_TS) &&
5107 (client_ptr -> nx_ptp_client_pdelay_req_packet_ptr == packet_ptr))
5108 {
5109
5110 /* store timestamp */
5111 client_ptr -> nx_ptp_client_pdelay_req_ts = *timestamp_ptr;
5112
5113 /* update state */
5114 client_ptr -> nx_ptp_client_pdelay_initiator_state = NX_PTP_CLIENT_PDELAY_WAIT_RESP;
5115 }
5116
5117 /* process t3 response time */
5118 if (client_ptr &&
5119 (client_ptr -> nx_ptp_client_pdelay_resp_packet_ptr == packet_ptr))
5120 {
5121
5122 /* store timestamp */
5123 client_ptr -> nx_ptp_client_pdelay_resp_origin = *timestamp_ptr;
5124
5125 /* set timer event */
5126 tx_event_flags_set(&(client_ptr -> nx_ptp_client_events), NX_PTP_CLIENT_PDELAY_FOLLOW_EVENT, TX_OR);
5127
5128 client_ptr -> nx_ptp_client_pdelay_resp_packet_ptr = NX_NULL;
5129 }
5130
5131
5132
5133 #endif /* NX_ENABLE_GPTP */
5134
5135 /* get timestamp of previous delay_req message */
5136 if (client_ptr &&
5137 (client_ptr -> nx_ptp_client_delay_state == NX_PTP_CLIENT_DELAY_WAIT_REQ_TS) &&
5138 (client_ptr -> nx_ptp_client_delay_req_packet_ptr == packet_ptr))
5139 {
5140
5141 /* store timestamp */
5142 client_ptr -> nx_ptp_client_delay_ts = *timestamp_ptr;
5143
5144 /* update state */
5145 client_ptr -> nx_ptp_client_delay_state = NX_PTP_CLIENT_DELAY_WAIT_RESP;
5146 }
5147
5148 #if defined(NX_PTP_ENABLE_MASTER) || defined(NX_PTP_ENABLE_REVERSE_SYNC)
5149 /* get timestamp of previous sync message */
5150 if (client_ptr && (client_ptr -> nx_ptp_client_sync_packet_ptr == packet_ptr))
5151 {
5152
5153 client_ptr -> nx_ptp_client_sync_packet_ptr = NX_NULL;
5154
5155 /* store timestamp */
5156 client_ptr -> nx_ptp_client_sync_ts_local = *timestamp_ptr;
5157
5158 /* set follow up event */
5159 tx_event_flags_set(&(client_ptr -> nx_ptp_client_events), NX_PTP_CLIENT_SYNC_FOLLOW_EVENT, TX_OR);
5160 }
5161 #endif /* defined(NX_PTP_ENABLE_MASTER) || defined(NX_PTP_ENABLE_REVERSE_SYNC) */
5162 }
5163
5164
5165 /**************************************************************************/
5166 /* */
5167 /* FUNCTION RELEASE */
5168 /* */
5169 /* _nx_ptp_client_soft_clock_callback PORTABLE C */
5170 /* 6.1.3 */
5171 /* AUTHOR */
5172 /* */
5173 /* Yuxin Zhou, Microsoft Corporation */
5174 /* */
5175 /* DESCRIPTION */
5176 /* */
5177 /* This function implements soft PTP clock. */
5178 /* */
5179 /* INPUT */
5180 /* */
5181 /* client_ptr Pointer to PTP client */
5182 /* operation PTP clock operation */
5183 /* time_ptr Pointer to timestamp */
5184 /* packet_ptr Pointer to PTP packet */
5185 /* callback_data Pointer to callback data */
5186 /* */
5187 /* OUTPUT */
5188 /* */
5189 /* status Completion status */
5190 /* */
5191 /* CALLS */
5192 /* */
5193 /* _nx_ptp_client_soft_clock_adjust Adjust soft PTP clock */
5194 /* _nx_ptp_client_utility_inc64 Increment a 64-bit number */
5195 /* */
5196 /* CALLED BY */
5197 /* */
5198 /* PTP internal */
5199 /* */
5200 /* RELEASE HISTORY */
5201 /* */
5202 /* DATE NAME DESCRIPTION */
5203 /* */
5204 /* 12-31-2020 Yuxin Zhou Initial Version 6.1.3 */
5205 /* */
5206 /**************************************************************************/
5207 UINT _nx_ptp_client_soft_clock_callback(NX_PTP_CLIENT *client_ptr, UINT operation,
5208 NX_PTP_TIME *time_ptr, NX_PACKET *packet_ptr,
5209 VOID *callback_data)
5210 {
5211 TX_INTERRUPT_SAVE_AREA
5212
5213 NX_PARAMETER_NOT_USED(callback_data);
5214
5215 switch (operation)
5216 {
5217
5218 /* Nothing to do for soft initialization. */
5219 case NX_PTP_CLIENT_CLOCK_INIT:
5220 break;
5221
5222 /* Set clock. */
5223 case NX_PTP_CLIENT_CLOCK_SET:
5224 TX_DISABLE
5225 client_ptr -> nx_ptp_client_soft_clock = *time_ptr;
5226 TX_RESTORE
5227 break;
5228
5229 /* Extract timestamp from packet.
5230 For soft implementation, simply fallthrough and return current timestamp. */
5231 case NX_PTP_CLIENT_CLOCK_PACKET_TS_EXTRACT:
5232
5233 /* Get clock. */
5234 case NX_PTP_CLIENT_CLOCK_GET:
5235 TX_DISABLE
5236 *time_ptr = client_ptr -> nx_ptp_client_soft_clock;
5237 TX_RESTORE
5238 break;
5239
5240 /* Adjust clock. */
5241 case NX_PTP_CLIENT_CLOCK_ADJUST:
5242 _nx_ptp_client_soft_clock_adjust(client_ptr, time_ptr -> nanosecond);
5243 break;
5244
5245 /* Prepare timestamp for current packet.
5246 For soft implementation, simply notify current timestamp. */
5247 case NX_PTP_CLIENT_CLOCK_PACKET_TS_PREPARE:
5248 _nx_ptp_client_packet_timestamp_notify(client_ptr, packet_ptr, &(client_ptr -> nx_ptp_client_soft_clock));
5249 break;
5250
5251 /* Update soft timer. */
5252 case NX_PTP_CLIENT_CLOCK_SOFT_TIMER_UPDATE:
5253 TX_DISABLE
5254
5255 /* increment the nanosecond field of the software clock */
5256 time_ptr -> nanosecond +=
5257 (LONG)(NX_PTP_NANOSECONDS_PER_SEC / NX_PTP_CLIENT_TIMER_TICKS_PER_SECOND);
5258
5259 /* update the second field */
5260 if (time_ptr -> nanosecond >= NX_PTP_NANOSECONDS_PER_SEC)
5261 {
5262 time_ptr -> nanosecond -= NX_PTP_NANOSECONDS_PER_SEC;
5263 _nx_ptp_client_utility_inc64(&(time_ptr -> second_high),
5264 &(time_ptr -> second_low));
5265 }
5266 TX_RESTORE
5267 break;
5268
5269 default:
5270 return(NX_PTP_PARAM_ERROR);
5271 }
5272
5273 return(NX_SUCCESS);
5274 }
5275
5276
5277 /**************************************************************************/
5278 /* */
5279 /* FUNCTION RELEASE */
5280 /* */
5281 /* _nxe_ptp_client_utility_time_diff PORTABLE C */
5282 /* 6.1.3 */
5283 /* AUTHOR */
5284 /* */
5285 /* Yuxin Zhou, Microsoft Corporation */
5286 /* */
5287 /* DESCRIPTION */
5288 /* */
5289 /* This function checks for errors on the PTP time difference service. */
5290 /* */
5291 /* INPUT */
5292 /* */
5293 /* time1_ptr Pointer to first PTP time */
5294 /* time2_ptr Pointer to second PTP time */
5295 /* result_ptr Pointer to result time1-time2 */
5296 /* */
5297 /* OUTPUT */
5298 /* */
5299 /* status Completion status */
5300 /* */
5301 /* CALLS */
5302 /* */
5303 /* _nx_ptp_client_utility_time_diff Actual time difference service*/
5304 /* */
5305 /* CALLED BY */
5306 /* */
5307 /* Application */
5308 /* */
5309 /* RELEASE HISTORY */
5310 /* */
5311 /* DATE NAME DESCRIPTION */
5312 /* */
5313 /* 12-31-2020 Yuxin Zhou Initial Version 6.1.3 */
5314 /* */
5315 /**************************************************************************/
5316 UINT _nxe_ptp_client_utility_time_diff(NX_PTP_TIME *time1_ptr, NX_PTP_TIME *time2_ptr, NX_PTP_TIME *result_ptr)
5317 {
5318
5319 /* Check input parameters. */
5320 if ((time1_ptr == NX_NULL) || (time2_ptr == NX_NULL) || (result_ptr == NX_NULL))
5321 {
5322
5323 /* Return error status. */
5324 return(NX_PTR_ERROR);
5325 }
5326
5327 /* Check for appropriate caller. */
5328 NX_THREADS_ONLY_CALLER_CHECKING
5329
5330 /* Call the actual function. */
5331 return(_nx_ptp_client_utility_time_diff(time1_ptr, time2_ptr, result_ptr));
5332 }
5333
5334 /**************************************************************************/
5335 /* */
5336 /* FUNCTION RELEASE */
5337 /* */
5338 /* _nxe_ptp_client_utility_time_sum PORTABLE C */
5339 /* 6.4.0 */
5340 /* AUTHOR */
5341 /* */
5342 /* Tiejun Zhou, Microsoft Corporation */
5343 /* */
5344 /* DESCRIPTION */
5345 /* */
5346 /* This function checks for errors on the PTP time sum service. */
5347 /* */
5348 /* INPUT */
5349 /* */
5350 /* time1_ptr Pointer to first PTP time */
5351 /* time2_ptr Pointer to second PTP time */
5352 /* result_ptr Pointer to result time1+time2 */
5353 /* */
5354 /* OUTPUT */
5355 /* */
5356 /* status Completion status */
5357 /* */
5358 /* CALLS */
5359 /* */
5360 /* _nx_ptp_client_utility_time_sum Actual time sum service */
5361 /* */
5362 /* CALLED BY */
5363 /* */
5364 /* Application */
5365 /* */
5366 /* RELEASE HISTORY */
5367 /* */
5368 /* DATE NAME DESCRIPTION */
5369 /* */
5370 /* 12-31-2023 Tiejun Zhou Initial Version 6.4.0 */
5371 /* */
5372 /**************************************************************************/
5373 UINT _nxe_ptp_client_utility_time_sum(NX_PTP_TIME *time1_ptr, NX_PTP_TIME *time2_ptr, NX_PTP_TIME *result_ptr)
5374 {
5375
5376 /* Check input parameters. */
5377 if ((time1_ptr == NX_NULL) || (time2_ptr == NX_NULL) || (result_ptr == NX_NULL))
5378 {
5379
5380 /* Return error status. */
5381 return(NX_PTR_ERROR);
5382 }
5383
5384 /* Check for appropriate caller. */
5385 NX_THREADS_ONLY_CALLER_CHECKING
5386
5387 /* Call the actual function. */
5388 return(_nx_ptp_client_utility_time_sum(time1_ptr, time2_ptr, result_ptr));
5389 }
5390
5391
5392 /**************************************************************************/
5393 /* */
5394 /* FUNCTION RELEASE */
5395 /* */
5396 /* _nx_ptp_client_utility_time_diff PORTABLE C */
5397 /* 6.1.3 */
5398 /* AUTHOR */
5399 /* */
5400 /* Yuxin Zhou, Microsoft Corporation */
5401 /* */
5402 /* DESCRIPTION */
5403 /* */
5404 /* This function computes the difference between two PTP times. */
5405 /* */
5406 /* INPUT */
5407 /* */
5408 /* time1_ptr Pointer to first PTP time */
5409 /* time2_ptr Pointer to second PTP time */
5410 /* result_ptr Pointer to result time1-time2 */
5411 /* */
5412 /* OUTPUT */
5413 /* */
5414 /* status Completion status */
5415 /* */
5416 /* CALLS */
5417 /* */
5418 /* _nx_ptp_client_utility_sub64 Subtracts two 64-bit numbers */
5419 /* _nx_ptp_client_utility_dec64 Decrement a 64-bit number */
5420 /* _nx_ptp_client_utility_inc64 Increment a 64-bit number */
5421 /* */
5422 /* CALLED BY */
5423 /* */
5424 /* Application */
5425 /* _nx_ptp_client_delay_resp_received Process delay response */
5426 /* */
5427 /* RELEASE HISTORY */
5428 /* */
5429 /* DATE NAME DESCRIPTION */
5430 /* */
5431 /* 12-31-2020 Yuxin Zhou Initial Version 6.1.3 */
5432 /* */
5433 /**************************************************************************/
5434 UINT _nx_ptp_client_utility_time_diff(NX_PTP_TIME *time1_ptr, NX_PTP_TIME *time2_ptr, NX_PTP_TIME *result_ptr)
5435 {
5436 LONG sec_hi;
5437 ULONG sec_lo;
5438 LONG ns;
5439
5440 /* compute difference of seconds */
5441 sec_hi = time1_ptr -> second_high;
5442 sec_lo = time1_ptr -> second_low;
5443 _nx_ptp_client_utility_sub64(&sec_hi, &sec_lo, time2_ptr -> second_high,
5444 time2_ptr -> second_low);
5445
5446 /* compute difference of nanoseconds */
5447 /* note: this cannot overflow as nanosecond field is in range +/-0-999999999 */
5448 ns = time1_ptr -> nanosecond - time2_ptr -> nanosecond;
5449
5450 /* keep nanoseconds in range +/-0-999999999 */
5451 if (ns <= -NX_PTP_NANOSECONDS_PER_SEC)
5452 {
5453 ns += NX_PTP_NANOSECONDS_PER_SEC;
5454 _nx_ptp_client_utility_dec64(&sec_hi, &sec_lo);
5455 }
5456 else if (ns >= NX_PTP_NANOSECONDS_PER_SEC)
5457 {
5458 ns -= NX_PTP_NANOSECONDS_PER_SEC;
5459 _nx_ptp_client_utility_inc64(&sec_hi, &sec_lo);
5460 }
5461
5462 /* ensure the nanoseconds field has same sign as seconds field */
5463 if ((sec_hi >= 0) && ((sec_hi != 0) || (sec_lo != 0)))
5464 {
5465 /* positive number of seconds */
5466 if (ns < 0)
5467 {
5468 ns += NX_PTP_NANOSECONDS_PER_SEC;
5469 _nx_ptp_client_utility_dec64(&sec_hi, &sec_lo);
5470 }
5471 }
5472 else if (sec_hi < 0)
5473 {
5474 /* negative number of seconds */
5475 if (ns > 0)
5476 {
5477 ns -= NX_PTP_NANOSECONDS_PER_SEC;
5478 _nx_ptp_client_utility_inc64(&sec_hi, &sec_lo);
5479 }
5480 }
5481
5482 /* return result time */
5483 result_ptr -> second_high = sec_hi;
5484 result_ptr -> second_low = sec_lo;
5485 result_ptr -> nanosecond = ns;
5486
5487 return(NX_SUCCESS);
5488 }
5489
5490
5491 /**************************************************************************/
5492 /* */
5493 /* FUNCTION RELEASE */
5494 /* */
5495 /* _nx_ptp_client_utility_time_sum PORTABLE C */
5496 /* 6.4.0 */
5497 /* AUTHOR */
5498 /* */
5499 /* Tiejun Zhou, Microsoft Corporation */
5500 /* */
5501 /* DESCRIPTION */
5502 /* */
5503 /* This function computes the sum of two PTP times. */
5504 /* */
5505 /* INPUT */
5506 /* */
5507 /* time1_ptr Pointer to first PTP time */
5508 /* time2_ptr Pointer to second PTP time */
5509 /* result_ptr Pointer to result time1+time2 */
5510 /* */
5511 /* OUTPUT */
5512 /* */
5513 /* status Completion status */
5514 /* */
5515 /* CALLS */
5516 /* */
5517 /* _nx_ptp_client_utility_add64 Adds two 64-bit numbers */
5518 /* _nx_ptp_client_utility_dec64 Decrement a 64-bit number */
5519 /* _nx_ptp_client_utility_inc64 Increment a 64-bit number */
5520 /* */
5521 /* CALLED BY */
5522 /* */
5523 /* Application */
5524 /* _nx_ptp_client_pdelay_resp_received Process pdelay response */
5525 /* */
5526 /* RELEASE HISTORY */
5527 /* */
5528 /* DATE NAME DESCRIPTION */
5529 /* */
5530 /* 12-31-2023 Tiejun Zhou Initial Version 6.4.0 */
5531 /* */
5532 /**************************************************************************/
5533 UINT _nx_ptp_client_utility_time_sum(NX_PTP_TIME *time1_ptr, NX_PTP_TIME *time2_ptr, NX_PTP_TIME *result_ptr)
5534 {
5535 LONG sec_hi;
5536 ULONG sec_lo;
5537 LONG ns;
5538
5539 /* compute sum of seconds */
5540 sec_hi = time1_ptr -> second_high;
5541 sec_lo = time1_ptr -> second_low;
5542 _nx_ptp_client_utility_add64(&sec_hi, &sec_lo, time2_ptr -> second_high,
5543 time2_ptr -> second_low);
5544
5545 /* compute sum of nanoseconds */
5546 /* note: this cannot overflow as nanosecond field is in range +/-0-999999999 */
5547 ns = time1_ptr -> nanosecond + time2_ptr -> nanosecond;
5548
5549 /* keep nanoseconds in range +/-0-999999999 */
5550 if (ns <= -NX_PTP_NANOSECONDS_PER_SEC)
5551 {
5552 ns += NX_PTP_NANOSECONDS_PER_SEC;
5553 _nx_ptp_client_utility_dec64(&sec_hi, &sec_lo);
5554 }
5555 else if (ns >= NX_PTP_NANOSECONDS_PER_SEC)
5556 {
5557 ns -= NX_PTP_NANOSECONDS_PER_SEC;
5558 _nx_ptp_client_utility_inc64(&sec_hi, &sec_lo);
5559 }
5560
5561 /* ensure the nanoseconds field has same sign as seconds field */
5562 if ((sec_hi >= 0) && ((sec_hi != 0) || (sec_lo != 0)))
5563 {
5564 /* positive number of seconds */
5565 if (ns < 0)
5566 {
5567 ns += NX_PTP_NANOSECONDS_PER_SEC;
5568 _nx_ptp_client_utility_dec64(&sec_hi, &sec_lo);
5569 }
5570 }
5571 else if (sec_hi < 0)
5572 {
5573 /* negative number of seconds */
5574 if (ns > 0)
5575 {
5576 ns -= NX_PTP_NANOSECONDS_PER_SEC;
5577 _nx_ptp_client_utility_inc64(&sec_hi, &sec_lo);
5578 }
5579 }
5580
5581 /* return result time */
5582 result_ptr -> second_high = sec_hi;
5583 result_ptr -> second_low = sec_lo;
5584 result_ptr -> nanosecond = ns;
5585
5586 return(NX_SUCCESS);
5587 }
5588
5589 /**************************************************************************/
5590 /* */
5591 /* FUNCTION RELEASE */
5592 /* */
5593 /* _nxe_ptp_client_utility_convert_time_to_date PORTABLE C */
5594 /* 6.1.3 */
5595 /* AUTHOR */
5596 /* */
5597 /* Yuxin Zhou, Microsoft Corporation */
5598 /* */
5599 /* DESCRIPTION */
5600 /* */
5601 /* This function checks for errors on the PTP time conversion service. */
5602 /* */
5603 /* INPUT */
5604 /* */
5605 /* time_ptr Pointer to PTP time */
5606 /* offset signed second offset to add */
5607 /* the PTP time */
5608 /* date_time_ptr Pointer to resulting date */
5609 /* */
5610 /* OUTPUT */
5611 /* */
5612 /* status Completion status */
5613 /* */
5614 /* CALLS */
5615 /* */
5616 /* _nx_ptp_client_utility_convert_time_to_date */
5617 /* Actual time conversion service*/
5618 /* */
5619 /* CALLED BY */
5620 /* */
5621 /* Application */
5622 /* */
5623 /* RELEASE HISTORY */
5624 /* */
5625 /* DATE NAME DESCRIPTION */
5626 /* */
5627 /* 12-31-2020 Yuxin Zhou Initial Version 6.1.3 */
5628 /* */
5629 /**************************************************************************/
5630 UINT _nxe_ptp_client_utility_convert_time_to_date(NX_PTP_TIME *time_ptr, LONG offset, NX_PTP_DATE_TIME *date_time_ptr)
5631 {
5632
5633 /* Check input parameters. */
5634 if ((time_ptr == NX_NULL) || (date_time_ptr == NX_NULL))
5635 {
5636
5637 /* Return error status. */
5638 return(NX_PTR_ERROR);
5639 }
5640
5641 /* Check for appropriate caller. */
5642 NX_THREADS_ONLY_CALLER_CHECKING
5643
5644 /* Call the actual function. */
5645 return(_nx_ptp_client_utility_convert_time_to_date(time_ptr, offset, date_time_ptr));
5646 }
5647
5648
5649 /**************************************************************************/
5650 /* */
5651 /* FUNCTION RELEASE */
5652 /* */
5653 /* _nx_ptp_client_utility_convert_time_to_date PORTABLE C */
5654 /* 6.1.3 */
5655 /* AUTHOR */
5656 /* */
5657 /* Yuxin Zhou, Microsoft Corporation */
5658 /* */
5659 /* DESCRIPTION */
5660 /* */
5661 /* This function converts a PTP time to a UTC date and time. */
5662 /* */
5663 /* INPUT */
5664 /* */
5665 /* time_ptr Pointer to PTP time */
5666 /* offset Signed second offset to add */
5667 /* the PTP time */
5668 /* date_time_ptr Pointer to resulting date */
5669 /* */
5670 /* OUTPUT */
5671 /* */
5672 /* status Completion status */
5673 /* */
5674 /* CALLS */
5675 /* */
5676 /* _nx_ptp_client_utility_add64 Add two 64-bit number */
5677 /* */
5678 /* CALLED BY */
5679 /* */
5680 /* Application */
5681 /* */
5682 /* RELEASE HISTORY */
5683 /* */
5684 /* DATE NAME DESCRIPTION */
5685 /* */
5686 /* 12-31-2020 Yuxin Zhou Initial Version 6.1.3 */
5687 /* */
5688 /**************************************************************************/
5689 UINT _nx_ptp_client_utility_convert_time_to_date(NX_PTP_TIME *time_ptr, LONG offset, NX_PTP_DATE_TIME *date_time_ptr)
5690 {
5691 #define IS_LEAP(y) (((y) % 4) == 0 && (((y) % 100) != 0 || ((y) % 400) == 0))
5692 #define SECS_PER_MINUTE 60
5693 #define SECS_PER_HOUR (60 * SECS_PER_MINUTE)
5694 #define SECS_PER_DAY (24 * SECS_PER_HOUR)
5695 LONG secs_high;
5696 ULONG secs_low;
5697 UINT year, month, day, hour, minute;
5698 ULONG secs_per_year, secs_per_month;
5699 ULONG weekday;
5700 UINT is_leap;
5701
5702 /* get number of seconds */
5703 secs_high = time_ptr -> second_high;
5704 secs_low = time_ptr -> second_low;
5705
5706 /* add local time offset */
5707 if (offset != 0)
5708 {
5709 _nx_ptp_client_utility_add64(&secs_high, &secs_low, offset < 0 ? -1 : 0, (ULONG)offset);
5710 }
5711 if (secs_high < 0)
5712 {
5713
5714 /* invalid negative time */
5715 return(NX_PTP_PARAM_ERROR);
5716 }
5717
5718 /* determine the current year from Epoch (January 1, 1970) */
5719 year = 1970;
5720 secs_per_year = 365 * SECS_PER_DAY;
5721 is_leap = 0;
5722 weekday = 4; /* thursday */
5723 while ((secs_high > 0) || (secs_low >= secs_per_year))
5724 {
5725 if (secs_low < secs_per_year)
5726 {
5727 secs_high--;
5728 }
5729 secs_low -= secs_per_year;
5730 weekday += is_leap ? 366 : 365;
5731 year++;
5732 is_leap = IS_LEAP(year) ? 1 : 0;
5733 secs_per_year = is_leap ? 366 * SECS_PER_DAY : 365 * SECS_PER_DAY;
5734 }
5735 /* compute day of the week from remaining seconds */
5736 weekday = (weekday + secs_low / SECS_PER_DAY) % 7;
5737
5738 /* determine current month */
5739 month = 1;
5740 secs_per_month = 31 * SECS_PER_DAY;
5741 while (secs_low >= secs_per_month)
5742 {
5743 secs_low -= secs_per_month;
5744 month++;
5745 if (month == 2)
5746 {
5747
5748 /* february */
5749 secs_per_month = is_leap ? 29 * SECS_PER_DAY : 28 * SECS_PER_DAY;
5750 }
5751 else if ((month == 4) || (month == 6) || (month == 9) || (month == 11))
5752 {
5753
5754 /* april, june, september, november */
5755 secs_per_month = 30 * SECS_PER_DAY;
5756 }
5757 else
5758 {
5759
5760 /* the other months */
5761 secs_per_month = 31 * SECS_PER_DAY;
5762 }
5763 }
5764
5765 /* determine current day of the month */
5766 day = secs_low / SECS_PER_DAY;
5767 secs_low -= day * SECS_PER_DAY;
5768
5769 /* determine current hour */
5770 hour = secs_low / SECS_PER_HOUR;
5771 secs_low -= hour * SECS_PER_HOUR;
5772
5773 /* determine current minute */
5774 minute = secs_low / SECS_PER_MINUTE;
5775 secs_low -= minute * SECS_PER_MINUTE;
5776
5777 /* return date */
5778 date_time_ptr -> year = year;
5779 date_time_ptr -> month = (UCHAR)month;
5780 date_time_ptr -> day = (UCHAR)(day + 1);
5781 date_time_ptr -> hour = (UCHAR)hour;
5782 date_time_ptr -> minute = (UCHAR)minute;
5783 date_time_ptr -> second = (UCHAR)secs_low;
5784 date_time_ptr -> weekday = (UCHAR)weekday;
5785 date_time_ptr -> nanosecond = (ULONG)time_ptr -> nanosecond;
5786
5787 return(NX_SUCCESS);
5788 }
5789
5790
5791 /**************************************************************************/
5792 /* */
5793 /* FUNCTION RELEASE */
5794 /* */
5795 /* _nx_ptp_client_utility_add64 PORTABLE C */
5796 /* 6.1.3 */
5797 /* AUTHOR */
5798 /* */
5799 /* Yuxin Zhou, Microsoft Corporation */
5800 /* */
5801 /* DESCRIPTION */
5802 /* */
5803 /* This function adds two 64-bit numbers: A = A + B. */
5804 /* */
5805 /* INPUT */
5806 /* */
5807 /* a_hi Pointer to higher 32-bit of A */
5808 /* a_lo Pointer to lower 32-bit of A */
5809 /* b_hi higher 32-bit of B */
5810 /* b_lo lower 32-bit of B */
5811 /* */
5812 /* OUTPUT */
5813 /* */
5814 /* None */
5815 /* */
5816 /* CALLS */
5817 /* */
5818 /* None */
5819 /* */
5820 /* CALLED BY */
5821 /* */
5822 /* _nx_ptp_client_clock_adjust Adjust PTP clock */
5823 /* _nx_ptp_client_utility_convert_time_to_date */
5824 /* Convert time to date */
5825 /* */
5826 /* RELEASE HISTORY */
5827 /* */
5828 /* DATE NAME DESCRIPTION */
5829 /* */
5830 /* 12-31-2020 Yuxin Zhou Initial Version 6.1.3 */
5831 /* */
5832 /**************************************************************************/
5833 VOID _nx_ptp_client_utility_add64(LONG *a_hi, ULONG *a_lo, LONG b_hi, ULONG b_lo)
5834 {
5835 LONG r_hi;
5836 ULONG r_lo;
5837
5838 r_hi = *a_hi + b_hi;
5839 r_lo = *a_lo + b_lo;
5840 if ((r_lo < *a_lo) || (r_lo < b_lo))
5841 {
5842 r_hi++; /* add carry */
5843 }
5844 *a_hi = r_hi;
5845 *a_lo = r_lo;
5846 }
5847
5848
5849 /**************************************************************************/
5850 /* */
5851 /* FUNCTION RELEASE */
5852 /* */
5853 /* _nx_ptp_client_utility_sub64 PORTABLE C */
5854 /* 6.1.3 */
5855 /* AUTHOR */
5856 /* */
5857 /* Yuxin Zhou, Microsoft Corporation */
5858 /* */
5859 /* DESCRIPTION */
5860 /* */
5861 /* This function substracts two 64-bit numbers: A = A - B. */
5862 /* */
5863 /* INPUT */
5864 /* */
5865 /* a_hi Pointer to higher 32-bit of A */
5866 /* a_lo Pointer to lower 32-bit of A */
5867 /* b_hi higher 32-bit of B */
5868 /* b_lo lower 32-bit of B */
5869 /* */
5870 /* OUTPUT */
5871 /* */
5872 /* None */
5873 /* */
5874 /* CALLS */
5875 /* */
5876 /* None */
5877 /* */
5878 /* CALLED BY */
5879 /* */
5880 /* _nx_ptp_client_utility_time_diff Diff two PTP times */
5881 /* */
5882 /* RELEASE HISTORY */
5883 /* */
5884 /* DATE NAME DESCRIPTION */
5885 /* */
5886 /* 12-31-2020 Yuxin Zhou Initial Version 6.1.3 */
5887 /* */
5888 /**************************************************************************/
5889 VOID _nx_ptp_client_utility_sub64(LONG *a_hi, ULONG *a_lo, LONG b_hi, ULONG b_lo)
5890 {
5891 LONG r_hi;
5892 ULONG r_lo;
5893
5894 r_hi = *a_hi - b_hi;
5895 r_lo = *a_lo - b_lo;
5896 if (*a_lo < b_lo)
5897 {
5898 r_hi--; /* subtract carry */
5899 }
5900 *a_hi = r_hi;
5901 *a_lo = r_lo;
5902 }
5903
5904
5905 /**************************************************************************/
5906 /* */
5907 /* FUNCTION RELEASE */
5908 /* */
5909 /* _nx_ptp_client_utility_inc64 PORTABLE C */
5910 /* 6.1.3 */
5911 /* AUTHOR */
5912 /* */
5913 /* Yuxin Zhou, Microsoft Corporation */
5914 /* */
5915 /* DESCRIPTION */
5916 /* */
5917 /* This function increments a 64-bit number: A = A + 1. */
5918 /* */
5919 /* INPUT */
5920 /* */
5921 /* a_hi Pointer to higher 32-bit of A */
5922 /* a_lo Pointer to lower 32-bit of A */
5923 /* */
5924 /* OUTPUT */
5925 /* */
5926 /* None */
5927 /* */
5928 /* CALLS */
5929 /* */
5930 /* None */
5931 /* */
5932 /* CALLED BY */
5933 /* */
5934 /* _nx_ptp_client_soft_clock_adjust Adjust soft PTP clock */
5935 /* _nx_ptp_client_clock_adjust Adjust PTP clock */
5936 /* _nx_ptp_client_utility_time_diff Diff two PTP times */
5937 /* _nx_ptp_client_soft_clock_callback Soft PTP clock */
5938 /* */
5939 /* RELEASE HISTORY */
5940 /* */
5941 /* DATE NAME DESCRIPTION */
5942 /* */
5943 /* 12-31-2020 Yuxin Zhou Initial Version 6.1.3 */
5944 /* */
5945 /**************************************************************************/
5946 VOID _nx_ptp_client_utility_inc64(LONG *a_hi, ULONG *a_lo)
5947 {
5948 ULONG r_lo;
5949
5950 r_lo = *a_lo + 1;
5951 if (r_lo == 0)
5952 {
5953 *a_hi = *a_hi + 1; /* add carry */
5954 }
5955 *a_lo = r_lo;
5956 }
5957
5958
5959 /**************************************************************************/
5960 /* */
5961 /* FUNCTION RELEASE */
5962 /* */
5963 /* _nx_ptp_client_utility_dec64 PORTABLE C */
5964 /* 6.1.3 */
5965 /* AUTHOR */
5966 /* */
5967 /* Yuxin Zhou, Microsoft Corporation */
5968 /* */
5969 /* DESCRIPTION */
5970 /* */
5971 /* This function decrements a 64-bit number: A = A - 1. */
5972 /* */
5973 /* INPUT */
5974 /* */
5975 /* a_hi Pointer to higher 32-bit of A */
5976 /* a_lo Pointer to lower 32-bit of A */
5977 /* */
5978 /* OUTPUT */
5979 /* */
5980 /* None */
5981 /* */
5982 /* CALLS */
5983 /* */
5984 /* None */
5985 /* */
5986 /* CALLED BY */
5987 /* */
5988 /* _nx_ptp_client_soft_clock_adjust Adjust soft PTP clock */
5989 /* _nx_ptp_client_clock_adjust Adjust PTP clock */
5990 /* _nx_ptp_client_utility_time_diff Diff two PTP times */
5991 /* */
5992 /* RELEASE HISTORY */
5993 /* */
5994 /* DATE NAME DESCRIPTION */
5995 /* */
5996 /* 12-31-2020 Yuxin Zhou Initial Version 6.1.3 */
5997 /* */
5998 /**************************************************************************/
5999 VOID _nx_ptp_client_utility_dec64(LONG *a_hi, ULONG *a_lo)
6000 {
6001 ULONG r_lo;
6002
6003 r_lo = *a_lo;
6004 if (r_lo == 0)
6005 {
6006 *a_hi = *a_hi - 1; /* subtract carry */
6007 }
6008 *a_lo = r_lo - 1;
6009 }
6010
6011
6012 /**************************************************************************/
6013 /* */
6014 /* FUNCTION RELEASE */
6015 /* */
6016 /* _nx_ptp_client_utility_neg64 PORTABLE C */
6017 /* 6.1.3 */
6018 /* AUTHOR */
6019 /* */
6020 /* Yuxin Zhou, Microsoft Corporation */
6021 /* */
6022 /* DESCRIPTION */
6023 /* */
6024 /* This function changes the sign of a 64-bit number: A = -A. */
6025 /* */
6026 /* INPUT */
6027 /* */
6028 /* a_hi Pointer to higher 32-bit of A */
6029 /* a_lo Pointer to lower 32-bit of A */
6030 /* */
6031 /* OUTPUT */
6032 /* */
6033 /* None */
6034 /* */
6035 /* CALLS */
6036 /* */
6037 /* None */
6038 /* */
6039 /* CALLED BY */
6040 /* */
6041 /* _nx_ptp_client_utility_time_div_by_2 Divide a PTP time by 2 */
6042 /* */
6043 /* RELEASE HISTORY */
6044 /* */
6045 /* DATE NAME DESCRIPTION */
6046 /* */
6047 /* 12-31-2020 Yuxin Zhou Initial Version 6.1.3 */
6048 /* */
6049 /**************************************************************************/
6050 VOID _nx_ptp_client_utility_neg64(LONG *a_hi, ULONG *a_lo)
6051 {
6052 LONG r_hi;
6053
6054 r_hi = -*a_hi;
6055 if (*a_lo != 0)
6056 {
6057 r_hi--; /* subtract carry */
6058 }
6059 *a_hi = r_hi;
6060 *a_lo = -*a_lo;
6061 }
6062
6063
6064 /**************************************************************************/
6065 /* */
6066 /* FUNCTION RELEASE */
6067 /* */
6068 /* _nx_ptp_client_utility_time_div_by_2 PORTABLE C */
6069 /* 6.1.3 */
6070 /* AUTHOR */
6071 /* */
6072 /* Yuxin Zhou, Microsoft Corporation */
6073 /* */
6074 /* DESCRIPTION */
6075 /* */
6076 /* This function divides a PTP time by 2. */
6077 /* */
6078 /* INPUT */
6079 /* */
6080 /* time_ptr Pointer to PTP time */
6081 /* */
6082 /* OUTPUT */
6083 /* */
6084 /* None */
6085 /* */
6086 /* CALLS */
6087 /* */
6088 /* _nx_ptp_client_utility_neg64 Change the sign of number */
6089 /* */
6090 /* CALLED BY */
6091 /* */
6092 /* _nx_ptp_client_delay_resp_received Process delay response */
6093 /* */
6094 /* RELEASE HISTORY */
6095 /* */
6096 /* DATE NAME DESCRIPTION */
6097 /* */
6098 /* 12-31-2020 Yuxin Zhou Initial Version 6.1.3 */
6099 /* */
6100 /**************************************************************************/
6101 VOID _nx_ptp_client_utility_time_div_by_2(NX_PTP_TIME *time_ptr)
6102 {
6103 UINT neg;
6104 LONG sec_hi;
6105 ULONG sec_lo;
6106 LONG ns;
6107
6108 /* get current time value */
6109 sec_hi = time_ptr -> second_high;
6110 sec_lo = time_ptr -> second_low;
6111 ns = time_ptr -> nanosecond;
6112
6113 /* implement division on unsigned values */
6114 if ((sec_hi < 0) || (ns < 0))
6115 {
6116 _nx_ptp_client_utility_neg64(&sec_hi, &sec_lo);
6117 ns = -ns;
6118 neg = 1;
6119 }
6120 else
6121 {
6122 neg = 0;
6123 }
6124
6125 /* divide nanoseconds by two */
6126 ns >>= 1;
6127 if (sec_lo & 1)
6128 {
6129
6130 /* add rest of seconds division */
6131 ns += 500000000L;
6132 }
6133
6134 /* divide seconds by two */
6135 sec_lo >>= 1;
6136 if (sec_hi & 1)
6137 {
6138 sec_lo |= 0x80000000UL;
6139 }
6140 sec_hi >>= 1;
6141
6142 /* restore sign */
6143 if (neg)
6144 {
6145 _nx_ptp_client_utility_neg64(&sec_hi, &sec_lo);
6146 ns = -ns;
6147 }
6148
6149 /* return result */
6150 time_ptr -> second_high = sec_hi;
6151 time_ptr -> second_low = sec_lo;
6152 time_ptr -> nanosecond = ns;
6153 }
6154