Integrator Resources

The official home for NAI Support

Not sure where to start? Try Quick Start Guide or ask a question below!

Toggle Components with Visual Button
JavaScript Form Processing

DIF EtherInterrupts

DIF EtherInterrupts Sample Application (SSK 1.x)

Overview

The DIF EtherInterrupts sample application demonstrates how to configure and handle Ethernet-based interrupts on differential (DIF) I/O modules using the NAI Software Support Kit (SSK 1.x). The sample uses the Ethernet IDR (Interrupt Driven Response) mechanism: when an interrupt fires on the module, the board’s onboard processor executes a set of pre-configured Ethernet commands (reading and clearing status registers) and sends the results to your application over TCP or UDP. This eliminates the need for a hardware ISR on the host and delivers all status values in a single network message.

The sample covers three DIF interrupt status types: BIT (Built-In Test) fault, low-to-high transition, and high-to-low transition. It configures a single DIF channel as an input, sets up the IDR command payload, enables interrupts, and spawns a listener thread that receives and decodes the Ethernet interrupt messages.

This sample supports DIF module types such as DF1 and DF2. Consult your module’s manual for the specific DIF module types supported by your hardware.

For background on interrupt concepts — including edge vs. level triggering, interrupt vector numbering, steering architecture, and Ethernet IDR fundamentals — see the Interrupts API Guide. This guide focuses on how those concepts apply specifically to DIF modules and walks through the practical Ethernet IDR implementation using the SSK 1.x API.

Prerequisites

Before running this sample, make sure you have:

  • An NAI board with a DIF module installed (DF1, DF2, or a compatible module type).

  • A Gen4 or later board with Ethernet support — Ethernet IDR requires Gen4 Ethernet commands.

  • SSK 1.x installed on your development host.

  • The sample applications built. Refer to the SSK 1.x build instructions for your platform if you have not already compiled them.

  • Network connectivity between the host and the board, with no firewall blocking the configured IDR response port.

How to Run

Launch DIF_EtherInterrupts from your build output directory. On startup the application looks for a configuration file (default_DIFEthInterrupts.txt). On the first run, this file will not exist — the application will present an interactive board menu where you configure a board connection, card index, and module slot. You can save this configuration so that subsequent runs skip the menu and connect automatically. Once connected, the application prompts you for a DIF channel, IDR response IP address and port, and interrupt steering mode, then begins listening for Ethernet interrupt messages.

Board Connection and Module Selection

Note
This startup sequence is common to all NAI sample applications. The board connection and module selection code shown here is not specific to DIF. For details on board connection configuration, see the First Time Setup Guide.

The main() function follows a standard SSK 1.x startup flow:

  1. Call naiapp_RunBoardMenu() to load a saved configuration file (if one exists) or present the interactive board menu. The configuration file (default_DIFEthInterrupts.txt) is not included with the SSK — it is created when the user saves their connection settings from the board menu. On the first run, the menu will always appear.

  2. Call naiapp_query_CardIndex() to query the user for the card index.

  3. Call naibrd_GetModuleCount() and naiapp_query_ModuleNumber() to query for the module slot.

  4. Retrieve the module ID with naibrd_GetModuleID() and pass control to Run_DIF_EthInterrupt().

#if defined (__VXWORKS__)
int32_t DIF_EtherInterrupts(void)
#else
int32_t main(void)
#endif
{
   bool_t stop = FALSE;
   int32_t cardIndex;
   int32_t moduleCnt;
   int32_t module;
   uint32_t moduleID = 0;
   int8_t inputBuffer[80];
   int32_t inputResponseCnt;

   if (naiapp_RunBoardMenu(CONFIG_FILE) == TRUE)
   {
      while (stop != TRUE)
      {
         stop = naiapp_query_CardIndex(naiapp_GetBoardCnt(), 0, &cardIndex);
         if (stop != TRUE)
         {
            check_status(naibrd_GetModuleCount(cardIndex, &moduleCnt));
            stop = naiapp_query_ModuleNumber(moduleCnt, 1, &module);
            if (stop != TRUE)
            {
               moduleID = naibrd_GetModuleID(cardIndex, module);
               if (moduleID != 0)
               {
                  Run_DIF_EthInterrupt(cardIndex, module, moduleID);
               }
            }
         }
         printf("\nType Q to quit or Enter key to restart application:\n");
         stop = naiapp_query_ForQuitResponse(sizeof(inputBuffer), NAI_QUIT_CHAR, inputBuffer, &inputResponseCnt);
      }
   }

   naiapp_access_CloseAllOpenCards();
   return 0;
}
Important

Common connection errors you may encounter at this stage:

  • No board found — verify that the board is powered on and physically connected. Check that the configuration file lists the correct interface and address.

  • Connection timeout — confirm network settings (for Ethernet connections) or bus configuration (for PCI/PCIe). Firewalls and IP mismatches are frequent causes.

  • Invalid card or module index — indices are zero-based for cards and one-based for modules. Ensure the values you pass match your hardware setup.

  • Module not present at selected slot — the slot you selected does not contain a DIF module. Use the board menu to verify which slots are populated.

Program Structure

The DIF EtherInterrupts sample is contained in a single source file, DIF_EtherInterrupts.c. The program flow is:

  1. Board connection and module selection — the standard SSK 1.x startup sequence described above.

  2. Channel and network configuration — the user selects a DIF channel, enters the IDR response IP address and port, and chooses onboard or offboard interrupt steering.

  3. Module configuration — the application clears pending status, configures the channel as an input, builds the IDR command payload, and enables interrupts.

  4. IDR start and listener thread — the IDR is started on the board and a TCP or UDP listener thread is spawned to receive interrupt messages.

  5. Decode and display — incoming messages are parsed into individual Ethernet responses and their register data is displayed.

The entry point is main() (or DIF_EtherInterrupts() on VxWorks). The core configuration and interrupt handling logic lives in the static Run_DIF_EthInterrupt() function.

Key Constants

The sample defines several constants that control IDR behavior:

#define DEF_DIF_IDR_ID                           3
#define DEF_DIF_ETHER_CMD_COUNT                  3
#define DEF_DIF_RESPONSE_PROTOCOL                ETHER_GEN4_TCP_PROTOCOL
#define DEF_DIF_RESPONSE_IP_LEN                  ETHER_GEN4_IPv4_ADDR_LEN

static uint16_t DEF_DIF_RESPONSE_PORT         =  52801;
static uint8_t  DEF_DIF_RESPONSE_IP_ADDR[]    = {192,168,1,100};
  • DEF_DIF_IDR_ID — the IDR identifier (ID 3) used to register and manage this IDR configuration on the board. Each IDR on a board must have a unique ID.

  • DEF_DIF_ETHER_CMD_COUNT — the number of Ethernet commands in the IDR payload (three: read statuses, write to clear, read again to confirm).

  • DEF_DIF_RESPONSE_PROTOCOL — TCP by default. Change to ETHER_GEN4_UDP_PROTOCOL for UDP delivery.

  • DEF_DIF_RESPONSE_PORT and DEF_DIF_RESPONSE_IP_ADDR — the IP address and port where your application listens for IDR responses. The user is prompted to override these at runtime.

Interrupt Status Types

The DIF module exposes three interrupt status types that this sample configures. Each type monitors a different hardware condition and latches when that condition is detected.

BIT (Built-In Test) / Fault

NAI_DIF_STATUS_BIT_LATCHED

The module’s internal self-test has detected an anomaly on a channel. The Built-In Test circuitry continuously monitors the health of each differential channel. When BIT detects a problem, it latches the corresponding status bit and, if enabled, raises an interrupt. Enable BIT interrupts for health monitoring or safety-critical applications where a failed channel must be flagged immediately.

Low-to-High Transition

NAI_DIF_STATUS_LO_HI_TRANS_LATCHED

A differential input transitioned from low to high. The module captures the rising edge and latches the status bit so the event is not lost even if the input changes again before the software reads the register. Enable low-to-high transition interrupts for rising-edge detection: signal activation, event counting, or detecting when an external condition becomes active.

High-to-Low Transition

NAI_DIF_STATUS_HI_LO_TRANS_LATCHED

A differential input transitioned from high to low. Like its low-to-high counterpart, the module captures the falling edge and latches it. Enable high-to-low transition interrupts for falling-edge detection: signal deactivation or detecting when an external condition clears. Used together with low-to-high interrupts, the two transition types give full visibility into both edges of a signal.

