pps/pps_example.c

Reference Documentation

product_line_custom
Napatech SmartNIC
category
Reference Information

Description

This source file is an example of how to use the PPS functionality.

Prerequisites

A working system is needed.

Program flow

The following is required to perform read and write operations on the configuration stream:
  • #include/nt.h - Applications/Tools only need to include nt.h to obtain prototypes, macros etc. from NTAPI.

  • NT_Init(NTAPI_VERSION) - Initialize the NTAPI library. NTAPI_VERSION is a define that describes the version of the API described in the header files included by nt.h. NT_Init() will ask the NTAPI library to convert return data to the NTAPI_VERSION if possible. This will ensure that applications can run on NTAPI libraries of newer versions.

  • NT_ConfigOpen() - Open a configuration stream.

  • NT_ConfigRead() - Read configuration.

  • NT_ConfigWrite() - Write configuration.

  • NT_ConfigClose() - Close the stream when terminating.

/* * %NT_SOFTWARE_LICENSE% */ /** * @example pps/pps_example.c * @section pps_example_description Description * * This source file is an example of how to use the PPS functionality. * * The following NTAPI functions are used: * - @ref NT_Init() * - @ref NT_ConfigOpen() * - @ref NT_ConfigWrite() * - @ref NT_ConfigRead() * - @ref NT_ConfigClose() * - @ref NT_ExplainError() * * <hr> * @section pps_example_prerequisites Prerequisites * A working system is needed. * * @section pps_example_flow Program flow * @{ * The following is required to perform read and write operations on * the @ref ConfigStream "configuration stream": * - \#include/nt.h - Applications/Tools only need to include @ref * nt.h to obtain prototypes, macros etc. from NTAPI. * - @ref NT_Init(@ref NTAPI_VERSION) - Initialize the NTAPI * library. @ref NTAPI_VERSION is a define that describes the version * of the API described in the header files included by @ref * nt.h. NT_Init() will ask the NTAPI library to convert return data * to the @ref NTAPI_VERSION if possible. This will ensure that * applications can run on NTAPI libraries of newer versions. * - @ref NT_ConfigOpen() - Open a configuration stream. * - @ref NT_ConfigRead() - Read configuration. * - @ref NT_ConfigWrite() - Write configuration. * - @ref NT_ConfigClose() - Close the stream when terminating. * *<hr> * @} */ #if defined(__linux__) || defined(__FreeBSD__) #include <signal.h> #include <sys/time.h> #include <unistd.h> // sleep() #include <time.h> #elif defined(WIN32) || defined (WIN64) #include <winsock2.h> #include <time.h> #include <sys/timeb.h> #endif #include "nt.h" #define MAX_TS_CARDS 4 typedef struct TimeSync_s{ unsigned timeSyncEnabled; unsigned timeSyncConStatus; } TimeSync_t; TimeSync_t TS_os[MAX_TS_CARDS]; int stopApplication=0; /* Flag to signal that application should stop. */ #if defined(WIN32) || defined (WIN64) struct timezone { int tz_minuteswest; /* minutes west of Greenwich */ int tz_dsttime; /* type of DST correction */ }; int gettimeofday(struct timeval *tv, struct timezone *tz) { struct __timeb64 timebuffer; _ftime64_s(&timebuffer); tv->tv_sec = (long)timebuffer.time; tv->tv_usec = timebuffer.millitm * 1000; return 0; } #endif #define NT_CONST64(a) a##ULL #define UNIX_EPOCH_OFFSET_MAGIC 116444736000000000ULL /** * 32bit struct timeval. Used because our HW is only 32bit PCAP compatible */ struct nttimeval { uint32_t tv_sec; uint32_t tv_usec; }; // Forward declarations int PpsGetOsTime(uint64_t *osTime); int PrintTimestamp(uint64_t timeValue); int PpsPrintStatusAndTime(int i, uint64_t timeSyncPpsSampled, int64_t timeSyncTimeSkew); /* * The function called when user is pressing CTRL-C */ #if defined(WIN32) || defined (WIN64) static BOOL WINAPI StopApplication(int sig) #else static void StopApplication(int sig) #endif { printf("Stopping application (%d)\n", sig); #ifdef WIN32 stopApplication = 1; return TRUE; #else if (sig == SIGINT) stopApplication = 1; #endif } /* This function returns the OS time in seconds. * ----------------------------------------------------------------------*/ int /* Ret Result. */ PpsGetOsTime(uint64_t *osTime) /* Seconds since 1. jan 1970. */ { struct timeval timeofday; struct timezone timeZone; int result; result = gettimeofday(&timeofday, &timeZone); *osTime = (uint64_t)(timeofday.tv_sec & 0xFFFFFFFF); return result; } int PrintTimestamp(uint64_t timeValue) { time_t timeT; struct tm *ptm; char wday[7][4]={"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"}; char wmon[12][4]={"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"}; timeT = (time_t)(timeValue/1000000000ULL); ptm = gmtime(&timeT); if (ptm == NULL) { printf("Time is invalid"); } else { printf("UTC Time : %s %d-%s-%d %02d:%02d:%02d.%09lld", wday[ptm->tm_wday], ptm->tm_mday, wmon[ptm->tm_mon], ptm->tm_year+1900, ptm->tm_hour, ptm->tm_min, ptm->tm_sec, ((unsigned long long)timeValue%100000000)); } return 0; } int PpsPrintStatusAndTime(int i, uint64_t timeSyncPpsSampled, int64_t timeSyncTimeSkew) { /* Check if more than 100 milli seconds off and conclude loss of SYNC */ if ((timeSyncTimeSkew < -100000000) || (timeSyncTimeSkew > 100000000)) { printf("%d: PPS not in SYNC: ", i); } else { /* Check if more than 1 milli second off and conclude trying to SYNC */ if ((timeSyncTimeSkew < -1000000) || (timeSyncTimeSkew > 1000000)) { printf("%d PPS SYNCING: ", i); } else { /* Less than 1 milli second off, conclude it's in SYNC */ printf("%d PPS in SYNC: ", i); } } PrintTimestamp(timeSyncPpsSampled); printf(" ClockSkew : %13lld nano seconds \n", (long long)(timeSyncTimeSkew)); return 0; } int main(void) { int i; int32_t status; int timeout = 1000; uint64_t osTime; uint64_t helpTime; uint64_t printTime=0; NtInfoStream_t hInfoStream; // Info stream handle NtEventStream_t hEventStream; NtConfigStream_t hConfigStream; NtInfo_t hInfo; // Info handle NtEvent_t hEvent; NtConfig_t configInfo; char errorBuffer[NT_ERRBUF_SIZE]; int numAdapters=0; int found=0; // Set up ctrl+c handler #if defined(WIN32) || defined (WIN64) SetConsoleCtrlHandler((PHANDLER_ROUTINE)StopApplication, TRUE); #else struct sigaction newaction; // Ctrl+c handle memset(&newaction, 0, sizeof(newaction)); newaction.sa_handler = StopApplication; if (sigaction(SIGINT, &newaction, NULL) < 0) { fprintf(stderr, "Failed to register sigaction.\n"); return -1; } #endif printf("Running the PPS example.\n\n"); if ((status = NT_Init(NTAPI_VERSION)) != NT_SUCCESS) { // Get the status code as text NT_ExplainError(status, errorBuffer, sizeof(errorBuffer)); fprintf(stderr, "NT_ConfigRead() failed: %s\n", errorBuffer); return -1; } /* Init local variables */ for (i=0;i<MAX_TS_CARDS;i++) { TS_os[i].timeSyncConStatus = NT_TIMESYNC_CONNECTOR_STATUS_NONE; } printf("Opening info stream\n"); /* Open the info stream */ if ((status = NT_InfoOpen(&hInfoStream, "InfoPps")) != NT_SUCCESS) { // Get the status code as text NT_ExplainError(status, errorBuffer, sizeof(errorBuffer)); fprintf(stderr, "NT_ConfigRead() failed: %s\n", errorBuffer); return -1; } printf("Info stream opened successfully\n"); /* Read number of adapters */ hInfo.cmd=NT_INFO_CMD_READ_SYSTEM; if((status = NT_InfoRead(hInfoStream, &hInfo)) != 0) { // Get the status code as text NT_ExplainError(status, errorBuffer, sizeof(errorBuffer)); fprintf(stderr, "NT_ConfigRead() failed: %s\n", errorBuffer); return -1; } numAdapters = hInfo.u.system.data.numAdapters; printf("Found %d adapters\n", numAdapters); for (i=0;i<numAdapters;i++) { /* Read timesync info */ hInfo.cmd=NT_INFO_CMD_READ_TIMESYNC_V4; hInfo.u.adapter_v6.adapterNo = (uint8_t) i; if ((status = NT_InfoRead(hInfoStream, &hInfo)) != NT_SUCCESS) { fprintf(stderr, "Failed to read timesync info.\n"); return -1; } /* Print timesync info */ printf("Adapter %d:\n", i); printf(" TimeSync reference priority: %d, %d, %d\n", hInfo.u.timeSync_v4.data.tsRefPrio[0], hInfo.u.timeSync_v4.data.tsRefPrio[1], hInfo.u.timeSync_v4.data.tsRefPrio[2]); printf(" TimeSync reference: %d\n", hInfo.u.timeSync_v4.data.timeRef); printf(" TimeSync connector Ext1: %d\n", hInfo.u.timeSync_v4.data.timeSyncConnectorExt1); printf(" TimeSync connector Int1: %d\n", hInfo.u.timeSync_v4.data.timeSyncConnectorInt1); printf(" TimeSync connector Int2: %d\n", hInfo.u.timeSync_v4.data.timeSyncConnectorInt2); if (hInfo.u.timeSync_v4.data.timeSyncClockAdjustmentMode == 1) { printf(" TimeSync Time Jump (s): %d\n", hInfo.u.timeSync_v4.data.timeSyncTimeJumpThreshold); } else { printf(" TimeSync Time Jump Allowed : %d\n", hInfo.u.timeSync_v4.data.timeSyncHardReset); } printf(" TimeSync Time Offset (ns): %d\n\n", hInfo.u.timeSync_v4.data.timeSyncTimeOffset); // Check if the adapter is configured for PPS if (((hInfo.u.timeSync_v4.data.tsRefPrio[0] == NT_TIMESYNC_REFERENCE_INT1) && (hInfo.u.timeSync_v4.data.timeSyncConnectorInt1 == NT_TIMESYNC_CONNECTOR_SETTING_PPS_IN)) || ((hInfo.u.timeSync_v4.data.tsRefPrio[0] == NT_TIMESYNC_REFERENCE_INT2) && (hInfo.u.timeSync_v4.data.timeSyncConnectorInt2 == NT_TIMESYNC_CONNECTOR_SETTING_PPS_IN)) || ((hInfo.u.timeSync_v4.data.tsRefPrio[0] == NT_TIMESYNC_REFERENCE_EXT1) && (hInfo.u.timeSync_v4.data.timeSyncConnectorExt1 == NT_TIMESYNC_CONNECTOR_SETTING_PPS_IN))) { found = 1; TS_os[i].timeSyncEnabled = 1; // Read the Timestamp type from the adapter hInfo.cmd=NT_INFO_CMD_READ_ADAPTER_V6; hInfo.u.adapter_v6.adapterNo = (uint8_t) i; if((status = NT_InfoRead(hInfoStream, &hInfo)) != NT_SUCCESS) { // Get the status code as text NT_ExplainError(status, errorBuffer, sizeof(errorBuffer)); fprintf(stderr, "NT_InfoRead() failed: %s\n", errorBuffer); return -1; } // Check that Timestamp type is set to Native UNIX if (hInfo.u.adapter_v6.data.timestampType != NT_TIMESTAMP_TYPE_NATIVE_UNIX) { fprintf(stderr, "Timestamp should be Native UNIX, please configure in the Ntservice.ini file.\n"); return -1; } } } if (found == 0) { fprintf(stderr, "No PPS Enabled adapters found! Please configure PPS in ntservice.ini\n"); return -1; } /* Open the event stream */ if ((status = NT_EventOpen(&hEventStream, "PpsEvent", NT_EVENT_SOURCE_TIMESYNC)) != NT_SUCCESS) { // Get the status code as text NT_ExplainError(status, errorBuffer, sizeof(errorBuffer)); fprintf(stderr, "NT_EventOpen() failed: %s\n", errorBuffer); return -1; } // Open the config stream if((status = NT_ConfigOpen(&hConfigStream, "CONFIG"))) { // Get the status code as text NT_ExplainError(status, errorBuffer, sizeof(errorBuffer)); fprintf(stderr, "NT_ConfigOpen() failed: %s\n", errorBuffer); return -1; } // Enable PPS for (i=0;i<numAdapters;i++) { if (TS_os[i].timeSyncEnabled == 1) { configInfo.parm = NT_CONFIG_PARM_ADAPTER_TIMESYNC; configInfo.u.timesyncWrite.adapter = (uint8_t) i; configInfo.u.timesyncWrite.data.action = NT_TIMESYNC_PPS_ACTION_ENABLE; /* Set Initial PPS time */ PpsGetOsTime(&osTime); configInfo.u.timesyncWrite.data.refTime = osTime; if ((status = NT_ConfigWrite(hConfigStream, &configInfo)) != NT_SUCCESS) { // Get the status code as text NT_ExplainError(status, errorBuffer, sizeof(errorBuffer)); fprintf(stderr, "NT_ConfigWrite() failed: %s\n", errorBuffer); return -1; } } } fprintf(stderr, "PPS example starting in 5 seconds\n"); // Sleep 5 sec #if defined(__linux__) || defined(__FreeBSD__) sleep(5); #elif defined(WIN32) || defined (WIN64) Sleep(5000); // sleep 5000 milliseconds = 5 second #endif #if defined(WIN32) || defined (WIN64) /* Clear screen */ if(system("cls")==0) { // Avoid compiler warning } #else /* Clear screen */ if(system("clear")==0) { // Avoid compiler warning } #endif printf("PPS Example running (press CTRL-C to exit)\n"); while (stopApplication == 0) { status = NT_EventRead(hEventStream, &hEvent, timeout); if (status == NT_STATUS_TIMEOUT) { // Timeout try again } else { if (status != NT_SUCCESS) { // Get the status code as text NT_ExplainError(status, errorBuffer, sizeof(errorBuffer)); fprintf(stderr, "NT_EventRead() failed: %s\n", errorBuffer); return -1; } // Handle event if (hEvent.type == NT_EVENT_SOURCE_TIMESYNC) { if (hEvent.u.timeSyncEvent.action == NT_EVENT_TIMESYNC_PPS_REQUEST_TIME) { // Send PPS Reference Time configInfo.parm = NT_CONFIG_PARM_ADAPTER_TIMESYNC; configInfo.u.timesyncWrite.adapter = hEvent.u.timeSyncEvent.adapter; configInfo.u.timesyncWrite.data.action = NT_TIMESYNC_PPS_ACTION_REFERENCE_TIME; /* Set PPS Reference Time */ PpsGetOsTime(&osTime); configInfo.u.timesyncWrite.data.refTime = osTime; if ((status = NT_ConfigWrite(hConfigStream, &configInfo)) != NT_SUCCESS) { // Get the status code as text NT_ExplainError(status, errorBuffer, sizeof(errorBuffer)); fprintf(stderr, "NT_ConfigWrite() failed: %s\n", errorBuffer); return -1; } } } } PpsGetOsTime(&helpTime); if (helpTime != printTime) { printTime=helpTime; #if defined(WIN32) || defined (WIN64) /* Clear screen */ if(system("cls")==0) { // Avoid compiler warning } #else /* Clear screen */ if(system("clear")==0) { // Avoid compiler warning } #endif /* Read timesync info */ for (i=0;i<numAdapters;i++) { if (TS_os[i].timeSyncEnabled == 1) { /* Read timesync info */ hInfo.cmd=NT_INFO_CMD_READ_TIMESYNC_V4; hInfo.u.timeSync_v4.adapterNo = (uint8_t) i; if ((status = NT_InfoRead(hInfoStream, &hInfo)) != NT_SUCCESS) { fprintf(stderr, "Failed to read timesync info.\n"); return -1; } if (hInfo.u.timeSync_v4.data.timeSyncCurrentConStatus == NT_TIMESYNC_CONNECTOR_STATUS_SIGNAL_LOST) { if (TS_os[i].timeSyncConStatus != NT_TIMESYNC_CONNECTOR_STATUS_SIGNAL_LOST) { TS_os[i].timeSyncConStatus = NT_TIMESYNC_CONNECTOR_STATUS_SIGNAL_LOST; } printf("PPS signal lost on adapter %d\n", i); } else if (hInfo.u.timeSync_v4.data.timeSyncCurrentConStatus == NT_TIMESYNC_CONNECTOR_STATUS_SIGNAL_PRESENT) { if (TS_os[i].timeSyncConStatus != NT_TIMESYNC_CONNECTOR_STATUS_SIGNAL_PRESENT) { TS_os[i].timeSyncConStatus = NT_TIMESYNC_CONNECTOR_STATUS_SIGNAL_PRESENT; } printf("PPS signal found on adapter %d\n", i); /* Print timesync info */ PpsPrintStatusAndTime(i, hInfo.u.timeSync_v4.data.timeSyncPpsSampled, hInfo.u.timeSync_v4.data.timeSyncTimeSkew); } } } } } // Disable PPS for (i=0;i<numAdapters;i++) { if (TS_os[i].timeSyncEnabled == 1) { configInfo.parm = NT_CONFIG_PARM_ADAPTER_TIMESYNC; configInfo.u.timesyncWrite.adapter = (uint8_t)i; configInfo.u.timesyncWrite.data.action = NT_TIMESYNC_PPS_ACTION_DISABLE; configInfo.u.timesyncWrite.data.refTime = 0; if ((status = NT_ConfigWrite(hConfigStream, &configInfo)) != NT_SUCCESS) { // Get the status code as text NT_ExplainError(status, errorBuffer, sizeof(errorBuffer)); fprintf(stderr, "NT_ConfigWrite() failed: %s\n", errorBuffer); return -1; } } } // Close the configuration stream if ((status = NT_ConfigClose(hConfigStream)) != NT_SUCCESS) { // Get the status code as text NT_ExplainError(status, errorBuffer, sizeof(errorBuffer)); fprintf(stderr, "NT_ConfigClose() failed: %s\n", errorBuffer); return -1; } // Close the event stream if ((status = NT_EventClose(hEventStream)) != NT_SUCCESS) { // Get the status code as text NT_ExplainError(status, errorBuffer, sizeof(errorBuffer)); fprintf(stderr, "NT_EventClose() failed: %s\n", errorBuffer); return -1; } /* Close the info stream */ if ((status = NT_InfoClose(hInfoStream)) != NT_SUCCESS) { // Get the status code as text NT_ExplainError(status, errorBuffer, sizeof(errorBuffer)); fprintf(stderr, "NT_InfoClose() failed: %s\n", errorBuffer); return -1; } printf("Streams closed\n"); return 0; }