pps/pps_example.c
Description
This source file is an example of how to use the PPS functionality.
The following NTAPI functions are used:
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.
/*
*
* Copyright 2024 Napatech A/S. All Rights Reserved.
*
* 1. Copying, modification, and distribution of this file, or executable
* versions of this file, is governed by the terms of the Napatech Software
* license agreement under which this file was made available. If you do not
* agree to the terms of the license do not install, copy, access or
* otherwise use this file.
*
* 2. Under the Napatech Software license agreement you are granted a
* limited, non-exclusive, non-assignable, copyright license to copy, modify
* and distribute this file in conjunction with Napatech SmartNIC's and
* similar hardware manufactured or supplied by Napatech A/S.
*
* 3. The full Napatech Software License Agreement is included in this
* distribution, please see "NA-0009 Software License Agreement.pdf"
*
* 4. Redistributions of source code must retain this copyright notice,
* list of conditions and the following disclaimer.
*
* THIS SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTIES, EXPRESS OR
* IMPLIED, AND NAPATECH DISCLAIMS ALL IMPLIED WARRANTIES INCLUDING ANY
* IMPLIED WARRANTY OF TITLE, MERCHANTABILITY, NONINFRINGEMENT, OR OF
* FITNESS FOR A PARTICULAR PURPOSE. TO THE EXTENT NOT PROHIBITED BY
* APPLICABLE LAW, IN NO EVENT SHALL NAPATECH BE LIABLE FOR PERSONAL INJURY,
* OR ANY INCIDENTAL, SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES WHATSOEVER,
* INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS OF PROFITS, CORRUPTION OR
* LOSS OF DATA, FAILURE TO TRANSMIT OR RECEIVE ANY DATA OR INFORMATION,
* BUSINESS INTERRUPTION OR ANY OTHER COMMERCIAL DAMAGES OR LOSSES, ARISING
* OUT OF OR RELATED TO YOUR USE OR INABILITY TO USE NAPATECH SOFTWARE OR
* SERVICES OR ANY THIRD PARTY SOFTWARE OR APPLICATIONS IN CONJUNCTION WITH
* THE NAPATECH SOFTWARE OR SERVICES, HOWEVER CAUSED, REGARDLESS OF THE THEORY
* OF LIABILITY (CONTRACT, TORT OR OTHERWISE) AND EVEN IF NAPATECH HAS BEEN
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. SOME JURISDICTIONS DO NOT ALLOW
* THE EXCLUSION OR LIMITATION OF LIABILITY FOR PERSONAL INJURY, OR OF
* INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO THIS LIMITATION MAY NOT APPLY TO YOU.
*
*
*/
/**
* @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>
* @}
*/
// Include this in order to access the Napatech API
#include <nt.h>
#if defined(__linux__) || defined(__FreeBSD__)
#include <signal.h>
#include <sys/time.h>
#include <unistd.h> // sleep()
#elif defined(WIN32) || defined (WIN64)
#include <winsock2.h>
#include <sys/timeb.h>
#endif
#include <time.h>
#define MAX_TS_CARDS 4
} TimeSync_t;
#if defined(WIN32) || defined (WIN64)
#if defined(_MSC_VER)
struct timezone {
int tz_minuteswest; /* minutes west of Greenwich */
int tz_dsttime; /* type of DST correction */
};
#endif // _MSC_VER
#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
*/
{
uint32_t tv_sec;
uint32_t tv_usec;
};
// Forward declarations
/*
* The function called when user is pressing CTRL-C
*/
#if defined(WIN32) || defined (WIN64)
#else
#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;
}
{
/* 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 i;
int32_t status;
uint32_t timeout = 1000;
uint64_t osTime;
uint64_t helpTime;
uint64_t printTime=0;
NtInfoStream_t hInfoStream; // Info stream handle
NtEventStream_t hEventStream;
NtConfigStream_t hConfigStream;
NtEvent_t hEvent;
NtConfig_t configInfo;
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");
// Get the status code as text
fprintf(stderr, "NT_Init() failed: %s\n", errorBuffer);
return -1;
}
/* Init local variables */
for (i=0;i<MAX_TS_CARDS;i++) {
}
printf("Opening info stream\n");
/* Open the info stream */
// 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 */
// Get the status code as text
NT_ExplainError(status, errorBuffer, sizeof(errorBuffer));
fprintf(stderr, "NT_ConfigRead() failed: %s\n", errorBuffer);
return -1;
}
printf("Found %d adapters\n", numAdapters);
for (i=0;i<numAdapters;i++) {
/* Read timesync info */
if ((status = NT_InfoRead(hInfoStream, &hInfo)) != NT_SUCCESS) {
// Get the status code as text
NT_ExplainError(status, errorBuffer, sizeof(errorBuffer));
fprintf(stderr, "Failed to read timesync info: %s\n", errorBuffer);
return -1;
}
/* Print timesync info */
printf("Adapter %d:\n", i);
} else {
}
// Check if the adapter is configured for PPS
found = 1;
TS_os[i].timeSyncEnabled = 1;
// Read the Timestamp type from the adapter
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
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 */
// 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
// 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) {
/* Set Initial PPS time */
PpsGetOsTime(&osTime);
// 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
// Send PPS Reference Time
configInfo.parm = NT_CONFIG_PARM_ADAPTER_TIMESYNC;
/* Set PPS Reference Time */
PpsGetOsTime(&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;
if ((status = NT_InfoRead(hInfoStream, &hInfo)) != NT_SUCCESS) {
// Get the status code as text
NT_ExplainError(status, errorBuffer, sizeof(errorBuffer));
fprintf(stderr, "Failed to read timesync info: %s\n", errorBuffer);
return -1;
}
if (hInfo.u.timeSync_v4.data.timeSyncCurrentConStatus == 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) {
}
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;
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
// 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
// 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 */
// 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;
}