The sample enables all three status types for demonstration. In your own application, enable only the status types relevant to your use case to reduce interrupt traffic and simplify your handler logic.

Interrupt Configuration

The Run_DIF_EthInterrupt() function performs the complete module configuration sequence before starting the IDR. Each step is explained below with the corresponding code.

Step 1: Check Gen4 Ethernet Support

Ethernet IDR requires Generation 4 or later Ethernet commands. The application checks this before proceeding:

bGen4DIFIDRCommands = SupportsGen4Ether(cardIndex);

If the board does not support Gen4, the application prints an error and exits. You may need to update your board firmware to use Ethernet IDR.

Step 2: Configure Channel as Input

To receive transition interrupts, the DIF channel must be configured as an input. The sample sets both the operating mode and the I/O format:

check_status(naibrd_DIF_SetOpMode(cardIndex, module, channel, NAI_DIF_MODE_STD_INPUT_OUTPUT));
check_status(naibrd_DIF_SetIOFormat(cardIndex, module, channel, NAI_DIF_IOFORMAT_INPUT));

naibrd_DIF_SetOpMode() sets the channel to standard input/output mode. naibrd_DIF_SetIOFormat() then configures the direction as input. If your channel is already configured as an input from a previous setup, these calls are still safe — they confirm the desired state.

Step 3: Clear Pending Status

Stale latched status from a previous run will trigger an immediate interrupt if not cleared. The sample clears all three status types before enabling interrupts:

check_status(naibrd_DIF_ClearStatus(cardIndex, module, channel, NAI_DIF_STATUS_BIT_LATCHED));
check_status(naibrd_DIF_ClearStatus(cardIndex, module, channel, NAI_DIF_STATUS_LO_HI_TRANS_LATCHED));
check_status(naibrd_DIF_ClearStatus(cardIndex, module, channel, NAI_DIF_STATUS_HI_LO_TRANS_LATCHED));

Always clear status registers before enabling interrupts. If you skip this step, stale status bits will not generate a new edge and the interrupt will never fire.

Step 4: Set Trigger Mode

The sample configures all three status types for level-triggered interrupts:

check_status(naibrd_DIF_SetEdgeLevelInterrupt(cardIndex, module, channel, NAI_DIF_STATUS_BIT_LATCHED, NAI_DIF_LEVEL_INTERRUPT));
check_status(naibrd_DIF_SetEdgeLevelInterrupt(cardIndex, module, channel, NAI_DIF_STATUS_LO_HI_TRANS_LATCHED, NAI_DIF_LEVEL_INTERRUPT));
check_status(naibrd_DIF_SetEdgeLevelInterrupt(cardIndex, module, channel, NAI_DIF_STATUS_HI_LO_TRANS_LATCHED, NAI_DIF_LEVEL_INTERRUPT));

NAI_DIF_LEVEL_INTERRUPT selects level-triggered mode, where the interrupt continues to assert as long as the latched condition remains active. For edge-triggered mode (fires once per event), use NAI_DIF_EDGE_INTERRUPT instead. For background on edge vs. level triggering, see the Interrupts API Guide.

Step 5: Set Interrupt Vectors

The sample assigns the same interrupt vector (NAI_DIF_INTERRUPT_VECTOR) to all three status types so that a single IDR handles every DIF interrupt on the module:

check_status(naibrd_DIF_SetGroupInterruptVector(cardIndex, module, 1, NAI_DIF_STATUS_BIT_LATCHED, NAI_DIF_INTERRUPT_VECTOR));
check_status(naibrd_DIF_SetGroupInterruptVector(cardIndex, module, 1, NAI_DIF_STATUS_LO_HI_TRANS_LATCHED, NAI_DIF_INTERRUPT_VECTOR));
check_status(naibrd_DIF_SetGroupInterruptVector(cardIndex, module, 1, NAI_DIF_STATUS_HI_LO_TRANS_LATCHED, NAI_DIF_INTERRUPT_VECTOR));

The vector identifies which interrupt source generated the event. The 1 parameter is the group number (group 1 covers all channels). If you need to distinguish status types inside your handler without parsing the IDR message, you can assign a different vector to each type and register separate IDRs.

Step 6: Set Interrupt Steering

Interrupt steering determines how the interrupt signal is routed from the module. The user selects onboard or offboard at runtime:

check_status(naibrd_DIF_SetGroupInterruptSteering(cardIndex, module, 1, NAI_DIF_STATUS_BIT_LATCHED,         steering));
check_status(naibrd_DIF_SetGroupInterruptSteering(cardIndex, module, 1, NAI_DIF_STATUS_LO_HI_TRANS_LATCHED, steering));
check_status(naibrd_DIF_SetGroupInterruptSteering(cardIndex, module, 1, NAI_DIF_STATUS_HI_LO_TRANS_LATCHED, steering));

The steering value is determined by the user’s onboard/offboard selection:

  • Onboard (NAIBRD_INT_STEERING_ON_BOARD_1) — triggers an Ethernet IDR response. The board’s onboard processor intercepts the interrupt and sends a notification over the network. This is the typical choice for Ethernet IDR.

  • Offboard cPCI (NAIBRD_INT_STEERING_CPCI_APP) — routes the interrupt to the CompactPCI backplane host, which can then process it locally.

For Ethernet IDR, onboard steering is the standard path. The interrupt fires on the board’s processor, which then executes the IDR commands and sends the result to your application over the network.

Step 7: Enable Interrupts

After configuring vectors, trigger mode, and steering, enable interrupt generation for the selected channel across all three status types:

check_status(naibrd_DIF_SetInterruptEnable(cardIndex, module, channel, NAI_DIF_STATUS_BIT_LATCHED, TRUE));
check_status(naibrd_DIF_SetInterruptEnable(cardIndex, module, channel, NAI_DIF_STATUS_LO_HI_TRANS_LATCHED, TRUE));
check_status(naibrd_DIF_SetInterruptEnable(cardIndex, module, channel, NAI_DIF_STATUS_HI_LO_TRANS_LATCHED, TRUE));

In your own application, enable only the status types and channels you need rather than enabling everything.

Important

Common interrupt configuration errors:

  • Interrupts not firing after enable — if latched status registers are not cleared before enabling interrupts, stale status bits from a previous run will not generate a new edge. Always clear status registers before enabling. See Step 3.

  • Wrong steering mode — selecting offboard steering when you want Ethernet IDR delivery (or vice versa) results in interrupts being routed to a path with no handler. For Ethernet IDR, use NAIBRD_INT_STEERING_ON_BOARD_1.

  • Channel not configured as input — transition interrupts require the channel to be set as an input. If you skip naibrd_DIF_SetIOFormat(), transition events may not be detected.

  • Gen4 not supported — if SupportsGen4Ether() returns FALSE, the board firmware does not support IDR commands. Update the board firmware.

Ethernet IDR Configuration

After the module is configured, the application builds and registers the IDR command payload. The IDR tells the board: "When this interrupt vector fires, execute these Ethernet commands and send the results to this IP address and port."

IDR Command Payload

The InitDIFIDRCommands() function builds a three-command IDR payload:

  1. Read status registers — reads the four latched status registers (BIT, low-to-high, high-to-low, and a fourth stride position) starting at NAI_DIF_GEN5_REG_BIT_LATCHED_STATUS_ADD with a stride of 0x10.

  2. Write to clear status — writes 0x00FFFFFF to the same four register addresses, clearing all latched bits across all channels.

  3. Read status registers again — re-reads the same registers to confirm the clear took effect.

status = check_status(naibrd_GetModuleOffset(cardIndex, module, &moduleOffset));
if (status == NAI_SUCCESS)
{
   /* First command: Read status registers */
   MakeDIFReadRegsCommand(bGen4DIFIDRCommands, msgIndex, moduleOffset, commands, &ethcmdlen, boardInterface);
   msgIndex += ethcmdlen;
   idrcmdcnt++;

   /* Second command: Write to clear status */
   MakeDIFWriteRegsCommand(bGen4DIFIDRCommands, msgIndex, moduleOffset, commands, &ethcmdlen, boardInterface);
   msgIndex += ethcmdlen;
   idrcmdcnt++;

   /* Third command: Read status registers again to confirm */
   MakeDIFReadRegsCommand(bGen4DIFIDRCommands, msgIndex, moduleOffset, commands, &ethcmdlen, boardInterface);
   msgIndex += ethcmdlen;
   idrcmdcnt++;
}

