eventMonitor_example.c

Reference Documentation

product_line_custom
Napatech SmartNIC
category
Reference Information

Description

This source file is an example of how to use NTAPI to monitor events. The example program runs in an infinite loop polling the event stream for events. When an event is received, it is printed on the screen. It also shows how to translate read sensor data into a text representation.

Prerequisites

  • None.

Program flow

The following is required to monitor events:
  • #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() instructs the NTAPI library to convert returned data to the NTAPI_VERSION, if possible. This ensures that applications can run on NTAPI libraries of newer versions.

  • NT_EventOpen() - Open an event stream making it possible to receive events. When an event stream is opened, all events are stored on an event queue until they are read.

  • NT_EventRead() - Wait for either a timeout or for an event to arrive, then return a single event from the event queue. If no event arrives within the timeout period, a NT_STATUS_TIMEOUT is returned.

  • NT_EventClose() - Close an event stream.

  • NT_InfoOpen() - Open an information stream.

  • NT_InfoRead() - Read sensor information data in order to get the name and sensor limits.

  • NT_InfoClose() - Close an information stream.

  • NT_Done() - Close down the NTAPI library.

  • NT_ExplainError() - Explain an error code returned by NTAPI functions.

Code

/* * %NT_SOFTWARE_LICENSE% */ /** * @example eventMonitor_example.c * @section eventMonitor_example_description Description * * This source file is an example of how to use NTAPI to monitor events. * The example program runs in an infinite loop polling the event stream * for events. When an event is received, it is printed on the screen. * It also shows how to translate read sensor data into a text representation. * * The example program uses the following NTAPI functions: * - @ref NT_Init() * - @ref NT_InfoOpen() * - @ref NT_InfoRead() * - @ref NT_InfoClose() * - @ref NT_EventOpen() * - @ref NT_EventRead() * - @ref NT_EventClose() * - @ref NT_Done() * - @ref NT_ExplainError() * * @section eventMonitor_example_prerequisites Prerequisites * - None. * * @section eventMonitor_example_flow Program flow * @{ * The following is required to monitor events: * - \#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() instructs the NTAPI library to convert returned data * to the @ref NTAPI_VERSION, if possible. This ensures that * applications can run on NTAPI libraries of newer versions. * - @ref NT_EventOpen() - Open an event stream making it possible to receive events. * When an event stream is opened, all events are stored on an event queue * until they are read. * - @ref NT_EventRead() - Wait for either a timeout or for an event to arrive, * then return a single event from the event queue. If no event arrives * within the timeout period, a NT_STATUS_TIMEOUT is returned. * - @ref NT_EventClose() - Close an event stream. * - @ref NT_InfoOpen() - Open an information stream. * - @ref NT_InfoRead() - Read sensor information data in order to get the name * and sensor limits. * - @ref NT_InfoClose() - Close an information stream. * - @ref NT_Done() - Close down the NTAPI library. * - @ref NT_ExplainError() - Explain an error code returned by NTAPI functions. * *<hr> * @section eventMonitor_example_code Code * @} */ #include <stdio.h> #include <signal.h> #include "nt.h" #if defined(WIN32) || defined(WIN64) #include <winsock2.h> // SetConsoleCtrlHandler(), for Windows 2000 Pro/Server or later #include <string.h> // strcpy_s() #endif #if defined(WIN32) || defined(WIN64) #define snprintf(dst, ...) _snprintf_s((dst), _countof(dst), __VA_ARGS__) #define strcpy(dst, src) strcpy_s((dst), _countof(dst), (src)) #define strncat(dst, src, sz) strcat_s(dst, sz, src) #endif //Error codes returned by the application #define NT_APPL_SUCCESS 0 #define NT_APPL_ERROR_NTAPI 1 #define NT_APPL_ERROR_OS 2 //Flag to signal that application should stop. static volatile bool stopApplication = false; //The function called when the user presses CTRL-C #if defined(WIN32) || defined (WIN64) static BOOL WINAPI StopApplication(int sig) #else static void StopApplication(int sig) #endif { #ifdef WIN32 stopApplication = true; return TRUE; #else if (sig == SIGINT) stopApplication = true; #endif } //Translate sensor type into a string representation. static const char* NT_TranslateSensorType(NtSensorType_t Type) { switch (Type) { case NT_SENSOR_TYPE_UNKNOWN : return "Unknown"; case NT_SENSOR_TYPE_TEMPERATURE : return "Temp."; case NT_SENSOR_TYPE_VOLTAGE : return "Voltage"; case NT_SENSOR_TYPE_CURRENT : return "Current"; case NT_SENSOR_TYPE_POWER : return "Power"; case NT_SENSOR_TYPE_FAN : return "Speed"; case NT_SENSOR_TYPE_HIGH_POWER : return "Power"; default: assert(false); return "Unhandled"; } } //Return the sensor multiplier static float NT_GetSensorMultiplier(NtSensorType_t Type) { switch (Type) { case NT_SENSOR_TYPE_TEMPERATURE : return (float)0.1; //!< Unit: 0.1 degree Celsius case NT_SENSOR_TYPE_VOLTAGE : return (float)1e-3; //!< Unit: 1 mV case NT_SENSOR_TYPE_CURRENT : return (float)1e-6; //!< Unit: 1 uA case NT_SENSOR_TYPE_POWER : return (float)1e-7; //!< Unit: 0.1 uW case NT_SENSOR_TYPE_FAN : return (float)1; //!< Unit: 1 RPM (Revolutions Per Minute) case NT_SENSOR_TYPE_HIGH_POWER : return (float)1e-3; //!< Unit: 1 mW default: assert(false); return 0.0; } } //Get the sensor unit. static const char* NT_GetSensorUnit(NtSensorType_t Type) { switch (Type) { case NT_SENSOR_TYPE_UNKNOWN : return "?"; case NT_SENSOR_TYPE_TEMPERATURE : return "C"; case NT_SENSOR_TYPE_VOLTAGE : return "V"; case NT_SENSOR_TYPE_CURRENT : return "A"; case NT_SENSOR_TYPE_POWER : return "W"; case NT_SENSOR_TYPE_FAN : return "RPM"; case NT_SENSOR_TYPE_HIGH_POWER : return "W"; default: assert(false); return "Unhandled"; } } /* * Translate a sensor value into a string representation * * This function converts the sensor value integer into a text string taking * care of multiplication with the sensor type multiplier and using a user supplied * formatting string and unit prefix. * * Input: Str Where to put the result * Input: Size The maximum number of characters that can * be written to Str including the terminating * zero. * Input: Value The sensor value * Input: Type The sensor type (what it measures) * Input: FmtStr String containing a printf format string for * a float value (%f) and a unit string (%s). * If the string does not contain an "f" value * is not printet, and if "s" is not specified, * the unit is not printed. * Input: Prefix Indicates if the unit is preceeded with a * prefix which can be "", (no prefix), "m" (milli) or * "u" (micro). By specifying a prefix, Value * is changed accordingly. * @retval Str */ static char* NT_TranslateSensorValue(char* Str, size_t Size, int Value, NtSensorType_t Type, const char* FmtStr, char* Prefix) { char UnitStr[32]; float FloatVal; float PrefixMultiplier; if (Value == NT_SENSOR_NAN) { snprintf(Str, Size, "%s", ""); return Str; } //Multiply with sensor multiplier in order to get a value that is in //correspondence with the sensor unit FloatVal = (float)Value * NT_GetSensorMultiplier(Type); if (strcmp(Prefix, "m") == 0) { PrefixMultiplier = 1e3; strcpy(UnitStr, "m"); } else if (strcmp(Prefix, "u") == 0) { PrefixMultiplier = 1e6; strcpy(UnitStr, "u"); } else { PrefixMultiplier = 1; strcpy(UnitStr, ""); } strncat(UnitStr, NT_GetSensorUnit(Type), sizeof(UnitStr) - strlen(UnitStr) - 1); FloatVal *= PrefixMultiplier; //Test if value and/or unit should be printet if (strstr(FmtStr, "s") != NULL) { if (strstr(FmtStr, "f") != NULL) snprintf(Str, Size, FmtStr, FloatVal, UnitStr); else snprintf(Str, Size, FmtStr, UnitStr); } else snprintf(Str, Size, FmtStr, FloatVal); return Str; } //Translate a port event into a string representation. static const char* NT_TranslatePortEvent(enum NtEventPort_e Event) { switch (Event) { case NT_EVENT_PORT_LINK_UP: return "Link up"; case NT_EVENT_PORT_LINK_DOWN: return "Link down"; case NT_EVENT_RXAUI_LINK_ERROR: return "RXAUI link error"; case NT_EVENT_PORT_BYPASS_ACTIVATED: return "Bypass activated"; case NT_EVENT_PORT_BYPASS_DEACTIVATED: return "Bypass deactivated"; case NT_EVENT_PORT_NIM_INSERTED: return "NIM inserted"; case NT_EVENT_PORT_NIM_REMOVED: return "NIM removed"; default: assert(false); return "Unhandled"; } } //Read additional sensor data in order to get sensor name, limits etc static int GetSensorData(const struct NtEventSensor_s *pSensor, NtInfo_t *pInfo) { NtInfoStream_t hStream; // Info stream handle int status; char errBuf[NT_ERRBUF_SIZE]; // Error buffer // Open the info stream status = NT_InfoOpen(&hStream, "InfoStream"); if (status != NT_SUCCESS) { NT_ExplainError(status, errBuf, sizeof(errBuf)); fprintf(stderr, "\n>>> Error: Opening Info stream failed. Code 0x%x = %s\n", status, errBuf); return status; } // Setup sensor data to read pInfo->cmd = NT_INFO_CMD_READ_SENSOR; // Command for sensor data read pInfo->u.sensor.source = pSensor->source; // Source of the sensor (port or adapter) pInfo->u.sensor.sourceIndex = pSensor->sourceIndex; // Source index - This is either port number or adapter number pInfo->u.sensor.sensorIndex = pSensor->sensorIndex; // Sensor index - This is the number of the sensor to read // Read sensor data status = NT_InfoRead(hStream, pInfo); if (status != NT_SUCCESS) { NT_ExplainError(status, errBuf, sizeof(errBuf)); fprintf(stderr, "\n>>> Error: Reading Info failed. Code 0x%x = %s\n", status, errBuf); NT_InfoClose(hStream); return status; } // Close sensor stream status = NT_InfoClose(hStream); if (status != NT_SUCCESS) { NT_ExplainError(status, errBuf, sizeof(errBuf)); fprintf(stderr, "\n>>> Error: Closing Info stream failed. Code 0x%x = %s\n", status, errBuf); return status; } return NT_SUCCESS; } //Dump the sensor information static NtError_t DumpSensor(const struct NtEventSensor_s *pSensorEvent) { NtError_t status; NtInfo_t info; NtInfoSensor_t* pSensor; NtSensorType_t SensorType; char UnitStr[16]; char ValStr[16] = ""; char LimLowStr[16] = ""; char LimHghStr[16] = ""; char AlarmStr[16] = ""; char Prefix[4]; const char* pValFmt; char LevelStr[16]; char OrigStr[32]; //Define the format for printing various sensor type values. //Curr is not used - only as a place holder // Unk Temp Volt Curr OptPwr FAN ElecPwr const char* ValFmt[7] = {"%.1f", "%.1f", "%.2f", "%.2f", "%.0f", "%.0f", "%.1f"}; switch (pSensorEvent->source) { case NT_SENSOR_SOURCE_PORT: case NT_SENSOR_SOURCE_ADAPTER: strcpy(LevelStr, "0"); break; case NT_SENSOR_SOURCE_LEVEL1_PORT: case NT_SENSOR_SOURCE_LEVEL1_ADAPTER: strcpy(LevelStr, "1"); break; default: strcpy(LevelStr, "?"); } switch (pSensorEvent->source) { case NT_SENSOR_SOURCE_PORT: case NT_SENSOR_SOURCE_LEVEL1_PORT: strcpy(OrigStr, "Port"); break; case NT_SENSOR_SOURCE_ADAPTER: case NT_SENSOR_SOURCE_LEVEL1_ADAPTER: strcpy(OrigStr, "Adapter"); break; default: strcpy(OrigStr, "?"); } if ((status = GetSensorData(pSensorEvent, &info)) != NT_SUCCESS) return status; pSensor = &info.u.sensor.data; SensorType = pSensor->type; //Specify the prefix. Since we dont print any adapter currents it is ok to //set the general current prefix to "m" if (SensorType == NT_SENSOR_TYPE_CURRENT) //Used for Tx bias current only in mA strcpy(Prefix, "m"); else if (SensorType == NT_SENSOR_TYPE_POWER) //Optical power in uW strcpy(Prefix, "u"); else strcpy(Prefix, ""); //Get the unit string alone by not specifying any float translation in the //output format using the arbitrary value 0 NT_TranslateSensorValue(UnitStr, sizeof(UnitStr), 0, SensorType, "[%s]", Prefix); if ((pSensor->state == NT_SENSOR_STATE_NORMAL) || (pSensor->state == NT_SENSOR_STATE_ALARM)) { pValFmt = ValFmt[SensorType]; //Dump sensor data //Do note: //The sensor value is taken from the event. If it had been taken from the //data acquired by GetSensorData an inconsistency might arise since the //alarm from the event might not correspond to the value read a little later. NT_TranslateSensorValue(ValStr , sizeof(ValStr), pSensorEvent->value, SensorType, pValFmt, Prefix); NT_TranslateSensorValue(LimLowStr, sizeof(ValStr), pSensor->limitLow , SensorType, pValFmt, Prefix); NT_TranslateSensorValue(LimHghStr, sizeof(ValStr), pSensor->limitHigh , SensorType, pValFmt, Prefix); } // If the sensor is in an alert state, then print alert message. if (pSensorEvent->action == NT_EVENT_SENSOR_ALARM_STATE_ENTRY) strcpy(AlarmStr, "Alarm"); else strcpy(AlarmStr, "No alarm"); printf("%s %d: Sensor(%s-%s, Id = %d, Level = %s), Value = %s%s, Range = [%s..%s]: %s\n", OrigStr, pSensor->sourceIndex, info.u.sensor.data.name, NT_TranslateSensorType(info.u.sensor.data.type), pSensor->sensorIndex, LevelStr, ValStr, UnitStr, LimLowStr, LimHghStr, AlarmStr); return NT_SUCCESS; } //Dump config change events. Sent if any changes are made to the configuration. static void DumpConfigChangeEvents(const struct NtConfig_s *pConfigEvent) { // Find the type of change event switch (pConfigEvent->parm) { case NT_CONFIG_PARM_PORT_SETTINGS_V2: printf("Settings have been changed for port %2d:\n", pConfigEvent->u.portSettings_v2.portNo); printf("--------------------------------------\n"); printf("Port Enable ................. %2d\n", pConfigEvent->u.portSettings_v2.data.enable); printf("Auto Negotiation ............ %2d\n", pConfigEvent->u.portSettings_v2.data.autoNegotiation); printf("Manual Duplex ............... %2d\n", pConfigEvent->u.portSettings_v2.data.manual.duplex); printf("Manual Speed ................ %2d\n", pConfigEvent->u.portSettings_v2.data.manual.speed); printf("MDI ......................... %2d\n", pConfigEvent->u.portSettings_v2.data.mdi); printf("Maximun IFG ................. %2d\n", pConfigEvent->u.portSettings_v2.data.maxIFG); printf("Minimum IFG ................. %2d\n", pConfigEvent->u.portSettings_v2.data.minIFG); printf("TxPower ..................... %2d\n", pConfigEvent->u.portSettings_v2.data.TxPower); printf("Advertising Full Duplex Mask %2d\n", pConfigEvent->u.portSettings_v2.data.advertise.fullDuplexMask); printf("Advertising Half Duplex Mask %2d\n", pConfigEvent->u.portSettings_v2.data.advertise.halfDuplexMask); printf("Host loopback................ %2d\n", pConfigEvent->u.portSettings_v2.data.hostLoopback); printf("Line loopback................ %2d\n", pConfigEvent->u.portSettings_v2.data.lineLoopback); printf("--------------------------------------\n"); break; case NT_CONFIG_PARM_ADAPTER_TIMESTAMP: printf("Timestamp has changed for adapter %d to ", pConfigEvent->u.timestampWrite.adapter); if (pConfigEvent->u.timestampWrite.data.bCurrent == 1) printf("current OS time\n"); else printf("%16llu\n", (long long unsigned int)pConfigEvent->u.timestampWrite.data.ts); break; case NT_CONFIG_PARM_ADAPTER_TIMESYNC: printf("Timesync has changed for adapter %d - Action 0x%X - Reference time %16llu\n", pConfigEvent->u.timesyncWrite.adapter, pConfigEvent->u.timesyncWrite.data.action, (long long unsigned int)pConfigEvent->u.timesyncWrite.data.refTime); break; case NT_CONFIG_PARM_SENSOR: printf("Limits for "); switch (pConfigEvent->u.sensor.source) { case NT_SENSOR_SOURCE_PORT: printf("port sensor %u on port %u ", pConfigEvent->u.sensor.sensorIndex, pConfigEvent->u.sensor.sourceIndex); break; case NT_SENSOR_SOURCE_ADAPTER: printf("adapter sensor %u on adapter %u ", pConfigEvent->u.sensor.sensorIndex, pConfigEvent->u.sensor.sourceIndex); break; default: printf("Sensor source not supported %02X\n", pConfigEvent->u.sensor.source); } printf("has changed to: high limit %d, low limit %d\n", pConfigEvent->u.sensor.data.limitHigh, pConfigEvent->u.sensor.data.limitLow); break; default: printf("Unknown change event %u\n", pConfigEvent->parm); break; } } //Convert time reference to a string. static const char *ref2text(enum NtTimeSyncReference_e ref) { switch (ref) { case NT_TIMESYNC_REFERENCE_FREE_RUN: return "free running clock"; case NT_TIMESYNC_REFERENCE_PTP: return "PTP"; //TODO case NT_TIMESYNC_REFERENCE_INT1: return "Int1"; case NT_TIMESYNC_REFERENCE_INT2: return "Int2"; case NT_TIMESYNC_REFERENCE_EXT1: return "Ext1"; case NT_TIMESYNC_REFERENCE_OSTIME: return "OS clock"; default: return "<unknown>"; } } //Convert PTP port state to a string static const char *ptp2text(enum NtPTPPortState_e state) { switch(state) { case NT_PTP_PORT_STATE_INIT: return "initializing"; case NT_PTP_PORT_STATE_FAULTY: return "faulty"; case NT_PTP_PORT_STATE_DISABLED: return "disabled"; case NT_PTP_PORT_STATE_LISTENING: return "listening"; case NT_PTP_PORT_STATE_PRE_MASTER: return "pre master"; case NT_PTP_PORT_STATE_MASTER: return "master"; case NT_PTP_PORT_STATE_PASSIVE: return "passive"; case NT_PTP_PORT_STATE_UNCALIBRATED: return "uncalibrated"; case NT_PTP_PORT_STATE_SLAVE: return "slave"; case NT_PTP_PORT_STATE_INACTIVE: return "inactive"; default: return "<unknown>"; } } //Dump the events. static NtError_t DumpEvent(const NtEvent_t *pEventInfo) { NtError_t status = NT_SUCCESS; uint32_t i; printf("********************************************************************************\n"); switch (pEventInfo->type) { case NT_EVENT_SOURCE_PORT: // Port event received. Check the action of port event. printf("Port %d: %s\n", pEventInfo->u.portEvent.portNo, NT_TranslatePortEvent(pEventInfo->u.portEvent.action)); break; case NT_EVENT_SOURCE_SENSOR: status = DumpSensor(&pEventInfo->u.sensorEvent); break; case NT_EVENT_SOURCE_CONFIG: DumpConfigChangeEvents(&pEventInfo->u.configEvent); break; case NT_EVENT_SOURCE_TIMESYNC: printf("Timesync event on adapter %u - Action %u\n", pEventInfo->u.timeSyncEvent.adapter, pEventInfo->u.timeSyncEvent.action); break; case NT_EVENT_SOURCE_SDRAM_FILL_LEVEL: printf("SDRAM usage: Filled %3d%% - Stream ID %3d - No. of streams %2d\n", (int)((pEventInfo->u.sdramFillLevelEvent.used*100)/pEventInfo->u.sdramFillLevelEvent.size), pEventInfo->u.sdramFillLevelEvent.streamsId, pEventInfo->u.sdramFillLevelEvent.numStreams); printf("------------------------------------------------------------\n"); printf(" Hostbuffer: App %3d%% - Driver %3d%% - Adapter %3d%%\n\n", (int)((pEventInfo->u.sdramFillLevelEvent.hb.deQueued*100)/pEventInfo->u.sdramFillLevelEvent.hb.size), (int)((pEventInfo->u.sdramFillLevelEvent.hb.enQueued*100)/pEventInfo->u.sdramFillLevelEvent.hb.size), (int)((pEventInfo->u.sdramFillLevelEvent.hb.enQueuedAdapter*100)/pEventInfo->u.sdramFillLevelEvent.hb.size)); for (i = 0; i < pEventInfo->u.sdramFillLevelEvent.numStreams; i++) { printf(" Stream %3d - Used %3d%% - Process ID %08llu\n", pEventInfo->u.sdramFillLevelEvent.aStreams[i].streamIndex, (int)((pEventInfo->u.sdramFillLevelEvent.aStreams[i].enQueued*100)/pEventInfo->u.sdramFillLevelEvent.hb.size), (long long unsigned int)pEventInfo->u.sdramFillLevelEvent.aStreams[i].processID); } break; case NT_EVENT_SOURCE_PTP_PORT: { uint8_t adapter = pEventInfo->u.ptpPortEvent.adapterNo; printf("Adapter %d: PTP link is %s\n", adapter, (pEventInfo->u.ptpPortEvent.action == NT_EVENT_PORT_LINK_UP ? "up" : "down")); break; } case NT_EVENT_SOURCE_TIMESYNC_STATE_MACHINE: { uint8_t adapter = pEventInfo->u.timeSyncStateMachineEvent.adapter; switch (pEventInfo->u.timeSyncStateMachineEvent.action) { case NT_EVENT_TIMESYNC_TIME_REFERENCE_LOST: printf("Adapter %d: Loses %s as time reference\n", adapter, ref2text(pEventInfo->u.timeSyncStateMachineEvent.timeReference)); break; case NT_EVENT_TIMESYNC_TIME_REFERENCE_SELECT: printf("Adapter %d: Uses %s as time reference\n", adapter, ref2text(pEventInfo->u.timeSyncStateMachineEvent.timeReference)); break; case NT_EVENT_TIMESYNC_TIME_REFERENCE_SELECT_FAIL: printf("Adapter %d: Fails to choose %s as time reference\n", adapter, ref2text(pEventInfo->u.timeSyncStateMachineEvent.timeReference)); break; case NT_EVENT_TIMESYNC_TIME_IN_SYNC: printf("Adapter %d: Is in sync with %s time reference\n", adapter, ref2text(pEventInfo->u.timeSyncStateMachineEvent.timeReference)); break; case NT_EVENT_TIMESYNC_TIME_OUT_OF_SYNC: printf("Adapter %d: Is out of sync with %s time reference\n", adapter, ref2text(pEventInfo->u.timeSyncStateMachineEvent.timeReference)); break; case NT_EVENT_TIMESYNC_PTP_STATE_CHANGE: /* "Old" state, ptpState[0] == NT_PTP_PORT_STATE_NA first time */ if (pEventInfo->u.timeSyncStateMachineEvent.ptpState[0] == NT_PTP_PORT_STATE_NA) printf("Adapter %d: Changes PTP state to %s\n", adapter, ptp2text(pEventInfo->u.timeSyncStateMachineEvent.ptpState[1])); else printf("Adapter %d: Changes PTP state from %s to %s\n", adapter, ptp2text(pEventInfo->u.timeSyncStateMachineEvent.ptpState[0]), ptp2text(pEventInfo->u.timeSyncStateMachineEvent.ptpState[1])); break; case NT_EVENT_TIMESYNC_TIME_STAMP_CLOCK_SET: printf("Adapter %d: Time stamp clock is set explicitly to %llu\n", adapter, (long long unsigned) pEventInfo->u.timeSyncStateMachineEvent.timeStampClock); break; case NT_EVENT_TIMESYNC_EXTERNAL_DEVICE_LOST_SYNC_SIGNAL: printf("Adapter %d: External device lost synchronization signal", adapter); break; case NT_EVENT_TIMESYNC_EXTERNAL_DEVICE_OUT_OF_SYNC: printf("Adapter %d: External device is out of synchronization", adapter); break; case NT_EVENT_TIMESYNC_EXTERNAL_DEVICE_LOST_TIME_OF_DAY: printf("Adapter %d: External device lost time of day information", adapter); break; } break; } default: printf("Unknown event 0x%X\n", pEventInfo->type); break; } return status; } //Main function. int main(void) { NtEventStream_t hEvent; // Event stream handle NtEvent_t eventInfo; // Event data container char errBuf[NT_ERRBUF_SIZE]; // Error data buffer NtError_t status = NT_SUCCESS; // 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 NT_APPL_ERROR_OS; } #endif printf("\nNapatech Event Monitor Example\n"); printf("------------------------------\n"); // Initialize NTAPI library if ((status = NT_Init(NTAPI_VERSION))) { NT_ExplainError(status, errBuf, sizeof(errBuf)); fprintf(stderr, ">>> Error: NT_Init failed. Code 0x%X = %s\n", status, errBuf); return NT_APPL_ERROR_NTAPI; } // Open the event stream if((status = NT_EventOpen(&hEvent, "EventStream", NT_EVENT_SOURCE_ALL))) { NT_ExplainError(status, errBuf, sizeof(errBuf)); fprintf(stderr, ">>> Error: Open event stream failed. Code %08X = %s\n", status, errBuf); NT_Done(); return NT_APPL_ERROR_NTAPI; } // Run in an infinite loop in order to get all events while (!stopApplication) { // Read an event from the event queue. Wait one second if there are no events. status = NT_EventRead(hEvent, &eventInfo, 1000); if (status == NT_STATUS_TIMEOUT) continue; // Timeout due to no events. Try again. if (status != NT_SUCCESS) { NT_ExplainError(status, errBuf, sizeof(errBuf)); fprintf(stderr, ">>> Error: Reading event failed. Code 0x%X = %s\n", status, errBuf); break; } // Print the received event on the screen if ((status = DumpEvent(&eventInfo)) != NT_SUCCESS) break; } // Close the event stream keeping the first error if any if (status == NT_SUCCESS) { if ((status = NT_EventClose(hEvent)) != NT_SUCCESS) { NT_ExplainError(status, errBuf, sizeof(errBuf)); fprintf(stderr, ">>> Error: Closing event stream failed. Code 0x%X = %s\n", status, errBuf); } } else NT_EventClose(hEvent); NT_Done(); // Close down the NTAPI library if (status != NT_SUCCESS) return NT_APPL_ERROR_NTAPI; return NT_APPL_SUCCESS; }