pps_example.c Source File

Reference Documentation

Platform
Intel® PAC
Napatech SmartNIC
Content Type
Reference Information
Capture Software Version
Link™ Capture Software 12.10
Napatech Software Suite: examples/pps/pps_example.c Source File
pps_example.c
Go to the documentation of this file.
1 /*
2  *
3  * Copyright 2023 Napatech A/S. All Rights Reserved.
4  *
5  * 1. Copying, modification, and distribution of this file, or executable
6  * versions of this file, is governed by the terms of the Napatech Software
7  * license agreement under which this file was made available. If you do not
8  * agree to the terms of the license do not install, copy, access or
9  * otherwise use this file.
10  *
11  * 2. Under the Napatech Software license agreement you are granted a
12  * limited, non-exclusive, non-assignable, copyright license to copy, modify
13  * and distribute this file in conjunction with Napatech SmartNIC's and
14  * similar hardware manufactured or supplied by Napatech A/S.
15  *
16  * 3. The full Napatech Software license agreement is included in this
17  * distribution, please see "NP-0405 Napatech Software license
18  * agreement.pdf"
19  *
20  * 4. Redistributions of source code must retain this copyright notice,
21  * list of conditions and the following disclaimer.
22  *
23  * THIS SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTIES, EXPRESS OR
24  * IMPLIED, AND NAPATECH DISCLAIMS ALL IMPLIED WARRANTIES INCLUDING ANY
25  * IMPLIED WARRANTY OF TITLE, MERCHANTABILITY, NONINFRINGEMENT, OR OF
26  * FITNESS FOR A PARTICULAR PURPOSE. TO THE EXTENT NOT PROHIBITED BY
27  * APPLICABLE LAW, IN NO EVENT SHALL NAPATECH BE LIABLE FOR PERSONAL INJURY,
28  * OR ANY INCIDENTAL, SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES WHATSOEVER,
29  * INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS OF PROFITS, CORRUPTION OR
30  * LOSS OF DATA, FAILURE TO TRANSMIT OR RECEIVE ANY DATA OR INFORMATION,
31  * BUSINESS INTERRUPTION OR ANY OTHER COMMERCIAL DAMAGES OR LOSSES, ARISING
32  * OUT OF OR RELATED TO YOUR USE OR INABILITY TO USE NAPATECH SOFTWARE OR
33  * SERVICES OR ANY THIRD PARTY SOFTWARE OR APPLICATIONS IN CONJUNCTION WITH
34  * THE NAPATECH SOFTWARE OR SERVICES, HOWEVER CAUSED, REGARDLESS OF THE THEORY
35  * OF LIABILITY (CONTRACT, TORT OR OTHERWISE) AND EVEN IF NAPATECH HAS BEEN
36  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. SOME JURISDICTIONS DO NOT ALLOW
37  * THE EXCLUSION OR LIMITATION OF LIABILITY FOR PERSONAL INJURY, OR OF
38  * INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO THIS LIMITATION MAY NOT APPLY TO YOU.
39  *
40  *
41 
42  */
43 
44 /**
45  * @example pps/pps_example.c
46  * @section pps_example_description Description
47  *
48  * This source file is an example of how to use the PPS functionality.
49  *
50  * The following NTAPI functions are used:
51  * - @ref NT_Init()
52  * - @ref NT_ConfigOpen()
53  * - @ref NT_ConfigWrite()
54  * - @ref NT_ConfigRead()
55  * - @ref NT_ConfigClose()
56  * - @ref NT_ExplainError()
57  *
58  * <hr>
59  * @section pps_example_prerequisites Prerequisites
60  * A working system is needed.
61  *
62  * @section pps_example_flow Program flow
63  * @{
64  * The following is required to perform read and write operations on
65  * the @ref ConfigStream "configuration stream":
66  * - \#include/nt.h - Applications/Tools only need to include @ref
67  * nt.h to obtain prototypes, macros etc. from NTAPI.
68  * - @ref NT_Init(@ref NTAPI_VERSION) - Initialize the NTAPI
69  * library. @ref NTAPI_VERSION is a define that describes the version
70  * of the API described in the header files included by @ref
71  * nt.h. NT_Init() will ask the NTAPI library to convert return data
72  * to the @ref NTAPI_VERSION if possible. This will ensure that
73  * applications can run on NTAPI libraries of newer versions.
74  * - @ref NT_ConfigOpen() - Open a configuration stream.
75  * - @ref NT_ConfigRead() - Read configuration.
76  * - @ref NT_ConfigWrite() - Write configuration.
77  * - @ref NT_ConfigClose() - Close the stream when terminating.
78  *
79  *<hr>
80  * @}
81  */
82 
83 // Include this in order to access the Napatech API
84 #include <nt.h>
85 
86 #if defined(__linux__) || defined(__FreeBSD__)
87  #include <signal.h>
88  #include <sys/time.h>
89  #include <unistd.h> // sleep()
90 #elif defined(WIN32) || defined (WIN64)
91  #include <winsock2.h>
92  #include <sys/timeb.h>
93 #endif
94 #include <time.h>
95 
96 #define MAX_TS_CARDS 4
97 
98 typedef struct TimeSync_s{
99  unsigned timeSyncEnabled;
101 } TimeSync_t;
102 
104 
105 
106 int stopApplication=0; /* Flag to signal that application should stop. */
107 
108 
109 #if defined(WIN32) || defined (WIN64)
110 
111 #if defined(_MSC_VER)
112  struct timezone {
113  int tz_minuteswest; /* minutes west of Greenwich */
114  int tz_dsttime; /* type of DST correction */
115  };
116 #endif // _MSC_VER
117 
118  int gettimeofday(struct timeval *tv, struct timezone *tz);
119 
120 #endif
121 
122 
123 #define NT_CONST64(a) a##ULL
124 #define UNIX_EPOCH_OFFSET_MAGIC 116444736000000000ULL
125 
126 /**
127  * 32bit struct timeval. Used because our HW is only 32bit PCAP compatible
128  */
129 struct nttimeval
130 {
131  uint32_t tv_sec;
132  uint32_t tv_usec;
133 };
134 
135 // Forward declarations
136 int PpsGetOsTime(uint64_t *osTime);
137 int PrintTimestamp(uint64_t timeValue);
138 int PpsPrintStatusAndTime(int i, uint64_t timeSyncPpsSampled, int64_t timeSyncTimeSkew);
139 
140 
141 /*
142  * The function called when user is pressing CTRL-C
143  */
144 #if defined(WIN32) || defined (WIN64)
145 static BOOL WINAPI StopApplication(int sig)
146 #else
147 static void StopApplication(int sig)
148 #endif
149 {
150  printf("Stopping application (%d)\n", sig);
151 #ifdef WIN32
152  stopApplication = 1;
153  return TRUE;
154 #else
155  if (sig == SIGINT)
156  stopApplication = 1;
157 #endif
158 }
159 
160 
161 /* This function returns the OS time in seconds.
162  * ----------------------------------------------------------------------*/
163 int /* Ret Result. */
164 PpsGetOsTime(uint64_t *osTime) /* Seconds since 1. jan 1970. */
165 {
166  struct timeval timeofday;
167  struct timezone timeZone;
168  int result;
169 
170  result = gettimeofday(&timeofday, &timeZone);
171 
172  *osTime = (uint64_t)(timeofday.tv_sec & 0xFFFFFFFF);
173  return result;
174 }
175 
176 
177 
178 int PrintTimestamp(uint64_t timeValue)
179 {
180  time_t timeT;
181  struct tm *ptm;
182  char wday[7][4]={"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
183  char wmon[12][4]={"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
184 
185  timeT = (time_t)(timeValue/1000000000ULL);
186  ptm = gmtime(&timeT);
187  if (ptm == NULL) {
188  printf("Time is invalid");
189  } else {
190  printf("UTC Time : %s %d-%s-%d %02d:%02d:%02d.%09lld",
191  wday[ptm->tm_wday], ptm->tm_mday, wmon[ptm->tm_mon], ptm->tm_year+1900,
192  ptm->tm_hour, ptm->tm_min, ptm->tm_sec, ((unsigned long long)timeValue%100000000));
193  }
194  return 0;
195 }
196 
197 
198 int PpsPrintStatusAndTime(int i, uint64_t timeSyncPpsSampled, int64_t timeSyncTimeSkew)
199 {
200  /* Check if more than 100 milli seconds off and conclude loss of SYNC */
201  if ((timeSyncTimeSkew < -100000000) ||
202  (timeSyncTimeSkew > 100000000)) {
203  printf("%d: PPS not in SYNC: ", i);
204  } else {
205  /* Check if more than 1 milli second off and conclude trying to SYNC */
206  if ((timeSyncTimeSkew < -1000000) ||
207  (timeSyncTimeSkew > 1000000)) {
208  printf("%d PPS SYNCING: ", i);
209  } else {
210  /* Less than 1 milli second off, conclude it's in SYNC */
211  printf("%d PPS in SYNC: ", i);
212  }
213  }
214 
215  PrintTimestamp(timeSyncPpsSampled);
216  printf(" ClockSkew : %13lld nano seconds \n", (long long)(timeSyncTimeSkew));
217  return 0;
218 }
219 
220 
221 int main(void)
222 {
223  int i;
224  int32_t status;
225  int timeout = 1000;
226  uint64_t osTime;
227  uint64_t helpTime;
228  uint64_t printTime=0;
229  NtInfoStream_t hInfoStream; // Info stream handle
230  NtEventStream_t hEventStream;
231  NtConfigStream_t hConfigStream;
232  NtInfo_t hInfo; // Info handle
233  NtEvent_t hEvent;
234  NtConfig_t configInfo;
236  int numAdapters=0;
237  int found=0;
238 
239 // Set up ctrl+c handler
240 #if defined(WIN32) || defined (WIN64)
241  SetConsoleCtrlHandler((PHANDLER_ROUTINE)StopApplication, TRUE);
242 #else
243  struct sigaction newaction; // Ctrl+c handle
244  memset(&newaction, 0, sizeof(newaction));
245  newaction.sa_handler = StopApplication;
246  if (sigaction(SIGINT, &newaction, NULL) < 0) {
247  fprintf(stderr, "Failed to register sigaction.\n");
248  return -1;
249  }
250 #endif
251 
252  printf("Running the PPS example.\n\n");
253 
254  if ((status = NT_Init(NTAPI_VERSION)) != NT_SUCCESS) {
255  // Get the status code as text
256  NT_ExplainError(status, errorBuffer, sizeof(errorBuffer));
257  fprintf(stderr, "NT_Init() failed: %s\n", errorBuffer);
258  return -1;
259  }
260 
261  /* Init local variables */
262  for (i=0;i<MAX_TS_CARDS;i++) {
264  }
265 
266  printf("Opening info stream\n");
267  /* Open the info stream */
268  if ((status = NT_InfoOpen(&hInfoStream, "InfoPps")) != NT_SUCCESS) {
269  // Get the status code as text
270  NT_ExplainError(status, errorBuffer, sizeof(errorBuffer));
271  fprintf(stderr, "NT_ConfigRead() failed: %s\n", errorBuffer);
272  return -1;
273  }
274  printf("Info stream opened successfully\n");
275 
276  /* Read number of adapters */
278  if ((status = NT_InfoRead(hInfoStream, &hInfo)) != 0) {
279  // Get the status code as text
280  NT_ExplainError(status, errorBuffer, sizeof(errorBuffer));
281  fprintf(stderr, "NT_ConfigRead() failed: %s\n", errorBuffer);
282  return -1;
283  }
284 
285  numAdapters = hInfo.u.system.data.numAdapters;
286 
287  printf("Found %d adapters\n", numAdapters);
288 
289  for (i=0;i<numAdapters;i++) {
290  /* Read timesync info */
292  hInfo.u.timeSync_v4.adapterNo = (uint8_t)i;
293  if ((status = NT_InfoRead(hInfoStream, &hInfo)) != NT_SUCCESS) {
294  // Get the status code as text
295  NT_ExplainError(status, errorBuffer, sizeof(errorBuffer));
296  fprintf(stderr, "Failed to read timesync info: %s\n", errorBuffer);
297  return -1;
298  }
299 
300  /* Print timesync info */
301  printf("Adapter %d:\n", i);
302  printf(" TimeSync reference priority: %d, %d, %d\n", hInfo.u.timeSync_v4.data.tsRefPrio[0],
303  hInfo.u.timeSync_v4.data.tsRefPrio[1], hInfo.u.timeSync_v4.data.tsRefPrio[2]);
304  printf(" TimeSync reference: %d\n", hInfo.u.timeSync_v4.data.timeRef);
305  printf(" TimeSync connector Ext1: %d\n", hInfo.u.timeSync_v4.data.timeSyncConnectorExt1);
306  printf(" TimeSync connector Int1: %d\n", hInfo.u.timeSync_v4.data.timeSyncConnectorInt1);
307  printf(" TimeSync connector Int2: %d\n", hInfo.u.timeSync_v4.data.timeSyncConnectorInt2);
309  printf(" TimeSync Time Jump (s): %d\n", hInfo.u.timeSync_v4.data.timeSyncTimeJumpThreshold);
310  } else {
311  printf(" TimeSync Time Jump Allowed : %d\n", hInfo.u.timeSync_v4.data.timeSyncHardReset);
312  }
313  printf(" TimeSync Time Offset (ns): %d\n\n", hInfo.u.timeSync_v4.data.timeSyncTimeOffset);
314 
315  // Check if the adapter is configured for PPS
322  found = 1;
323  TS_os[i].timeSyncEnabled = 1;
324 
325  // Read the Timestamp type from the adapter
327  hInfo.u.adapter_v6.adapterNo = (uint8_t) i;
328  if ((status = NT_InfoRead(hInfoStream, &hInfo)) != NT_SUCCESS) {
329  // Get the status code as text
330  NT_ExplainError(status, errorBuffer, sizeof(errorBuffer));
331  fprintf(stderr, "NT_InfoRead() failed: %s\n", errorBuffer);
332  return -1;
333  }
334 
335  // Check that Timestamp type is set to Native UNIX
337  fprintf(stderr, "Timestamp should be Native UNIX, please configure in the Ntservice.ini file.\n");
338  return -1;
339  }
340  }
341  }
342 
343  if (found == 0) {
344  fprintf(stderr, "No PPS Enabled adapters found! Please configure PPS in ntservice.ini\n");
345  return -1;
346  }
347 
348  /* Open the event stream */
349  if ((status = NT_EventOpen(&hEventStream, "PpsEvent", NT_EVENT_SOURCE_TIMESYNC)) != NT_SUCCESS) {
350  // Get the status code as text
351  NT_ExplainError(status, errorBuffer, sizeof(errorBuffer));
352  fprintf(stderr, "NT_EventOpen() failed: %s\n", errorBuffer);
353  return -1;
354  }
355 
356  // Open the config stream
357  if ((status = NT_ConfigOpen(&hConfigStream, "CONFIG"))) {
358  // Get the status code as text
359  NT_ExplainError(status, errorBuffer, sizeof(errorBuffer));
360  fprintf(stderr, "NT_ConfigOpen() failed: %s\n", errorBuffer);
361  return -1;
362  }
363 
364  // Enable PPS
365  for (i=0;i<numAdapters;i++) {
366  if (TS_os[i].timeSyncEnabled == 1) {
368  configInfo.u.timesyncWrite.adapter = (uint8_t) i;
370 
371  /* Set Initial PPS time */
372  PpsGetOsTime(&osTime);
373  configInfo.u.timesyncWrite.data.refTime = osTime;
374 
375  if ((status = NT_ConfigWrite(hConfigStream, &configInfo)) != NT_SUCCESS) {
376  // Get the status code as text
377  NT_ExplainError(status, errorBuffer, sizeof(errorBuffer));
378  fprintf(stderr, "NT_ConfigWrite() failed: %s\n", errorBuffer);
379  return -1;
380  }
381  }
382  }
383 
384  fprintf(stderr, "PPS example starting in 5 seconds\n");
385  // Sleep 5 sec
386 #if defined(__linux__) || defined(__FreeBSD__)
387  sleep(5);
388 #elif defined(WIN32) || defined (WIN64)
389  Sleep(5000); // sleep 5000 milliseconds = 5 second
390 #endif
391 
392 #if defined(WIN32) || defined (WIN64)
393  /* Clear screen */
394  if (system("cls")==0) {
395  // Avoid compiler warning
396  }
397 #else
398  /* Clear screen */
399  if (system("clear")==0) {
400  // Avoid compiler warning
401  }
402 #endif
403  printf("PPS Example running (press CTRL-C to exit)\n");
404 
405  while (stopApplication == 0) {
406 
407  status = NT_EventRead(hEventStream, &hEvent, timeout);
408  if (status == NT_STATUS_TIMEOUT) {
409  // Timeout try again
410  } else {
411  if (status != NT_SUCCESS) {
412  // Get the status code as text
413  NT_ExplainError(status, errorBuffer, sizeof(errorBuffer));
414  fprintf(stderr, "NT_EventRead() failed: %s\n", errorBuffer);
415  return -1;
416  }
417 
418  // Handle event
419  if (hEvent.type == NT_EVENT_SOURCE_TIMESYNC) {
421  // Send PPS Reference Time
423  configInfo.u.timesyncWrite.adapter = hEvent.u.timeSyncEvent.adapter;
425 
426  /* Set PPS Reference Time */
427  PpsGetOsTime(&osTime);
428  configInfo.u.timesyncWrite.data.refTime = osTime;
429 
430  if ((status = NT_ConfigWrite(hConfigStream, &configInfo)) != NT_SUCCESS) {
431  // Get the status code as text
432  NT_ExplainError(status, errorBuffer, sizeof(errorBuffer));
433  fprintf(stderr, "NT_ConfigWrite() failed: %s\n", errorBuffer);
434  return -1;
435  }
436  }
437  }
438  }
439  PpsGetOsTime(&helpTime);
440  if (helpTime != printTime) {
441  printTime=helpTime;
442 
443 #if defined(WIN32) || defined (WIN64)
444  /* Clear screen */
445  if (system("cls")==0) {
446  // Avoid compiler warning
447  }
448 #else
449  /* Clear screen */
450  if (system("clear")==0) {
451  // Avoid compiler warning
452  }
453 #endif
454 
455  /* Read timesync info */
456  for (i=0;i<numAdapters;i++) {
457  if (TS_os[i].timeSyncEnabled == 1) {
458  /* Read timesync info */
460  hInfo.u.timeSync_v4.adapterNo = (uint8_t) i;
461  if ((status = NT_InfoRead(hInfoStream, &hInfo)) != NT_SUCCESS) {
462  // Get the status code as text
463  NT_ExplainError(status, errorBuffer, sizeof(errorBuffer));
464  fprintf(stderr, "Failed to read timesync info: %s\n", errorBuffer);
465  return -1;
466  }
470  }
471  printf("PPS signal lost on adapter %d\n", i);
472  } else
476  }
477  printf("PPS signal found on adapter %d\n", i);
478  /* Print timesync info */
480  }
481  }
482  }
483  }
484  }
485 
486  // Disable PPS
487  for (i=0;i<numAdapters;i++) {
488  if (TS_os[i].timeSyncEnabled == 1) {
490  configInfo.u.timesyncWrite.adapter = (uint8_t)i;
492  configInfo.u.timesyncWrite.data.refTime = 0;
493 
494  if ((status = NT_ConfigWrite(hConfigStream, &configInfo)) != NT_SUCCESS) {
495  // Get the status code as text
496  NT_ExplainError(status, errorBuffer, sizeof(errorBuffer));
497  fprintf(stderr, "NT_ConfigWrite() failed: %s\n", errorBuffer);
498  return -1;
499  }
500  }
501  }
502 
503  // Close the configuration stream
504  if ((status = NT_ConfigClose(hConfigStream)) != NT_SUCCESS) {
505  // Get the status code as text
506  NT_ExplainError(status, errorBuffer, sizeof(errorBuffer));
507  fprintf(stderr, "NT_ConfigClose() failed: %s\n", errorBuffer);
508  return -1;
509  }
510 
511  // Close the event stream
512  if ((status = NT_EventClose(hEventStream)) != NT_SUCCESS) {
513  // Get the status code as text
514  NT_ExplainError(status, errorBuffer, sizeof(errorBuffer));
515  fprintf(stderr, "NT_EventClose() failed: %s\n", errorBuffer);
516  return -1;
517  }
518 
519  /* Close the info stream */
520  if ((status = NT_InfoClose(hInfoStream)) != NT_SUCCESS) {
521  // Get the status code as text
522  NT_ExplainError(status, errorBuffer, sizeof(errorBuffer));
523  fprintf(stderr, "NT_InfoClose() failed: %s\n", errorBuffer);
524  return -1;
525  }
526 
527  printf("Streams closed\n");
528  return 0;
529 }