naibrd_GetModuleOffset() retrieves the base register address for the installed module, which is needed to build absolute register addresses for the IDR commands. MakeDIFReadRegsCommand() calls nai_ether_MakeReadMessage() to construct a Gen4 Ethernet read command. MakeDIFWriteRegsCommand() uses nai_ether_BeginWriteMessage(), nai_ether_WriteMessageData(), and nai_ether_FinishMessage() to construct a Gen4 Ethernet write command.

The write command clears all interrupt bits by writing 0x00FFFFFF to each of the four status register positions. This means the IDR is self-clearing — the board reads the status, clears it, and reads again, all in a single atomic IDR execution. Your application receives the pre-clear and post-clear values without needing to issue any additional commands.

Registering the IDR

Once the command payload is built, register it with the board:

status = check_status(naibrd_Ether_ClearIDRConfig(IDRcardIndex, (uint16_t)DEF_DIF_IDR_ID));

status = check_status(naibrd_Ether_SetIDRConfig(IDRcardIndex, (uint16_t)DEF_DIF_IDR_ID,
   protocol, iplen, ip, port, NAI_DIF_INTERRUPT_VECTOR,
   cmdcount, cmdlength, commands));

naibrd_Ether_ClearIDRConfig() removes any existing IDR registered under DEF_DIF_IDR_ID so the new configuration starts clean. naibrd_Ether_SetIDRConfig() programs the board with the complete IDR definition: the response protocol (TCP or UDP), IP address and port, the interrupt vector that triggers this IDR, and the command payload to execute.

Starting and Stopping the IDR

Start the IDR so the board begins sending messages when interrupts occur:

status = check_status(naibrd_Ether_StartIDR(IDRcardIndex, (uint16_t)DEF_DIF_IDR_ID));

When the user quits, stop the IDR before closing the connection:

status = check_status(naibrd_Ether_StopIDR(cardIndex, (uint16_t)DEF_DIF_IDR_ID));

Always stop the IDR before closing the connection. If you close the connection without stopping the IDR, the board will continue sending messages to an address that is no longer listening.

Important

Common IDR configuration errors:

  • NAI_ERROR_NOT_SUPPORTED — the board firmware is older than Generation 4 and does not support IDR commands. Update the board firmware.

  • IDR ID conflict — each IDR on the board must have a unique ID. If another part of your application (or a previous run) already registered an IDR with the same ID, call naibrd_Ether_ClearIDRConfig() first.

  • IP address or port mismatch — the IDR response IP and port must match the address your listener thread is bound to. A mismatch means the board sends messages that never arrive.

Network Configuration

The sample prompts the user for the IDR response IP address and port at runtime through QueryEthInterruptDIFIPAddr():

printf("Please Enter IDR Response IP Address: [default=%d.%d.%d.%d]): ",
   DEF_DIF_RESPONSE_IP_ADDR[0], DEF_DIF_RESPONSE_IP_ADDR[1],
   DEF_DIF_RESPONSE_IP_ADDR[2], DEF_DIF_RESPONSE_IP_ADDR[3]);

The default IP address is 192.168.1.100 and the default port is 52801. Press Enter to accept the defaults, or enter your own values. The IP address must be the address of the machine where the sample is running (the machine that will receive the IDR responses). The port must not conflict with other services on that machine.

In your own application, set these values programmatically rather than prompting the user. The IP address should be the address of the network interface on your host that is reachable from the board.

Ethernet Listener Thread

After the IDR is started, the application spawns a background thread to receive the Ethernet interrupt messages. The protocol (TCP or UDP) is selected by DEF_DIF_RESPONSE_PROTOCOL:

if (protocol == ETHER_GEN4_TCP_PROTOCOL)
   CreateDIFIDRTCPServer();
else
   CreateDIFIDRUDPServer();

TCP Listener

CreateDIFIDRTCPServer() sets up a standard TCP listener: it binds to the configured port, listens for an incoming connection from the board, and enters a receive loop. Each received message is passed to DecodeUPRDIFIDRMessages() for parsing.

The TCP path provides reliable, ordered delivery. The board connects to your listener when the first IDR fires, and subsequent messages arrive on the same connection. If the connection drops, no further IDR messages will be delivered until the IDR is reconfigured and restarted.

UDP Listener

CreateDIFIDRUDPServer() sets up a UDP datagram receiver: it binds to the configured port and enters a recvfrom() loop. Each received datagram is passed to DecodeUPRDIFIDRMessages().

UDP provides lower latency but no delivery guarantee. If a datagram is lost, the corresponding interrupt event is missed. For most real-time monitoring applications, UDP is preferred because the lower overhead aligns with interrupt-driven workloads where timeliness matters more than guaranteed delivery.

Message Decoding

DecodeUPRDIFIDRMessages() iterates through the received buffer, calling ParseDIFIDRResponse() to extract individual Ethernet message frames. Each frame is delimited by Gen4 preamble and postamble markers (ETHER_GEN4_PREAMBLE and ETHER_GEN4_POSTAMBLE). The parser copies each complete frame and passes it to DisplayDecodedDIFIDRResponse().

DisplayDecodedDIFIDRResponse() decodes the message header using nai_ether_DecodeMessageHeader() and extracts the sequence number, typecode, and payload:

offset = nai_ether_DecodeMessageHeader(response, responselen, &seq, &tc, gen, &size);

/* Parse IDR Response Sequence Value */
seqrsptype = seq & ETHER_GEN4_SEQ_UPR_MASK;
seqrspidindex = (seq & (ETHER_GEN4_SEQ_ID_MASK)) >> ETHER_GEN4_SEQ_ID_SHIFT;
seqcmdindex = (seq & (ETHER_GEN4_SEQ_CMD_MASK)) >> ETHER_GEN4_SEQ_CMD_SHIFT;

The sequence number encodes three fields:

  • Response type (bit 15-14) — identifies whether this is a TDR (Time Driven Response) or IDR (Interrupt Driven Response) message.

  • ID index (bits 13-10) — the IDR ID that generated this response (value is ID minus 1).

  • Command index (bits 9-6) — which command in the IDR payload produced this response.

For read responses (NAI_ETHER_TYPECODE_RSP_COMMAND_COMPLETE_READ_4), the handler extracts 32-bit register values from the payload in big-endian order. These values correspond to the latched status registers that were read by the IDR command. A non-zero value in any position indicates that the corresponding status type has active latched bits.

Important

Common Ethernet listener errors:

  • No IDR messages received — verify that the response IP address and port configured in the IDR match the address your application is listening on. Check that no firewall is blocking inbound traffic on the configured port. Confirm that naibrd_Ether_StartIDR() was called after naibrd_Ether_SetIDRConfig().

  • Socket bind failure — the port may already be in use by another process or a previous run that did not shut down cleanly. Try a different port or wait for the OS to release the socket.

  • Partial or malformed messages — if ParseDIFIDRResponse() cannot find the Gen4 postamble, the message may have been truncated. This can happen with TCP if the receive buffer is too small or with UDP if the datagram was fragmented. Verify that the receive buffer size is at least NAI_ETHER_MAX_PACKET_SIZE_BYTES.

Troubleshooting Reference

This table summarizes common errors and symptoms covered in the sections above. For detailed context, refer to the relevant section. Consult your module’s manual for hardware-specific diagnostic procedures.

Error / Symptom Possible Causes Suggested Resolution

No board found or connection timeout

Board not powered, incorrect or missing configuration file, network issue

Verify hardware is powered and connected. If the configuration file exists, check that it lists the correct interface and address. If it does not exist, the board menu will appear — configure and save your connection settings.

Module not detected or not recognized as DIF

No DIF module installed at the selected slot, incorrect module number

Verify hardware configuration. naibrd_DIF_GetChannelCount() returning 0 indicates the selected module is not a DIF type.

Gen4 Ethernet not supported

Board Ethernet firmware is older than Gen4

Consult board documentation for Ethernet generation support. Firmware update may be required.

Interrupts not firing after enable

Status registers not cleared before enabling, wrong steering mode, channel not configured as input

Clear all status types before enabling interrupts. Verify steering is set to NAIBRD_INT_STEERING_ON_BOARD_1 for Ethernet IDR. Confirm the channel is set to input mode.

Wrong steering mode

