eventMonitor_example.c

Reference Documentation

product_line_custom
IntelĀ® PAC
Napatech SmartNIC
category
Reference Information
Napatech Software Suite: eventMonitor_example.c
eventMonitor_example.c

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:

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

/*
*
* Copyright 2020 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 "NP-0405 Napatech 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 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
return TRUE;
#else
if (sig == SIGINT)
#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
{
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,
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) {
strcpy(LevelStr, "0");
break;
strcpy(LevelStr, "1");
break;
default:
strcpy(LevelStr, "?");
}
switch (pSensorEvent->source) {
strcpy(OrigStr, "Port");
break;
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.
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,
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) {
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;
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;
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;
printf("Limits for ");
switch (pConfigEvent->u.sensor.source)
{
printf("port sensor %u on port %u ", pConfigEvent->u.sensor.sensorIndex,
pConfigEvent->u.sensor.sourceIndex);
break;
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) {
return "free running clock";
return "PTP";
//TODO
return "Int1";
return "Int2";
return "Ext1";
return "OS clock";
default:
return "<unknown>";
}
}
//Convert PTP port state to a string
static const char *ptp2text(enum NtPTPPortState_e state)
{
switch(state) {
return "initializing";
return "faulty";
return "disabled";
return "listening";
return "pre master";
return "master";
return "passive";
return "uncalibrated";
return "slave";
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) {
// Port event received. Check the action of port event.
printf("Port %d: %s\n", pEventInfo->u.portEvent.portNo,
break;
status = DumpSensor(&pEventInfo->u.sensorEvent);
break;
break;
printf("Timesync event on adapter %u - Action %u\n", pEventInfo->u.timeSyncEvent.adapter,
pEventInfo->u.timeSyncEvent.action);
break;
printf("SDRAM usage: Filled %3d%% - Stream ID %3d - No. of streams %2d\n", (int)((pEventInfo->u.sdramFillLevelEvent.used*100)/pEventInfo->u.sdramFillLevelEvent.size),
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;
{
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;
}
{
uint8_t adapter = pEventInfo->u.timeSyncStateMachineEvent.adapter;
switch (pEventInfo->u.timeSyncStateMachineEvent.action) {
printf("Adapter %d: Loses %s as time reference\n", adapter,
break;
printf("Adapter %d: Uses %s as time reference\n", adapter,
break;
printf("Adapter %d: Fails to choose %s as time reference\n", adapter,
break;
printf("Adapter %d: Is in sync with %s time reference\n", adapter,
break;
printf("Adapter %d: Is out of sync with %s time reference\n", adapter,
break;
/* "Old" state, ptpState[0] == NT_PTP_PORT_STATE_NA first time */
if (pEventInfo->u.timeSyncStateMachineEvent.ptpState[0] ==
printf("Adapter %d: Changes PTP state to %s\n", adapter,
else
printf("Adapter %d: Changes PTP state from %s to %s\n", adapter,
break;
printf("Adapter %d: Time stamp clock is set explicitly to %llu\n",
adapter,
(long long unsigned) pEventInfo->u.timeSyncStateMachineEvent.timeStampClock);
break;
printf("Adapter %d: External device lost synchronization signal", adapter);
break;
printf("Adapter %d: External device is out of synchronization", adapter);
break;
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");
}
#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);
}
// 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);
}
// 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)
}