pps_example.c

Reference Documentation

product_line_custom
Napatech SmartNIC
category
Reference Information

Go to the documentation of this file.

1/* 2 * %NT_SOFTWARE_LICENSE% 3 */ 4 5/** 6 * @example pps/pps_example.c 7 * @section pps_example_description Description 8 * 9 * This source file is an example of how to use the PPS functionality. 10 * 11 * The following NTAPI functions are used: 12 * - @ref NT_Init() 13 * - @ref NT_ConfigOpen() 14 * - @ref NT_ConfigWrite() 15 * - @ref NT_ConfigRead() 16 * - @ref NT_ConfigClose() 17 * - @ref NT_ExplainError() 18 * 19 * <hr> 20 * @section pps_example_prerequisites Prerequisites 21 * A working system is needed. 22 * 23 * @section pps_example_flow Program flow 24 * @{ 25 * The following is required to perform read and write operations on 26 * the @ref ConfigStream "configuration stream": 27 * - \#include/nt.h - Applications/Tools only need to include @ref 28 * nt.h to obtain prototypes, macros etc. from NTAPI. 29 * - @ref NT_Init(@ref NTAPI_VERSION) - Initialize the NTAPI 30 * library. @ref NTAPI_VERSION is a define that describes the version 31 * of the API described in the header files included by @ref 32 * nt.h. NT_Init() will ask the NTAPI library to convert return data 33 * to the @ref NTAPI_VERSION if possible. This will ensure that 34 * applications can run on NTAPI libraries of newer versions. 35 * - @ref NT_ConfigOpen() - Open a configuration stream. 36 * - @ref NT_ConfigRead() - Read configuration. 37 * - @ref NT_ConfigWrite() - Write configuration. 38 * - @ref NT_ConfigClose() - Close the stream when terminating. 39 * 40 *<hr> 41 * @} 42 */ 43 44 45#if defined(__linux__) || defined(__FreeBSD__) 46 #include <signal.h> 47 #include <sys/time.h> 48 #include <unistd.h> // sleep() 49 #include <time.h> 50#elif defined(WIN32) || defined (WIN64) 51 #include <winsock2.h> 52 #include <time.h> 53 #include <sys/timeb.h> 54#endif 55 56#include "nt.h" 57 58#define MAX_TS_CARDS 4 59 60typedef struct TimeSync_s{ 61 unsigned timeSyncEnabled; 62 unsigned timeSyncConStatus; 63} TimeSync_t; 64 65TimeSync_t TS_os[MAX_TS_CARDS]; 66 67 68int stopApplication=0; /* Flag to signal that application should stop. */ 69 70 71#if defined(WIN32) || defined (WIN64) 72 struct timezone { 73 int tz_minuteswest; /* minutes west of Greenwich */ 74 int tz_dsttime; /* type of DST correction */ 75 }; 76 77 int gettimeofday(struct timeval *tv, struct timezone *tz) 78 { 79 struct __timeb64 timebuffer; 80 _ftime64_s(&timebuffer); 81 tv->tv_sec = (long)timebuffer.time; 82 tv->tv_usec = timebuffer.millitm * 1000; 83 return 0; 84 } 85#endif 86 87 88#define NT_CONST64(a) a##ULL 89#define UNIX_EPOCH_OFFSET_MAGIC 116444736000000000ULL 90 91/** 92 * 32bit struct timeval. Used because our HW is only 32bit PCAP compatible 93 */ 94struct nttimeval 95{ 96 uint32_t tv_sec; 97 uint32_t tv_usec; 98}; 99 100// Forward declarations 101int PpsGetOsTime(uint64_t *osTime); 102int PrintTimestamp(uint64_t timeValue); 103int PpsPrintStatusAndTime(int i, uint64_t timeSyncPpsSampled, int64_t timeSyncTimeSkew); 104 105 106/* 107 * The function called when user is pressing CTRL-C 108 */ 109#if defined(WIN32) || defined (WIN64) 110static BOOL WINAPI StopApplication(int sig) 111#else 112static void StopApplication(int sig) 113#endif 114{ 115 printf("Stopping application (%d)\n", sig); 116#ifdef WIN32 117 stopApplication = 1; 118 return TRUE; 119#else 120 if (sig == SIGINT) 121 stopApplication = 1; 122#endif 123} 124 125 126/* This function returns the OS time in seconds. 127 * ----------------------------------------------------------------------*/ 128int /* Ret Result. */ 129PpsGetOsTime(uint64_t *osTime) /* Seconds since 1. jan 1970. */ 130{ 131 struct timeval timeofday; 132 struct timezone timeZone; 133 int result; 134 135 result = gettimeofday(&timeofday, &timeZone); 136 137 *osTime = (uint64_t)(timeofday.tv_sec & 0xFFFFFFFF); 138 return result; 139} 140 141 142 143int PrintTimestamp(uint64_t timeValue) 144{ 145 time_t timeT; 146 struct tm *ptm; 147 char wday[7][4]={"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"}; 148 char wmon[12][4]={"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"}; 149 150 timeT = (time_t)(timeValue/1000000000ULL); 151 ptm = gmtime(&timeT); 152 if (ptm == NULL) { 153 printf("Time is invalid"); 154 } else { 155 printf("UTC Time : %s %d-%s-%d %02d:%02d:%02d.%09lld", 156 wday[ptm->tm_wday], ptm->tm_mday, wmon[ptm->tm_mon], ptm->tm_year+1900, 157 ptm->tm_hour, ptm->tm_min, ptm->tm_sec, ((unsigned long long)timeValue%100000000)); 158 } 159 return 0; 160} 161 162 163int PpsPrintStatusAndTime(int i, uint64_t timeSyncPpsSampled, int64_t timeSyncTimeSkew) 164{ 165 /* Check if more than 100 milli seconds off and conclude loss of SYNC */ 166 if ((timeSyncTimeSkew < -100000000) || 167 (timeSyncTimeSkew > 100000000)) { 168 printf("%d: PPS not in SYNC: ", i); 169 } else { 170 /* Check if more than 1 milli second off and conclude trying to SYNC */ 171 if ((timeSyncTimeSkew < -1000000) || 172 (timeSyncTimeSkew > 1000000)) { 173 printf("%d PPS SYNCING: ", i); 174 } else { 175 /* Less than 1 milli second off, conclude it's in SYNC */ 176 printf("%d PPS in SYNC: ", i); 177 } 178 } 179 180 PrintTimestamp(timeSyncPpsSampled); 181 printf(" ClockSkew : %13lld nano seconds \n", (long long)(timeSyncTimeSkew)); 182 return 0; 183} 184 185 186int main(void) 187{ 188 int i; 189 int32_t status; 190 int timeout = 1000; 191 uint64_t osTime; 192 uint64_t helpTime; 193 uint64_t printTime=0; 194 NtInfoStream_t hInfoStream; // Info stream handle 195 NtEventStream_t hEventStream; 196 NtConfigStream_t hConfigStream; 197 NtInfo_t hInfo; // Info handle 198 NtEvent_t hEvent; 199 NtConfig_t configInfo; 200 char errorBuffer[NT_ERRBUF_SIZE]; 201 int numAdapters=0; 202 int found=0; 203 204// Set up ctrl+c handler 205#if defined(WIN32) || defined (WIN64) 206 SetConsoleCtrlHandler((PHANDLER_ROUTINE)StopApplication, TRUE); 207#else 208 struct sigaction newaction; // Ctrl+c handle 209 memset(&newaction, 0, sizeof(newaction)); 210 newaction.sa_handler = StopApplication; 211 if (sigaction(SIGINT, &newaction, NULL) < 0) { 212 fprintf(stderr, "Failed to register sigaction.\n"); 213 return -1; 214 } 215#endif 216 217 printf("Running the PPS example.\n\n"); 218 219 if ((status = NT_Init(NTAPI_VERSION)) != NT_SUCCESS) { 220 // Get the status code as text 221 NT_ExplainError(status, errorBuffer, sizeof(errorBuffer)); 222 fprintf(stderr, "NT_ConfigRead() failed: %s\n", errorBuffer); 223 return -1; 224 } 225 226 /* Init local variables */ 227 for (i=0;i<MAX_TS_CARDS;i++) { 228 TS_os[i].timeSyncConStatus = NT_TIMESYNC_CONNECTOR_STATUS_NONE; 229 } 230 231 printf("Opening info stream\n"); 232 /* Open the info stream */ 233 if ((status = NT_InfoOpen(&hInfoStream, "InfoPps")) != NT_SUCCESS) { 234 // Get the status code as text 235 NT_ExplainError(status, errorBuffer, sizeof(errorBuffer)); 236 fprintf(stderr, "NT_ConfigRead() failed: %s\n", errorBuffer); 237 return -1; 238 } 239 printf("Info stream opened successfully\n"); 240 241 /* Read number of adapters */ 242 hInfo.cmd=NT_INFO_CMD_READ_SYSTEM; 243 if((status = NT_InfoRead(hInfoStream, &hInfo)) != 0) { 244 // Get the status code as text 245 NT_ExplainError(status, errorBuffer, sizeof(errorBuffer)); 246 fprintf(stderr, "NT_ConfigRead() failed: %s\n", errorBuffer); 247 return -1; 248 } 249 250 numAdapters = hInfo.u.system.data.numAdapters; 251 252 printf("Found %d adapters\n", numAdapters); 253 254 for (i=0;i<numAdapters;i++) { 255 /* Read timesync info */ 256 hInfo.cmd=NT_INFO_CMD_READ_TIMESYNC_V4; 257 hInfo.u.adapter_v6.adapterNo = (uint8_t) i; 258 if ((status = NT_InfoRead(hInfoStream, &hInfo)) != NT_SUCCESS) { 259 fprintf(stderr, "Failed to read timesync info.\n"); 260 return -1; 261 } 262 263 /* Print timesync info */ 264 printf("Adapter %d:\n", i); 265 printf(" TimeSync reference priority: %d, %d, %d\n", hInfo.u.timeSync_v4.data.tsRefPrio[0], 266 hInfo.u.timeSync_v4.data.tsRefPrio[1], hInfo.u.timeSync_v4.data.tsRefPrio[2]); 267 printf(" TimeSync reference: %d\n", hInfo.u.timeSync_v4.data.timeRef); 268 printf(" TimeSync connector Ext1: %d\n", hInfo.u.timeSync_v4.data.timeSyncConnectorExt1); 269 printf(" TimeSync connector Int1: %d\n", hInfo.u.timeSync_v4.data.timeSyncConnectorInt1); 270 printf(" TimeSync connector Int2: %d\n", hInfo.u.timeSync_v4.data.timeSyncConnectorInt2); 271 if (hInfo.u.timeSync_v4.data.timeSyncClockAdjustmentMode == 1) { 272 printf(" TimeSync Time Jump (s): %d\n", hInfo.u.timeSync_v4.data.timeSyncTimeJumpThreshold); 273 } else { 274 printf(" TimeSync Time Jump Allowed : %d\n", hInfo.u.timeSync_v4.data.timeSyncHardReset); 275 } 276 printf(" TimeSync Time Offset (ns): %d\n\n", hInfo.u.timeSync_v4.data.timeSyncTimeOffset); 277 278 // Check if the adapter is configured for PPS 279 if (((hInfo.u.timeSync_v4.data.tsRefPrio[0] == NT_TIMESYNC_REFERENCE_INT1) && 280 (hInfo.u.timeSync_v4.data.timeSyncConnectorInt1 == NT_TIMESYNC_CONNECTOR_SETTING_PPS_IN)) || 281 ((hInfo.u.timeSync_v4.data.tsRefPrio[0] == NT_TIMESYNC_REFERENCE_INT2) && 282 (hInfo.u.timeSync_v4.data.timeSyncConnectorInt2 == NT_TIMESYNC_CONNECTOR_SETTING_PPS_IN)) || 283 ((hInfo.u.timeSync_v4.data.tsRefPrio[0] == NT_TIMESYNC_REFERENCE_EXT1) && 284 (hInfo.u.timeSync_v4.data.timeSyncConnectorExt1 == NT_TIMESYNC_CONNECTOR_SETTING_PPS_IN))) { 285 found = 1; 286 TS_os[i].timeSyncEnabled = 1; 287 288 // Read the Timestamp type from the adapter 289 hInfo.cmd=NT_INFO_CMD_READ_ADAPTER_V6; 290 hInfo.u.adapter_v6.adapterNo = (uint8_t) i; 291 if((status = NT_InfoRead(hInfoStream, &hInfo)) != NT_SUCCESS) { 292 // Get the status code as text 293 NT_ExplainError(status, errorBuffer, sizeof(errorBuffer)); 294 fprintf(stderr, "NT_InfoRead() failed: %s\n", errorBuffer); 295 return -1; 296 } 297 298 // Check that Timestamp type is set to Native UNIX 299 if (hInfo.u.adapter_v6.data.timestampType != NT_TIMESTAMP_TYPE_NATIVE_UNIX) { 300 fprintf(stderr, "Timestamp should be Native UNIX, please configure in the Ntservice.ini file.\n"); 301 return -1; 302 } 303 } 304 } 305 306 if (found == 0) { 307 fprintf(stderr, "No PPS Enabled adapters found! Please configure PPS in ntservice.ini\n"); 308 return -1; 309 } 310 311 /* Open the event stream */ 312 if ((status = NT_EventOpen(&hEventStream, "PpsEvent", NT_EVENT_SOURCE_TIMESYNC)) != NT_SUCCESS) { 313 // Get the status code as text 314 NT_ExplainError(status, errorBuffer, sizeof(errorBuffer)); 315 fprintf(stderr, "NT_EventOpen() failed: %s\n", errorBuffer); 316 return -1; 317 } 318 319 // Open the config stream 320 if((status = NT_ConfigOpen(&hConfigStream, "CONFIG"))) { 321 // Get the status code as text 322 NT_ExplainError(status, errorBuffer, sizeof(errorBuffer)); 323 fprintf(stderr, "NT_ConfigOpen() failed: %s\n", errorBuffer); 324 return -1; 325 } 326 327 // Enable PPS 328 for (i=0;i<numAdapters;i++) { 329 if (TS_os[i].timeSyncEnabled == 1) { 330 configInfo.parm = NT_CONFIG_PARM_ADAPTER_TIMESYNC; 331 configInfo.u.timesyncWrite.adapter = (uint8_t) i; 332 configInfo.u.timesyncWrite.data.action = NT_TIMESYNC_PPS_ACTION_ENABLE; 333 334 /* Set Initial PPS time */ 335 PpsGetOsTime(&osTime); 336 configInfo.u.timesyncWrite.data.refTime = osTime; 337 338 if ((status = NT_ConfigWrite(hConfigStream, &configInfo)) != NT_SUCCESS) { 339 // Get the status code as text 340 NT_ExplainError(status, errorBuffer, sizeof(errorBuffer)); 341 fprintf(stderr, "NT_ConfigWrite() failed: %s\n", errorBuffer); 342 return -1; 343 } 344 } 345 } 346 347 fprintf(stderr, "PPS example starting in 5 seconds\n"); 348 // Sleep 5 sec 349#if defined(__linux__) || defined(__FreeBSD__) 350 sleep(5); 351#elif defined(WIN32) || defined (WIN64) 352 Sleep(5000); // sleep 5000 milliseconds = 5 second 353#endif 354 355#if defined(WIN32) || defined (WIN64) 356 /* Clear screen */ 357 if(system("cls")==0) { 358 // Avoid compiler warning 359 } 360#else 361 /* Clear screen */ 362 if(system("clear")==0) { 363 // Avoid compiler warning 364 } 365#endif 366 printf("PPS Example running (press CTRL-C to exit)\n"); 367 368 while (stopApplication == 0) { 369 370 status = NT_EventRead(hEventStream, &hEvent, timeout); 371 if (status == NT_STATUS_TIMEOUT) { 372 // Timeout try again 373 } else { 374 if (status != NT_SUCCESS) { 375 // Get the status code as text 376 NT_ExplainError(status, errorBuffer, sizeof(errorBuffer)); 377 fprintf(stderr, "NT_EventRead() failed: %s\n", errorBuffer); 378 return -1; 379 } 380 381 // Handle event 382 if (hEvent.type == NT_EVENT_SOURCE_TIMESYNC) { 383 if (hEvent.u.timeSyncEvent.action == NT_EVENT_TIMESYNC_PPS_REQUEST_TIME) { 384 // Send PPS Reference Time 385 configInfo.parm = NT_CONFIG_PARM_ADAPTER_TIMESYNC; 386 configInfo.u.timesyncWrite.adapter = hEvent.u.timeSyncEvent.adapter; 387 configInfo.u.timesyncWrite.data.action = NT_TIMESYNC_PPS_ACTION_REFERENCE_TIME; 388 389 /* Set PPS Reference Time */ 390 PpsGetOsTime(&osTime); 391 configInfo.u.timesyncWrite.data.refTime = osTime; 392 393 if ((status = NT_ConfigWrite(hConfigStream, &configInfo)) != NT_SUCCESS) { 394 // Get the status code as text 395 NT_ExplainError(status, errorBuffer, sizeof(errorBuffer)); 396 fprintf(stderr, "NT_ConfigWrite() failed: %s\n", errorBuffer); 397 return -1; 398 } 399 } 400 } 401 } 402 PpsGetOsTime(&helpTime); 403 if (helpTime != printTime) { 404 printTime=helpTime; 405 406#if defined(WIN32) || defined (WIN64) 407 /* Clear screen */ 408 if(system("cls")==0) { 409 // Avoid compiler warning 410 } 411#else 412 /* Clear screen */ 413 if(system("clear")==0) { 414 // Avoid compiler warning 415 } 416#endif 417 418 /* Read timesync info */ 419 for (i=0;i<numAdapters;i++) { 420 if (TS_os[i].timeSyncEnabled == 1) { 421 /* Read timesync info */ 422 hInfo.cmd=NT_INFO_CMD_READ_TIMESYNC_V4; 423 hInfo.u.timeSync_v4.adapterNo = (uint8_t) i; 424 if ((status = NT_InfoRead(hInfoStream, &hInfo)) != NT_SUCCESS) { 425 fprintf(stderr, "Failed to read timesync info.\n"); 426 return -1; 427 } 428 if (hInfo.u.timeSync_v4.data.timeSyncCurrentConStatus == NT_TIMESYNC_CONNECTOR_STATUS_SIGNAL_LOST) { 429 if (TS_os[i].timeSyncConStatus != NT_TIMESYNC_CONNECTOR_STATUS_SIGNAL_LOST) { 430 TS_os[i].timeSyncConStatus = NT_TIMESYNC_CONNECTOR_STATUS_SIGNAL_LOST; 431 } 432 printf("PPS signal lost on adapter %d\n", i); 433 } else 434 if (hInfo.u.timeSync_v4.data.timeSyncCurrentConStatus == NT_TIMESYNC_CONNECTOR_STATUS_SIGNAL_PRESENT) { 435 if (TS_os[i].timeSyncConStatus != NT_TIMESYNC_CONNECTOR_STATUS_SIGNAL_PRESENT) { 436 TS_os[i].timeSyncConStatus = NT_TIMESYNC_CONNECTOR_STATUS_SIGNAL_PRESENT; 437 } 438 printf("PPS signal found on adapter %d\n", i); 439 /* Print timesync info */ 440 PpsPrintStatusAndTime(i, hInfo.u.timeSync_v4.data.timeSyncPpsSampled, hInfo.u.timeSync_v4.data.timeSyncTimeSkew); 441 } 442 } 443 } 444 } 445 } 446 447 // Disable PPS 448 for (i=0;i<numAdapters;i++) { 449 if (TS_os[i].timeSyncEnabled == 1) { 450 configInfo.parm = NT_CONFIG_PARM_ADAPTER_TIMESYNC; 451 configInfo.u.timesyncWrite.adapter = (uint8_t)i; 452 configInfo.u.timesyncWrite.data.action = NT_TIMESYNC_PPS_ACTION_DISABLE; 453 configInfo.u.timesyncWrite.data.refTime = 0; 454 455 if ((status = NT_ConfigWrite(hConfigStream, &configInfo)) != NT_SUCCESS) { 456 // Get the status code as text 457 NT_ExplainError(status, errorBuffer, sizeof(errorBuffer)); 458 fprintf(stderr, "NT_ConfigWrite() failed: %s\n", errorBuffer); 459 return -1; 460 } 461 } 462 } 463 464 // Close the configuration stream 465 if ((status = NT_ConfigClose(hConfigStream)) != NT_SUCCESS) { 466 // Get the status code as text 467 NT_ExplainError(status, errorBuffer, sizeof(errorBuffer)); 468 fprintf(stderr, "NT_ConfigClose() failed: %s\n", errorBuffer); 469 return -1; 470 } 471 472 // Close the event stream 473 if ((status = NT_EventClose(hEventStream)) != NT_SUCCESS) { 474 // Get the status code as text 475 NT_ExplainError(status, errorBuffer, sizeof(errorBuffer)); 476 fprintf(stderr, "NT_EventClose() failed: %s\n", errorBuffer); 477 return -1; 478 } 479 480 /* Close the info stream */ 481 if ((status = NT_InfoClose(hInfoStream)) != NT_SUCCESS) { 482 // Get the status code as text 483 NT_ExplainError(status, errorBuffer, sizeof(errorBuffer)); 484 fprintf(stderr, "NT_InfoClose() failed: %s\n", errorBuffer); 485 return -1; 486 } 487 488 printf("Streams closed\n"); 489 return 0; 490}