Using offboard steering when Ethernet IDR requires onboard, or vice versa

For Ethernet IDR, use NAIBRD_INT_STEERING_ON_BOARD_1. For direct ISR on external host, use CPCI_APP or PCIE_APP.

No IDR messages received

IP/port mismatch, firewall blocking traffic, IDR not started

Verify network configuration matches IDR setup. Check firewall rules. Confirm naibrd_Ether_StartIDR() was called after naibrd_Ether_SetIDRConfig().

Socket bind failure

Port already in use from a previous run or another process

Use a different port, or wait for the OS to release the socket. On Windows, check for lingering connections with netstat.

Ethernet message parsing errors

Protocol generation mismatch between board and application, truncated message

Verify both use Gen4 protocol. Check that the receive buffer is large enough (NAI_ETHER_MAX_PACKET_SIZE_BYTES).

IDR ID conflict

Another IDR already registered with the same ID

Call naibrd_Ether_ClearIDRConfig() before naibrd_Ether_SetIDRConfig() to clear any previous registration.

Board continues sending after application exits

naibrd_Ether_StopIDR() was not called before closing the connection

Always call naibrd_Ether_StopIDR() before naiapp_access_CloseAllOpenCards() in your shutdown sequence.

Full Source

The complete source for this sample is provided below for reference. The sections above explain each part in detail.

Full Source — DIF_EtherInterrupts.c (SSK 1.x)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>

/* Common Sample Program include files */
#include "include/naiapp_interrupt.h"
#include "include/naiapp_interrupt_ether.h"
#include "include/naiapp_boardaccess_menu.h"
#include "include/naiapp_boardaccess_query.h"
#include "include/naiapp_boardaccess_access.h"
#include "include/naiapp_boardaccess_display.h"
#include "include/naiapp_boardaccess_utils.h"

/* naibrd include files */
#include "nai.h"
#include "naibrd.h"
#include "functions/naibrd_dif.h"
#include "naibrd_ether.h"
#include "advanced/nai_ether_adv.h"
#if defined (WIN32)
#include "maps/nai_map_dif.h"
#else
#include "nai_map_dif.h"
#endif

#if defined (WIN32)
#include <winsock2.h>
#include <ws2tcpip.h>
/* Need to link with Ws2_32.lib */
#pragma comment (lib, "Ws2_32.lib")
/* The following eliminates the FD_SET warning C4127 associated with the do...while(0) construct in the Microsoft winsock2.h file */
#pragma warning (disable:4127)
#elif (LINUX)
#include <sys/errno.h>
#include <pthread.h>
typedef int32_t SOCKET;
#define ZeroMemory(S, N)         memset((S), 0, (N))
#define closesocket(SD)          close(SD)
#define INVALID_SOCKET -1
#define SOCKET_ERROR   -1
#define SD_RECEIVE        0
#define SD_SEND           1
#define SD_BOTH           2
#elif (__VXWORKS__)
#include <netinet/ip.h>
#define ZeroMemory(S, N)         memset((S), 0, (N))
#define closesocket(SD)          close(SD)
#define INVALID_SOCKET -1
#define SOCKET_ERROR   -1
#define SD_RECEIVE        0
#define SD_SEND           1
#define SD_BOTH           2
#endif

static const int8_t *CONFIG_FILE = (int8_t *)"default_DIFEthInterrupts.txt";

/* Function prototypes */
static bool_t Run_DIF_EthInterrupt(int32_t cardIndex, int32_t module, uint32_t modid);
static bool_t QueryEthInterruptDIFIPAddr(void);
static nai_status_t InitDIFIDRCommands(int32_t cardIndex, int32_t module, uint8_t commands[], uint16_t *cmdcount, uint16_t *cmdlen,nai_intf_t boardInterface);
static void MakeDIFReadRegsCommand(bool_t bGen4Ether, uint16_t startIndex, uint32_t moduleOffset, uint8_t commands[], uint16_t *cmdlen,nai_intf_t boardInterface);
static void MakeDIFWriteRegsCommand(bool_t bGen4Ether, uint16_t startIndex, uint32_t moduleOffset, uint8_t commands[], uint16_t *cmdlen,nai_intf_t boardInterface);
static void CreateDIFIDRTCPServer(void);
static void CreateDIFIDRUDPServer(void);
static void DecodeUPRDIFIDRMessages(const uint8_t msg[], int32_t msgsize);
static bool_t ParseDIFIDRResponse(int32_t startIndex, int32_t rsparraysize, uint8_t response[], uint16_t *idrrsplen, int32_t idrrsparraysize, uint8_t idr_response[]);
static void DisplayDecodedDIFIDRResponse(uint16_t responselen, uint8_t response[]);

static bool_t bGen4DIFIDRCommands = FALSE;
/* Default Ethernet Command Count specified for the IDR Commands.
   Change this to match the Command Count specified in InitDIFIDRCommands() routine
*/
#define DEF_DIF_IDR_ID                           3
#define DEF_DIF_ETHER_CMD_COUNT                  3   /* Number of Ethernet Commands in IDR Configuration */
#define DEF_DIF_RESPONSE_PROTOCOL                ETHER_GEN4_TCP_PROTOCOL
#define DEF_DIF_RESPONSE_IP_LEN                  ETHER_GEN4_IPv4_ADDR_LEN

static uint16_t DEF_DIF_RESPONSE_PORT         =  52801;
static uint8_t  DEF_DIF_RESPONSE_IP_ADDR[]    = {192,168,1,100};

#if defined (__VXWORKS__)
 int UPR_DIFEthInt_Handler( int Param );
#elif LINUX
 pthread_t interruptDIFThread;
 static void* UPR_DIFEthInt_Handler(void* lpParam );
#else /* Default Windows */
 DWORD WINAPI UPR_DIFEthInt_Handler( LPVOID lpParam );
#endif
static int terminateDIFThread;

/*****************************************************************************/
/**
<summary>
The purpose of the DIF_EtherInterrupts is to demonstrate the methods to call in the
naibrd library to perform Ethernet interrupt operations with the Differential modules.

The following system configuration routines from the nai_sys_cfg.c file are
called to assist with the configuration setup for this program prior to
calling the naibrd AD routines.
 - ConfigDevice
 - DisplayDeviceCfg
 - GetBoardSNModCfg
 - CheckModule
</summary>
*/
/*****************************************************************************/
#if defined (__VXWORKS__)
int32_t DIF_EtherInterrupts(void)
#else
int32_t main(void)
#endif
{
   bool_t stop = FALSE;
   int32_t cardIndex;
   int32_t moduleCnt;
   int32_t module;
   uint32_t moduleID = 0;
   int8_t inputBuffer[80];
   int32_t inputResponseCnt;

   if (naiapp_RunBoardMenu(CONFIG_FILE) == TRUE)
   {
      while (stop != TRUE)
      {
         /* Query the user for the card index */
         stop = naiapp_query_CardIndex(naiapp_GetBoardCnt(), 0, &cardIndex);
         if (stop != TRUE)
         {
            check_status(naibrd_GetModuleCount(cardIndex, &moduleCnt));

            /* Query the user for the module number */
            stop = naiapp_query_ModuleNumber(moduleCnt, 1, &module);
            if (stop != TRUE)
            {
               moduleID = naibrd_GetModuleID(cardIndex, module);
               if (moduleID != 0)
               {
                  Run_DIF_EthInterrupt(cardIndex, module, moduleID);
               }
            }
         }
         printf("\nType Q to quit or Enter key to restart application:\n");
         stop = naiapp_query_ForQuitResponse(sizeof(inputBuffer), NAI_QUIT_CHAR, inputBuffer, &inputResponseCnt);
      }
   }

   printf("\nType the Enter key to exit the program: ");
   naiapp_query_ForQuitResponse(sizeof(inputBuffer), NAI_QUIT_CHAR, inputBuffer, &inputResponseCnt);
   naiapp_access_CloseAllOpenCards();

   return 0;
}

