1 /* PTP API test.  This test case extends the basic test case to cover API not tested by others. */
2 
3 #include   "netx_ptp_utility.h"
4 
5 #define     DEMO_STACK_SIZE    2048
6 
7 /* Define the ThreadX and NetX object control blocks...  */
8 
9 static TX_THREAD               ntest_0;
10 static TX_THREAD               ntest_1;
11 
12 static NX_PACKET_POOL          pool_0;
13 static NX_IP                   ip_0;
14 static NX_IP                   ip_1;
15 static NX_UDP_SOCKET           generic_socket;
16 static NX_UDP_SOCKET           event_socket;
17 static NX_PTP_CLIENT           ptp_client;
18 
19 static NX_PTP_TIME             sync_ts = {0x0, 0x5F97CD71, 0x240d93b2};
20 static NX_PTP_TIME             follow_up_ts = {0x0, 0x5F97CD71, 0x240e29e0};
21 static NX_PTP_TIME             delay_response_ts = {0x0, 0x5F97CD71, 0x2494b730};
22 static NX_PTP_TIME             synced_time;
23 static NX_PTP_TIME             expected_time;
24 static USHORT                  synced_utc_offset;
25 static USHORT                  expected_utc_offset;
26 static UCHAR                   ptp_stack[2048];
27 
28 
29 #define NUM_PACKETS            24
30 #define PACKET_SIZE            1536
31 #define PACKET_POOL_SIZE       (NUM_PACKETS * (PACKET_SIZE + sizeof(NX_PACKET)))
32 
33 /* Define thread prototypes.  */
34 
35 static void    ntest_0_entry(ULONG thread_input);
36 static void    ntest_1_entry(ULONG thread_input);
37 extern void    _nx_ram_network_driver(struct NX_IP_DRIVER_STRUCT *driver_req);
38 
39 
40 /* Define what the initial system looks like.  */
41 #ifdef CTEST
test_application_define(void * first_unused_memory)42 VOID test_application_define(void *first_unused_memory)
43 #else
44 void netx_ptp_client_api_application_define(void *first_unused_memory)
45 #endif
46 {
47 CHAR       *pointer;
48 UINT       status;
49 
50     /* Print out test information banner.  */
51     printf("NetX Test:   PTP API Test .............................................");
52 
53 #if defined(NX_ENABLE_GPTP) || (NX_PTP_CLIENT_TRANSPORT_UDP==0)
54     printf("N/A\n");
55     test_control_return(3);
56 #else
57     /* Setup the working pointer.  */
58     pointer = (CHAR *) first_unused_memory;
59 
60     /* Create the main thread.  */
61     tx_thread_create(&ntest_0, "thread 0", ntest_0_entry, 0,
62                      pointer, DEMO_STACK_SIZE,
63                      4, 4, TX_NO_TIME_SLICE, TX_AUTO_START);
64 
65     pointer = pointer + DEMO_STACK_SIZE;
66 
67     /* Create the main thread.  */
68     tx_thread_create(&ntest_1, "thread 1", ntest_1_entry, 0,
69                      pointer, DEMO_STACK_SIZE,
70                      3, 3, TX_NO_TIME_SLICE, TX_AUTO_START);
71 
72     pointer = pointer + DEMO_STACK_SIZE;
73 
74     /* Initialize the NetX system.  */
75     nx_system_initialize();
76 
77     /* Create a packet pool.  */
78     status = nx_packet_pool_create(&pool_0, "NetX Main Packet Pool", PACKET_SIZE, pointer, PACKET_POOL_SIZE);
79     pointer = pointer + PACKET_POOL_SIZE;
80 
81     if(status)
82         ASSERT_SUCCESS(status);
83 
84     /* Create an IP instance.  */
85     status = nx_ip_create(&ip_0, "NetX IP Instance 0", IP_ADDRESS(1, 2, 3, 4), 0xFFFFFF00UL, &pool_0, _nx_ram_network_driver,
86                           pointer, 2048, 1);
87     pointer = pointer + 2048;
88 
89     /* Create another IP instance.  */
90     status += nx_ip_create(&ip_1, "NetX IP Instance 1", IP_ADDRESS(1, 2, 3, 5), 0xFFFFFF00UL, &pool_0, _nx_ram_network_driver,
91                            pointer, 2048, 1);
92     pointer = pointer + 2048;
93 
94     if(status)
95         ASSERT_SUCCESS(status);
96 
97     /* Enable ARP and supply ARP cache memory for IP Instance 0.  */
98     status = nx_arp_enable(&ip_0, (void *) pointer, 1024);
99     pointer = pointer + 1024;
100 
101     /* Enable ARP and supply ARP cache memory for IP Instance 1.  */
102     status += nx_arp_enable(&ip_1, (void *) pointer, 1024);
103     pointer = pointer + 1024;
104 
105     /* Check ARP enable status.  */
106     if(status)
107         ASSERT_SUCCESS(status);
108 
109     /* Enable UDP processing for both IP instances.  */
110     status = nx_udp_enable(&ip_0);
111     status += nx_udp_enable(&ip_1);
112 
113     /* Check UDP enable status.  */
114     if(status)
115         ASSERT_SUCCESS(status);
116 #endif
117 }
118 
119 
120 /* PTP handler.  */
ptp_event_callback(NX_PTP_CLIENT * ptp_client_ptr,UINT event,VOID * event_data,VOID * callback_data)121 static UINT ptp_event_callback(NX_PTP_CLIENT *ptp_client_ptr, UINT event, VOID *event_data, VOID *callback_data)
122 {
123 NX_PTP_DATE_TIME date;
124 NXD_ADDRESS address;
125 UCHAR *port_identity;
126 UINT port_identity_length;
127 UCHAR priority1, priority2;
128 UCHAR clock_class, clock_accuracy;
129 USHORT clock_variance;
130 UCHAR *grandmaster_identity;
131 UINT grandmaster_identity_length;
132 USHORT steps_removed;
133 UCHAR time_source;
134 
135     NX_PARAMETER_NOT_USED(callback_data);
136 
137     switch (event)
138     {
139         case NX_PTP_CLIENT_EVENT_MASTER:
140         {
141             DBGPRINTF("new MASTER clock!\r\n");
142             nx_ptp_client_master_info_get((NX_PTP_CLIENT_MASTER *)event_data, &address, &port_identity,
143                                           &port_identity_length, &priority1, &priority2, &clock_class,
144                                           &clock_accuracy, &clock_variance, &grandmaster_identity,
145                                           &grandmaster_identity_length, &steps_removed, &time_source);
146             ASSERT_TRUE(address.nxd_ip_address.v4 == IP_ADDRESS(1, 2, 3, 5));
147             ASSERT_TRUE(address.nxd_ip_version == NX_IP_VERSION_V4);
148             ASSERT_TRUE(port_identity_length == NX_PTP_CLOCK_PORT_IDENTITY_SIZE);
149             ASSERT_SUCCESS(memcmp(port_identity, "\x46\xe7\xc8\xff\xfe\x71\x61\xa1\x00\x01", port_identity_length));
150             ASSERT_TRUE(priority1 == 128);
151             ASSERT_TRUE(priority2 == 128);
152             ASSERT_TRUE(clock_class == 127);
153             ASSERT_TRUE(clock_accuracy == 0xfe);
154             ASSERT_TRUE(clock_variance == 0x7060);
155             ASSERT_TRUE(grandmaster_identity_length == NX_PTP_CLOCK_IDENTITY_SIZE);
156             ASSERT_SUCCESS(memcmp(grandmaster_identity, "\x46\xe7\xc8\xff\xfe\x71\x61\xa1\x00\x00", port_identity_length));
157             ASSERT_TRUE(steps_removed == 0);
158             ASSERT_TRUE(time_source == 0xa0);
159             break;
160         }
161 
162         case NX_PTP_CLIENT_EVENT_SYNC:
163         {
164             nx_ptp_client_sync_info_get((NX_PTP_CLIENT_SYNC *)event_data, NX_NULL, &synced_utc_offset);
165             DBGPRINTF("SYNC event: utc offset=%d\r\n", synced_utc_offset);
166 
167             /* read the PTP clock */
168             nx_ptp_client_time_get(ptp_client_ptr, &synced_time);
169 
170             /* convert PTP time to UTC date and time */
171             nx_ptp_client_utility_convert_time_to_date(&synced_time, -synced_utc_offset, &date);
172 
173             /* display the current time */
174             DBGPRINTF("ts: %d%d.%d\r\n", synced_time.second_high,
175                                          synced_time.second_low,
176                                          synced_time.nanosecond);
177             DBGPRINTF("%2u/%02u/%u %02u:%02u:%02u.%09lu\r\n", date.day, date.month, date.year,
178                                                               date.hour, date.minute, date.second,
179                                                               date.nanosecond);
180 
181             break;
182         }
183 
184         case NX_PTP_CLIENT_EVENT_TIMEOUT:
185         {
186             DBGPRINTF("Master clock TIMEOUT!\r\n");
187             break;
188         }
189         default:
190         {
191             break;
192         }
193     }
194 
195     return(0);
196 }
197 
198 /* Define the test threads.  */
ntest_0_entry(ULONG thread_input)199 static void    ntest_0_entry(ULONG thread_input)
200 {
201 UINT status;
202 NX_PTP_TIME ts_zero = {0};
203 NX_PTP_TIME ts_diff = {1, 1, 1};
204 
205     /* Reset synced time. */
206     memset(&synced_time, 0, sizeof(synced_time));
207     synced_utc_offset = 0xFFFF;
208 
209     /* Set expected value. */
210     expected_utc_offset = 0x1234;
211     expected_time.second_high = (delay_response_ts.second_high + follow_up_ts.second_high) / 2;
212     expected_time.second_low = (delay_response_ts.second_low + follow_up_ts.second_low) / 2;
213     expected_time.nanosecond = (delay_response_ts.nanosecond + follow_up_ts.nanosecond) / 2;
214 
215     /* Create the PTP client instance */
216     status = nx_ptp_client_create(&ptp_client, &ip_0, 0, &pool_0,
217                                   2, ptp_stack, sizeof(ptp_stack),
218                                   nx_ptp_client_soft_clock_callback, NX_NULL);
219     ASSERT_SUCCESS(status);
220 
221     /* Set timestamp to all zero.  */
222     status = nx_ptp_client_time_set(&ptp_client, &ts_zero);
223     ASSERT_SUCCESS(status);
224 
225     /* start the PTP client */
226     status = nx_ptp_client_start(&ptp_client, NX_NULL, 0, 0, 0, ptp_event_callback, NX_NULL);
227     ASSERT_SUCCESS(status);
228 
229     /* Sleep 5 seconds for sync up. */
230     tx_thread_sleep(5 * NX_IP_PERIODIC_RATE);
231 
232     /* Compare synced time. */
233     ASSERT_TRUE(synced_utc_offset == expected_utc_offset);
234 
235     /* Set timestamp to all zero when PTP already started.  */
236     status = nx_ptp_client_time_set(&ptp_client, &ts_zero);
237     ASSERT_TRUE(status == NX_PTP_CLIENT_ALREADY_STARTED);
238 
239     /* Diff time.  */
240     status = nx_ptp_client_utility_time_diff(&synced_time, &expected_time, &ts_diff);
241     ASSERT_SUCCESS(status);
242     ASSERT_TRUE(ts_diff.second_high == 0);
243     ASSERT_TRUE(ts_diff.second_low == 0);
244     ASSERT_TRUE(ts_diff.nanosecond / 1000000 <= 1000 / NX_PTP_CLIENT_TIMER_TICKS_PER_SECOND);
245 
246     /* Cleanup */
247     status = nx_ptp_client_stop(&ptp_client);
248     ASSERT_SUCCESS(status);
249 
250     status = nx_ptp_client_delete(&ptp_client);
251     ASSERT_SUCCESS(status);
252 
253     printf("SUCCESS!\n");
254     test_control_return(0);
255 }
256 
257 /* This thread acts as PTP server, accepting the connection. */
ntest_1_entry(ULONG thread_input)258 static void    ntest_1_entry(ULONG thread_input)
259 {
260 DELAY_REQUEST_CONTEXT context;
261 UINT status;
262 
263     create_socket(&ip_1, &generic_socket, PTP_GENERAL_UDP_PORT);
264     create_socket(&ip_1, &event_socket, PTP_EVENT_UDP_PORT);
265 
266     /* Sleep 1 second to wait for PTP thread running. */
267     tx_thread_sleep(1 * NX_IP_PERIODIC_RATE);
268 
269     /* Send announce.  */
270     send_announce(&generic_socket, &pool_0, expected_utc_offset);
271 
272     /* Send sync.  */
273     send_sync(&event_socket, &pool_0, &sync_ts);
274 
275     /* Send follow up.  */
276     send_follow_up(&generic_socket, &pool_0, &follow_up_ts);
277 
278     /* Wait for delay request.  */
279     status = receive_delay_request(&event_socket, &context, NX_WAIT_FOREVER);
280     ASSERT_SUCCESS(status);
281 
282     /* Send delay response.  */
283     send_delay_response(&generic_socket, &pool_0, &context, &delay_response_ts);
284 }