/**************************************************************************************************************/
/**
<summary>
This function runs handles configuring a DIF channel to receive Differential BIT, Low-to-High and
High-to-Low Ethernet Interrupt commands. This routine will create a thread to wait to
receive the unprompted interrupt ethernet messages.
</summary>
*/
/**************************************************************************************************************/
static bool_t Run_DIF_EthInterrupt(int32_t cardIndex, int32_t module, uint32_t modid)
{
   bool_t bQuit = FALSE;
   nai_status_t status;
   int32_t MAX_CHANNELS = naibrd_DIF_GetChannelCount(modid);
   int32_t channel;
   uint8_t commands[MAX_ETHER_IDR_CMD_CNT*MAX_ETHER_BLOCK_REG_CNT];
   uint16_t cmdcount = 0;
   uint16_t cmdlength = 0;
   uint16_t protocol = DEF_DIF_RESPONSE_PROTOCOL;
   uint16_t iplen = DEF_DIF_RESPONSE_IP_LEN;
   uint16_t port;
   uint8_t ip[DEF_DIF_RESPONSE_IP_LEN];
   int32_t i;
   nai_intf_t boardInterface=0;
   naibrd_int_steering_t steering=0;
   bool_t Query_steering= FALSE;
   int32_t IDRcardIndex=0;
   int8_t inputBuffer[80];
   int32_t inputResponseCnt;

   /* Determine if the board selected supports the Generation 4 Ethernet Commands */
   bGen4DIFIDRCommands = SupportsGen4Ether(cardIndex);

   /* Get the Differential channel to configure for Ethernet interrupts */
   printf("Differential Channel Selection:");
   bQuit = naiapp_query_ChannelNumber(MAX_CHANNELS, 1, &channel);

   if (!bQuit)
      bQuit = QueryEthInterruptDIFIPAddr();

   if(!bQuit){
      bQuit = QueryUserForOnboardOffboardInterrupts(&Query_steering);
   }

      if(Query_steering == TRUE)
      {
         IDRcardIndex = 0;
         boardInterface =  NAI_INTF_ONBOARD;
         steering = NAIBRD_INT_STEERING_ON_BOARD_1;
      }
      else /*OffBoard Interrupt*/
      {
         IDRcardIndex = 0;
         boardInterface = NAI_INTF_PCI;
         steering =  NAIBRD_INT_STEERING_CPCI_APP;
      }

   if (!bQuit)
   {
      if (bGen4DIFIDRCommands)
      {
         /* Make sure there are no pending interrupts before interrupts are enabled */
         /* Clear NAI_DIF_STATUS_BIT_LATCHED, NAI_DIF_STATUS_LO_HI_TRANS_LATCHED
            and NAI_DIF_STATUS_HI_LO_TRANS_LATCHED channel status */
         check_status(naibrd_DIF_ClearStatus(cardIndex, module, channel, NAI_DIF_STATUS_BIT_LATCHED));
         check_status(naibrd_DIF_ClearStatus(cardIndex, module, channel, NAI_DIF_STATUS_LO_HI_TRANS_LATCHED));
         check_status(naibrd_DIF_ClearStatus(cardIndex, module, channel, NAI_DIF_STATUS_HI_LO_TRANS_LATCHED));

         /* Configure the Differential channel to Input */
         check_status(naibrd_DIF_SetOpMode(cardIndex, module, channel,  NAI_DIF_MODE_STD_INPUT_OUTPUT));
         check_status(naibrd_DIF_SetIOFormat(cardIndex, module, channel, NAI_DIF_IOFORMAT_INPUT));

         /* Configure the Interrupt Driven Response Ethernet Command */
         status = check_status(naibrd_Ether_ClearIDRConfig(IDRcardIndex,(uint16_t)DEF_DIF_IDR_ID));
       InitDIFIDRCommands(IDRcardIndex, module, commands, &cmdcount, &cmdlength,boardInterface);

         for (i = 0; i < DEF_DIF_RESPONSE_IP_LEN; i++)
            ip[i] = DEF_DIF_RESPONSE_IP_ADDR[i];
         port = DEF_DIF_RESPONSE_PORT;

       status = check_status(naibrd_Ether_SetIDRConfig(IDRcardIndex,(uint16_t)DEF_DIF_IDR_ID,protocol,iplen,ip,port,NAI_DIF_INTERRUPT_VECTOR,cmdcount,cmdlength,commands));

       if (status == NAI_SUCCESS)
         {
            printf("IDR ID = %d configured.\n", DEF_DIF_IDR_ID);
         }

       /* Start the IDR */
         status = check_status(naibrd_Ether_StartIDR(IDRcardIndex, (uint16_t)DEF_DIF_IDR_ID));
         if (status == NAI_SUCCESS)
         {
            printf("IDR ID = %d Started\n", DEF_DIF_IDR_ID);
         }

         /* Configure to generate interrupts on NAI_DIF_STATUS_BIT_LATCHED, NAI_DIF_STATUS_LO_HI_TRANS_LATCHED and
            NAI_DIF_STATUS_HI_LO_TRANS_LATCHED */

         /* Set the Interrupt Type (Edge/Level) */
         check_status(naibrd_DIF_SetEdgeLevelInterrupt(cardIndex, module, channel, NAI_DIF_STATUS_BIT_LATCHED, NAI_DIF_LEVEL_INTERRUPT));
         check_status(naibrd_DIF_SetEdgeLevelInterrupt(cardIndex, module, channel, NAI_DIF_STATUS_LO_HI_TRANS_LATCHED, NAI_DIF_LEVEL_INTERRUPT));
         check_status(naibrd_DIF_SetEdgeLevelInterrupt(cardIndex, module, channel, NAI_DIF_STATUS_HI_LO_TRANS_LATCHED, NAI_DIF_LEVEL_INTERRUPT));

         /* Set the Interrupt Vectors for BIT, Lo-Hi and Hi-Lo Transition */
         /* Note, set to same vector since one IDR will handle all the interrupts */
         check_status(naibrd_DIF_SetGroupInterruptVector(cardIndex, module, 1, NAI_DIF_STATUS_BIT_LATCHED, NAI_DIF_INTERRUPT_VECTOR));
         check_status(naibrd_DIF_SetGroupInterruptVector(cardIndex, module, 1, NAI_DIF_STATUS_LO_HI_TRANS_LATCHED, NAI_DIF_INTERRUPT_VECTOR));
         check_status(naibrd_DIF_SetGroupInterruptVector(cardIndex, module, 1, NAI_DIF_STATUS_HI_LO_TRANS_LATCHED, NAI_DIF_INTERRUPT_VECTOR));

         /* Set the Interrupt Steering */
         check_status(naibrd_DIF_SetGroupInterruptSteering(cardIndex, module, 1, NAI_DIF_STATUS_BIT_LATCHED,         steering));
         check_status(naibrd_DIF_SetGroupInterruptSteering(cardIndex, module, 1, NAI_DIF_STATUS_LO_HI_TRANS_LATCHED, steering));
         check_status(naibrd_DIF_SetGroupInterruptSteering(cardIndex, module, 1, NAI_DIF_STATUS_HI_LO_TRANS_LATCHED, steering));

         /* Enable BIT, Lo-Hi and Hi-Lo Transition Interrupts */
         check_status(naibrd_DIF_SetInterruptEnable(cardIndex, module, channel, NAI_DIF_STATUS_BIT_LATCHED, TRUE));
         check_status(naibrd_DIF_SetInterruptEnable(cardIndex, module, channel, NAI_DIF_STATUS_LO_HI_TRANS_LATCHED, TRUE));
         check_status(naibrd_DIF_SetInterruptEnable(cardIndex, module, channel, NAI_DIF_STATUS_HI_LO_TRANS_LATCHED, TRUE));

         /* Create a thread that will receive Unprompted Reply interrupt messages */
         terminateDIFThread = FALSE;

   #if defined (__VXWORKS__)
         taskSpawn("uprDIFHandler", 100, 0, 10000, (FUNCPTR)UPR_DIFEthInt_Handler, NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0 );
   #elif defined (LINUX)
         pthread_create(&interruptDIFThread, NULL, (void*)UPR_DIFEthInt_Handler, NULL);
   #else /* Default Windows */
         CreateThread( NULL, 0, UPR_DIFEthInt_Handler, NULL, 0, NULL );
   #endif

         while (!bQuit)
         {
            printf("Type %c to exit program : ", NAI_QUIT_CHAR);
            bQuit = naiapp_query_ForQuitResponse(sizeof(inputBuffer), NAI_QUIT_CHAR, inputBuffer, &inputResponseCnt);
            if (bQuit)
            {
               terminateDIFThread = TRUE;

               /* Stop the IDR */
               status = check_status(naibrd_Ether_StopIDR(cardIndex, (uint16_t)DEF_DIF_IDR_ID));
               if (status == NAI_SUCCESS)
               {
                  printf("IDR ID = %d Stopped\n", DEF_DIF_IDR_ID);
               }
            }
         }
      }
      else
      {
         printf("DIF Ethernet Interrupt Support Prior to Generation 4 Ethernet commands currently not supported\n");
         bQuit = TRUE;
      }
   }
   return bQuit;
}

/**************************************************************************************************************/
/**
<summary>
This function queries the user to enter the IP address associated with receiving DIF Interrupt commands.
</summary>
*/
/**************************************************************************************************************/
static bool_t QueryEthInterruptDIFIPAddr(void)
{
   bool_t bQuit = FALSE;
   bool_t bContinue = TRUE;
   int8_t inputBuffer[80];
   int32_t inputResponseCnt;

   /* Get the IP Address */
   if (!bQuit)
   {
      bContinue = TRUE;
      while (bContinue)
      {
         /* Get the Response IP Address */
         printf("Please Enter IDR Response IP Address: [default=%d.%d.%d.%d]): ",
            DEF_DIF_RESPONSE_IP_ADDR[0],DEF_DIF_RESPONSE_IP_ADDR[1],DEF_DIF_RESPONSE_IP_ADDR[2],DEF_DIF_RESPONSE_IP_ADDR[3]);
         bQuit = naiapp_query_ForQuitResponse(sizeof(inputBuffer), NAI_QUIT_CHAR, inputBuffer, &inputResponseCnt);
         if (bQuit)
            bContinue = FALSE;
         else
         {
            if (inputResponseCnt > NAI_MAX_IP_LEN)
               printf("ERROR: Invalid IP Address.\n");
            else
            {
               if (inputResponseCnt > 0)
                  ParseIPv4Address((char *)inputBuffer, DEF_DIF_RESPONSE_IP_ADDR);
            }
         }
         if (!bQuit)
         {
            /* Get the Response Port */
            printf("Please Enter IDR Response Port: [default=%d]): ", DEF_DIF_RESPONSE_PORT);
            bQuit = naiapp_query_ForQuitResponse(sizeof(inputBuffer), NAI_QUIT_CHAR, inputBuffer, &inputResponseCnt);
            if (bQuit)
               bContinue = FALSE;
            else
            {
               if (inputResponseCnt > 0)
                  DEF_DIF_RESPONSE_PORT = (uint16_t)atol((const char *)inputBuffer);
               bContinue = FALSE;
            }

         }
      }
   }
   return bQuit;
}

/**************************************************************************************************************/
/**
<summary>
This function configures the IDR (Interrupt Driven Response) commands when a DIF interrupt occurs.
There are two Ethernet commands that will be processed by the board when a DIF interrupt occurs. This
routine calls the MakeDIFReadRegsCommand() and MakeDIFWriteRegsCommand() to configure the two
Ethernet commands to include when setting the IDR.
</summary>
*/
/**************************************************************************************************************/
static nai_status_t InitDIFIDRCommands(int32_t cardIndex, int32_t module, uint8_t commands[], uint16_t *cmdcount, uint16_t *cmdlen,nai_intf_t boardInterface)
{
   nai_status_t status = NAI_SUCCESS;
   uint16_t msgIndex = 0;
   uint16_t idrcmdcnt = 0;
   uint16_t ethcmdlen = 0;
   uint16_t idrcmdlen = 0;
   uint32_t moduleOffset;

   status = check_status(naibrd_GetModuleOffset(cardIndex, module, &moduleOffset));
   if (status == NAI_SUCCESS)
   {
      if (bGen4DIFIDRCommands)
      {
         /* First command */
         MakeDIFReadRegsCommand(bGen4DIFIDRCommands, msgIndex, moduleOffset, commands, &ethcmdlen,boardInterface);
         msgIndex += ethcmdlen;
         idrcmdlen += ethcmdlen;
         idrcmdcnt++;

         /* Next command */
         MakeDIFWriteRegsCommand(bGen4DIFIDRCommands, msgIndex, moduleOffset, commands, &ethcmdlen,boardInterface);
         msgIndex += ethcmdlen;
         idrcmdlen += ethcmdlen;
         idrcmdcnt++;

         /* Next command */
         MakeDIFReadRegsCommand(bGen4DIFIDRCommands, msgIndex, moduleOffset, commands, &ethcmdlen,boardInterface);
         msgIndex += ethcmdlen;
         idrcmdlen += ethcmdlen;
         idrcmdcnt++;

         *cmdcount = idrcmdcnt;
         *cmdlen = msgIndex;
      }
      else
      {
         printf("DIF Ethernet Interrupt Support Prior to Generation 4 Ethernet commands currently not supported\n");
         status = NAI_ERROR_NOT_SUPPORTED;
      }
   }
   return status;
}

/**************************************************************************************************************/
/**
<summary>
This function formats the buffer for the Ethernet Read Registers command.
</summary>
*/
/**************************************************************************************************************/
static void MakeDIFReadRegsCommand(bool_t bGen4Ether, uint16_t startIndex, uint32_t moduleOffset, uint8_t commands[], uint16_t *cmdlen,nai_intf_t boardInterface)
{
   uint16_t msgIndex = startIndex;
   uint16_t seqno;
   uint32_t count, stride;
   uint32_t regaddr;

   if (bGen4Ether)
   {
      /* Create a ReadRegs command with the following attributes:
            Onboard Access, 32-bit Register Size,
            Reg Address: NAI_DIF_GEN5_REG_BIT_LATCHED_STATUS_ADD (to read the BIT, Lo-Hi, Hi-Lo and Overcurrent statuses)
            Count: 4, Stride 0x10
      */
      seqno = 0;
      regaddr = moduleOffset + NAI_DIF_GEN5_REG_BIT_LATCHED_STATUS_ADD;
      count = 4;
      stride = 0x10;
      msgIndex = (uint16_t)nai_ether_MakeReadMessage(&commands[startIndex],seqno,NAI_ETHER_GEN4,boardInterface,regaddr,stride,count,NAI_REG32);

      *cmdlen = msgIndex;
   }
}

/**************************************************************************************************************/
/**
<summary>
This function formats the buffer for the Ethernet Write Registers command.
</summary>
*/
/**************************************************************************************************************/
static void MakeDIFWriteRegsCommand(bool_t bGen4Ether, uint16_t startIndex, uint32_t moduleOffset, uint8_t commands[], uint16_t *cmdlen,nai_intf_t boardInterface)
{
   uint16_t msgIndex = startIndex;
   uint16_t seqno;
   uint32_t count, stride;
   uint32_t regaddr;
   uint32_t data[4] = {0x00FFFFFF, 0x00FFFFFF, 0x00FFFFFF, 0x00FFFFFF};  /* Clear all interrupt bits */

   if (bGen4Ether)
   {
      /* Create a WriteRegs command with the following attributes:
            Onboard Access, 32-bit Register Size,
            Reg Address: NAI_DIF_GEN5_REG_BIT_LATCHED_STATUS_ADD (to read the BIT, Lo-Hi, Hi-Lo and Overcurrent statuses)
            Count: 4, Stride 0x10
            Data: 0xFFFFFFFF (clear all interrupts)
      */
      seqno = 0;
      regaddr = moduleOffset + NAI_DIF_GEN5_REG_BIT_LATCHED_STATUS_ADD;
      count = 4;
      stride = 0x10;

      msgIndex = (uint16_t)nai_ether_BeginWriteMessage(&commands[startIndex],seqno,NAI_ETHER_GEN4,boardInterface,regaddr,stride,count,NAI_REG32);
      if (msgIndex >= 0)
      {
         msgIndex = (uint16_t)nai_ether_WriteMessageData(&commands[startIndex],msgIndex,NAI_REG32,&data,NAI_REG32,count);

         if (msgIndex >= 0)
         {
            msgIndex = (uint16_t)nai_ether_FinishMessage(&commands[startIndex],msgIndex,NAI_ETHER_GEN4);
         }
      }
      *cmdlen = msgIndex;
   }
}

/**************************************************************************************************************/
/**
<summary>
This thread calls CreateDIFIDRTCPServer or CreateDIFIDRUDPServer depending on the
DEF_SER_RESPONSE_PROTOCOL to receive the Interrupt Driven Response (IDR) Unprompted Ethernet Replies.
</summary>
*/
/**************************************************************************************************************/
#if defined (__VXWORKS__)
 int UPR_DIFEthInt_Handler( int32_t nParam )
 {
#elif LINUX
 static void* UPR_DIFEthInt_Handler(void *lpParam )
 {
#else /* Default Windows */
 DWORD WINAPI UPR_DIFEthInt_Handler( LPVOID lpParam )
 {
#endif

   uint16_t protocol = DEF_DIF_RESPONSE_PROTOCOL;

#if defined (WIN32)
   UNREFERENCED_PARAMETER(lpParam);
#endif

   printf("\nUnprompted Reply Thread Started....\n");
   if (protocol == ETHER_GEN4_TCP_PROTOCOL)
      CreateDIFIDRTCPServer();
   else
      CreateDIFIDRUDPServer();
   printf("\nUnprompted Reply Thread Terminated\n");
   return 0;
}

/**************************************************************************************************************/
/**
<summary>
This function creates a TCP Listener socket to receive the Interrupt Driven Response (IDR) Unprompted Ethernet Replies
and waits for the Ethernet messages.
</summary>
*/
/**************************************************************************************************************/
static void CreateDIFIDRTCPServer(void)
{
   nai_socket_t listensock = INVALID_SOCKET, clientsock = INVALID_SOCKET;
   struct addrinfo hints;
   struct addrinfo *info;
   char_t portbuf[10];
   uint8_t recvbuf[NAI_ETHER_MAX_PACKET_SIZE_BYTES];
   int32_t recvbuflen = NAI_ETHER_MAX_PACKET_SIZE_BYTES;
   int32_t result;

#if defined (WIN32)
   WSADATA wsaData;
   result = WSAStartup(MAKEWORD(2,2), &wsaData);
   if (result != 0)
   {
      printf("WSAStartup failed with error: %d\n", result);
      return;
   }
#endif

   ZeroMemory(&hints, sizeof(hints));
   hints.ai_family = AF_INET;
   hints.ai_socktype = SOCK_STREAM;
   hints.ai_protocol = IPPROTO_TCP;
   hints.ai_flags = AI_PASSIVE;

   /* Resolve the server address and port */
   sprintf((char *)portbuf, "%d", DEF_DIF_RESPONSE_PORT);
#if defined (WIN32)
   result = getaddrinfo(NULL, (PCSTR)portbuf, &hints, &info);
#elif defined(LINUX) || defined(__VXWORKS__)
   result = getaddrinfo(NULL, portbuf, &hints, &info);
#endif
   if ( result != 0 )
   {
      printf("getaddrinfo failed with error: %d\n", result);
#if defined (WIN32)
      WSACleanup();
#endif
      return;
   }

   /* Create a SOCKET for connecting to server */
   listensock = socket(info->ai_family, info->ai_socktype, info->ai_protocol);
   if (listensock == INVALID_SOCKET)
   {
#if defined (WIN32)
      printf("socket failed with error: %ld\n", WSAGetLastError());
#elif defined(LINUX) || defined(__VXWORKS__)
      printf("socket failed with error: %s\n", strerror(errno));
#endif
      freeaddrinfo(info);
#if defined (WIN32)
      WSACleanup();
#endif
      return;
   }

   /* Setup the TCP listening socket */
   result = bind( listensock, info->ai_addr, (int)info->ai_addrlen);
   if (result == SOCKET_ERROR)
   {
#if defined (WIN32)
      printf("bind failed with error: %d\n", WSAGetLastError());
#elif defined(LINUX) || defined(__VXWORKS__)
      printf("bind failed with error: %s\n", strerror(errno));
#endif
      freeaddrinfo(info);
      closesocket(listensock);
#if defined (WIN32)
      WSACleanup();
#endif
      return;
   }

   freeaddrinfo(info);

   result = listen(listensock, SOMAXCONN);
   if (result == SOCKET_ERROR)
   {
#if defined (WIN32)
      printf("listen failed with error: %d\n", WSAGetLastError());
#elif defined(LINUX) || defined(__VXWORKS__)
      printf("listen failed with error: %s\n", strerror(errno));
#endif
      closesocket(listensock);
#if defined (WIN32)
      WSACleanup();
#endif
      return;
   }

   /* Accept a client socket */
   clientsock = accept(listensock, NULL, NULL);
   if (clientsock == INVALID_SOCKET)
   {
#if defined (WIN32)
      printf("accept failed with error: %d\n", WSAGetLastError());
#elif defined(LINUX) || defined(__VXWORKS__)
      printf("accept failed with error: %s\n", strerror(errno));
#endif
      closesocket(listensock);
#if defined (WIN32)
      WSACleanup();
#endif
      return;
   }

   /* No longer need server socket */
   closesocket(listensock);

   printf("Ready to receive a TCP messages...\n");

   /* Receive until the peer shuts down the connection */
   do
   {
      result = recv(clientsock, (char *)recvbuf, recvbuflen, 0);
      if (result > 0)
      {
         printf("\n\nTCP Server: Bytes received: %d\n", result);
         DecodeUPRDIFIDRMessages(recvbuf, result);
      }
      else if (result == 0)
         printf("Connection closing...\n");
      else
      {
#if defined (WIN32)
         printf("recv failed with error: %d\n", WSAGetLastError());
#elif defined(LINUX) || defined(__VXWORKS__)
         printf("recv failed with error: %s\n", strerror(errno));
#endif
         closesocket(clientsock);
#if defined (WIN32)
         WSACleanup();
#endif
         return;
      }
    } while ((result > 0) && (terminateDIFThread == FALSE));

    /* shutdown the connection when done */
    result = shutdown(clientsock, SD_SEND);
    if (result == SOCKET_ERROR)
    {
#if defined (WIN32)
       printf("shutdown failed with error: %d\n", WSAGetLastError());
#elif defined(LINUX) || defined(__VXWORKS__)
       printf("shutdown failed with error: %s\n", strerror(errno));
#endif
       closesocket(clientsock);
#if defined (WIN32)
       WSACleanup();
#endif
       return;
    }

    /*cleanup */
    closesocket(clientsock);
#if defined (WIN32)
    WSACleanup();
#endif
}

/**************************************************************************************************************/
/**
<summary>
This function creates a UDP Listener socket to receive the Interrupt Driven Response (IDR) Unprompted Ethernet Replies
and waits for the Ethernet messages.
</summary>
*/
/**************************************************************************************************************/
static void CreateDIFIDRUDPServer()
{
   nai_socket_t recvsock;
   uint8_t recvbuf[NAI_ETHER_MAX_PACKET_SIZE_BYTES];
   int32_t recvbuflen = NAI_ETHER_MAX_PACKET_SIZE_BYTES;
#if defined (WIN32)
   SOCKADDR_IN recvaddr;
   SOCKADDR_IN sendaddr;
#elif defined(LINUX) || defined(__VXWORKS__)
   struct sockaddr_in recvaddr;
   struct sockaddr_in sendaddr;
#endif
   socklen_t sendaddrsize = sizeof(sendaddr);
   int32_t result;

#if defined (WIN32)
   WSADATA wsaData;
   result = WSAStartup(MAKEWORD(2,2), &wsaData);
   if (result != 0)
   {
      printf("WSAStartup failed with error: %d\n", result);
      return;
   }
#endif

   /* Create a new socket to receive datagrams on. */
   recvsock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
   if (recvsock == INVALID_SOCKET)
   {
#if defined (WIN32)
      printf("socket failed with error: %ld\n", WSAGetLastError());
#elif defined(LINUX) || defined(__VXWORKS__)
      printf("socket failed with error: %s\n", strerror(errno));
#endif
#if defined (WIN32)
      WSACleanup();
#endif
      return;
   }

   /* Set up a SOCKADDR_IN structure that will tell bind that we
      want to receive datagrams from all interfaces using port DEF_RESPONSE_PORT.
   */
   /* The IPv4 family */
   recvaddr.sin_family = AF_INET;
   recvaddr.sin_port = htons(DEF_DIF_RESPONSE_PORT);
   /* From all interface (0.0.0.0) */
   recvaddr.sin_addr.s_addr = htonl(INADDR_ANY);

   /* Associate the address information with the socket using bind.
      At this point you can receive datagrams on your bound socket.
   */
#if defined (WIN32)
   result = bind(recvsock, (SOCKADDR *)&recvaddr, sizeof(recvaddr));
#elif defined(LINUX) || defined(__VXWORKS__)
   result = bind(recvsock, (struct sockaddr *)&recvaddr, sizeof(recvaddr));
#endif
   if (result == SOCKET_ERROR)
   {
#if defined (WIN32)
      printf("bind failed with error: %d\n", WSAGetLastError());
#elif defined(LINUX) || defined(__VXWORKS__)
      printf("bind failed with error: %s\n", strerror(errno));
#endif
      closesocket(recvsock);
#if defined (WIN32)
      WSACleanup();
#endif
      return;
   }

   printf("Ready to receive UDP messages...\n");

   while (terminateDIFThread == FALSE)
   {
      /* Call recvfrom() to get it then display the received data. */
#if defined (WIN32)
      result = recvfrom(recvsock, (char *)recvbuf, recvbuflen,
                                          0, (SOCKADDR *)&sendaddr, &sendaddrsize);
#elif defined(LINUX) || defined(__VXWORKS__)
      result = recvfrom(recvsock, (char *)recvbuf, recvbuflen, 0, (struct sockaddr *)&sendaddr, &sendaddrsize);
#endif
      if ( result > 0 )
      {
         printf("\n\nUDP Server: Bytes received: %d\n", result);
         DecodeUPRDIFIDRMessages(recvbuf, result);
      }
      else if ( result <= 0 )
#if defined (WIN32)
         printf("Connection closed with error code: %ld\n", WSAGetLastError());
#elif defined(LINUX) || defined(__VXWORKS__)
         printf("Connection closed with error code: %s\n", strerror(errno));
#endif
      else
#if defined (WIN32)
         printf("recvfrom() failed with error code: %d\n", WSAGetLastError());
#elif defined(LINUX) || defined(__VXWORKS__)
         printf("recvfrom() failed with error code: %s\n", strerror(errno));
#endif
   }

   /* When application is finished receiving datagrams close the socket. */
   printf("Server: Finished receiving. Closing the listening socket...\n");
   closesocket(recvsock);
#if defined (WIN32)
   WSACleanup();
#endif
   return;
}

/**************************************************************************************************************/
/**
<summary>
This function calls ParseDIFIDRResponse() to break down the IDR message received to individual Ethernet messages
and calls DisplayDecodedDIFIDRResponse() to display the data in the Ethernet message.
</summary>
*/
/**************************************************************************************************************/
static void DecodeUPRDIFIDRMessages(const uint8_t msg[], int32_t msgsize)
{
   uint32_t arraysize = MAX_ETHER_IDR_CMD_CNT*MAX_ETHER_BLOCK_REG_CNT;
   uint16_t responselen;
   uint8_t response[MAX_ETHER_BLOCK_REG_CNT];
   int32_t startIndex;

   startIndex = 0;
   while (startIndex < msgsize)
   {
      if (ParseDIFIDRResponse(startIndex, arraysize, (uint8_t *)msg, &responselen, MAX_ETHER_BLOCK_REG_CNT, response))
      {
         startIndex += responselen;
         DisplayDecodedDIFIDRResponse(responselen, response);
      }
   }
}

/**************************************************************************************************************/
/**
<summary>
This function break downs the IDR message received to individual Ethernet messages.
</summary>
*/
/**************************************************************************************************************/
static bool_t ParseDIFIDRResponse(int32_t startIndex, int32_t rsparraysize, uint8_t response[], uint16_t *idrrsplen, int32_t idrrsparraysize, uint8_t idr_response[])
{
   bool_t bParsed = FALSE;
   bool_t bContinueCopy = TRUE;
   uint16_t preamble, postamble;
   int32_t rspIndex = startIndex;
   int32_t idrIndex = 0;

   preamble = (response[startIndex] << 8) | response[startIndex+1];
   if (bGen4DIFIDRCommands)
   {
      if (preamble == ETHER_GEN4_PREAMBLE)
      {
         while ((bContinueCopy) && (idrIndex < idrrsparraysize) && (rspIndex < rsparraysize-1))
         {
            postamble = (response[rspIndex] << 8) | response[rspIndex+1];
            if (postamble == ETHER_GEN4_POSTAMBLE)
            {
               idr_response[idrIndex++] = response[rspIndex++];
               idr_response[idrIndex++] = response[rspIndex++];
               bContinueCopy = FALSE;
            }
            else
            {
               idr_response[idrIndex++] = response[rspIndex++];
            }
         }
         bParsed = TRUE;
         *idrrsplen = (uint16_t)idrIndex;
      }
   }
   else
   {
      printf("DIF Ethernet Interrupt Support Prior to Generation 4 Ethernet commands currently not supported\n");
   }
   return bParsed;
}

/**************************************************************************************************************/
/**
<summary>
This function displays the data in the Ethernet message.
</summary>
*/
/**************************************************************************************************************/
static void DisplayDecodedDIFIDRResponse(uint16_t responselen, uint8_t response[])
{
   uint16_t seq;
   nai_ether_typecode_t tc;
   nai_ether_gen_t gen;
   int32_t size;
   int32_t offset;
   uint16_t seqrsptype;
   uint16_t seqrspidindex;
   uint16_t seqcmdindex;
   uint16_t datacnt;
   uint32_t data;
   int32_t i;

   if (bGen4DIFIDRCommands)
      gen = NAI_ETHER_GEN4;
   else
      gen = NAI_ETHER_GEN3;

   offset = nai_ether_DecodeMessageHeader(response, responselen, &seq, &tc, gen, &size);

   printf("Size=%d   ", size);

   /* Parse IDR Response Sequence Value */
   seqrsptype = seq & ETHER_GEN4_SEQ_UPR_MASK;
   seqrspidindex = (seq & (ETHER_GEN4_SEQ_ID_MASK)) >> ETHER_GEN4_SEQ_ID_SHIFT;
   seqcmdindex = (seq & (ETHER_GEN4_SEQ_CMD_MASK)) >> ETHER_GEN4_SEQ_CMD_SHIFT;
   printf("seq:0x%04X (", seq);
   if (seqrsptype == ETHER_GEN4_SEQ_UPR_TDR)
      printf("Type=Unprompted TDR ");
   else if (seqrsptype == ETHER_GEN4_SEQ_UPR_IDR)
      printf("Type=Unprompted IDR ");
   else
      printf("Type=UNKNOWN(0x%X) ", seqrsptype);
   printf("ID=%d Cmd=%d)   ", seqrspidindex+1, seqcmdindex+1);

   switch (tc)
   {
   case NAI_ETHER_TYPECODE_RSP_COMMAND_COMPLETE_READ_4:
      printf("Typecode: Read Regs (0x%4X)\n", tc);
      datacnt = (responselen - 10)/NAI_REG32;
      printf("   Data (Count=%d): ", datacnt);
      for (i = 0; i < datacnt; i++)
      {
         if (i != 0)
            printf(",");
         data = 0;
         data = response[offset++] << 24;
         data |=  response[offset++] << 16;
         data |=  response[offset++] << 8;
         data |= response[offset++];
         printf("0x%08X",data);
      }
      printf("\n");
      break;
   case NAI_ETHER_TYPECODE_RSP_COMMAND_COMPLETE_WRITE_4:
      printf("Typecode: Write Regs (0x%4X)\n", tc);
      break;
   case NAI_ETHER_TYPECODE_RSP_COMMAND_COMPLETE_READ_BLOCK_4:
      printf("Typecode: Read Block (0x%4X)\n", tc);
      datacnt = (responselen - 10)/NAI_REG32;
      printf("   Data (Count=%d): ", datacnt);
      for (i = 0; i < datacnt; i++)
      {
         if (i != 0)
            printf(",");
         data = 0;
         data = response[offset++] << 24;
         data |=  response[offset++] << 16;
         data |=  response[offset++] << 8;
         data |= response[offset++];
         printf("0x%08X",data);
      }
      printf("\n");
      break;
   case NAI_ETHER_TYPECODE_RSP_COMMAND_COMPLETE_WRITE_BLOCK_4:
      printf("Typecode: Write Block (0x%4X)\n", tc);
      break;
   case NAI_ETHER_TYPECODE_RSP_ERROR_BLOCK_NOT_CONFIG_4:
      printf("Typecode: Block Error (Not Configured) (0x%4X)\n", tc);
      break;
   default:
      printf("Typecode: Unknown (0x%4X)\n", tc);
      break;
   }
}

Help Bot

X