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

DSW Interrupt Ethernet

DSW Interrupt Ethernet Sample Application (SSK 1.x)

Overview

The DSW Interrupt Ethernet sample application demonstrates how to receive discrete switch (DSW) interrupt notifications over an Ethernet network using the NAI Software Support Kit (SSK 1.x) Interrupt Driven Response (IDR) mechanism. When a Lo-Hi or Hi-Lo transition occurs on a discrete channel, the board generates an interrupt and — instead of invoking a local ISR — sends a UDP packet to a remote host containing the interrupt status registers and any embedded read/write commands you configured. Your application runs an IDR server that listens for these packets and decodes the transition status.

This is the Ethernet IDR-only variant of the discrete switch interrupt handling samples. It operates on a single channel and delivers all interrupt information in a single UDP message to a remote host. For the combined ISR + IDR version that supports multi-channel monitoring and both onboard/offboard ISR delivery alongside Ethernet IDR, see the DSW Interrupt sample application guide. For a simplified ISR-only starting point with no Ethernet involvement, see the DSW Interrupt Basic sample application guide.

This sample supports the following discrete switch module types: K7, DT2, and DT5.

DSW modules support seven latched status types that can generate interrupts: BIT, Overcurrent, Max-Hi, Min-Lo, Mid-Range, Lo-Hi Transition, and Hi-Lo Transition. This sample monitors the Lo-Hi and Hi-Lo Transition latched status types via two separate IDR IDs — one for each transition direction. The IDR read command reads both status registers in a single strided read operation (DSW_INTERRUPT_RESPONSE_REG_COUNT = 2).

Why Ethernet IDR?

Standard interrupt delivery (ISR) requires your application to run on the same board or be connected via a backplane bus (PCI/PCIe/cPCI). Ethernet IDR removes that constraint entirely:

  • Remote monitoring — your application can run on any host reachable over the network. There is no need for a physical bus connection to the board.

  • All status in one message — the IDR packet contains the interrupt status register value and any read/write command results you configured, eliminating the need for separate register reads after the interrupt fires.

  • Automatic re-arming — you can include a write command in the IDR configuration that clears the latched status register as part of the response, so interrupts re-arm without a separate API call from the host.

  • Reduced host-side complexity — no ISR installation, no IRQ management, no thread synchronization. Your application simply listens on a UDP socket.

The tradeoff is that Ethernet IDR is only available on Gen4 and later boards, and network latency is inherently higher than a local ISR. For latency-critical applications where the host is directly connected to the board, standard ISR delivery may be more appropriate.

Prerequisites

Before running this sample, make sure you have:

  • An NAI board with a discrete switch module installed (K7, DT2, or DT5).

  • A Gen4 or later board with Ethernet connectivity. Earlier board generations do not support the Ethernet IDR protocol.

  • 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 running this sample and the board. The host must be reachable at the IP address configured in the IDR settings (default: 192.168.1.100).

How to Run

Launch the DSW_Interrupt_Ethernet executable from your build output directory. On startup the application looks for a configuration file (default_DSW_Interrupt_Ethernet.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 channel selection, IDR network settings, and interrupt display options, then begins listening for IDR packets from the board.

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 DSW. For details on board connection configuration, see the First Time Setup Guide.

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

  1. Initialize DSW, interrupt, and IDR configuration structures with defaults using initializeDSWConfigurations(), initializeInterruptConfigurations(), and initializeIDRConfigurations(). The IDR initialization sets the default response IP address (192.168.1.100), UDP port (52802), and protocol (ETHER_GEN4_UDP_PROTOCOL).

  2. Call naiapp_RunBoardMenu() to load a saved configuration file (if one exists) or present the interactive board menu. The configuration file (default_DSW_Interrupt_Ethernet.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.

  3. Query the user for card index and module number.

  4. Retrieve the module ID with naibrd_GetModuleID() to verify a discrete switch module is installed at the selected slot.

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

   initializeDSWConfigurations(0, 0, 0, 0, 0, 0);
   initializeInterruptConfigurations(FALSE, FALSE, FALSE, 0, NAIBRD_INT_STEERING_ON_BOARD_1, -1, 0);
   initializeIDRConfigurations(0, 0, DEF_RX_RESPONSE_PROTOCOL, DEF_RX_RESPONSE_PORT,
                              DEF_RX_RESPONSE_IPv4_ADDR, DEF_RX_RESPONSE_IPv4_LENGTH,
                              COMMANDS, 0, 0, DEF_ETHERNET_DSW_LOHI_IDR_ID);

   if (naiapp_RunBoardMenu(CONFIG_FILE) == TRUE)
   {
      while (stop != TRUE)
      {
         stop = naiapp_query_CardIndex(naiapp_GetBoardCnt(), 0, &cardIndex);
         inputDSWConfig.cardIndex = cardIndex;
         if (stop != TRUE)
         {
            check_status(naibrd_GetModuleCount(cardIndex, &moduleCnt));
            stop = naiapp_query_ModuleNumber(moduleCnt, 1, &module);
            inputDSWConfig.module = module;
            if (stop != TRUE)
            {
               inputDSWConfig.modid = naibrd_GetModuleID(cardIndex, module);
               if ((inputDSWConfig.modid != 0))
               {
                  Run_DSW_Interrupt_Basic_Ethernet();
               }
            }
         }
         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;
}

Note the three initialization calls before the board menu. initializeIDRConfigurations() is unique to the Ethernet variant — it populates the IDRConfig structure with default network settings that are used later when configuring the board’s IDR engine. The IDR ID is initialized to DEF_ETHERNET_DSW_LOHI_IDR_ID for the Lo-Hi transition IDR.

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 discrete switch module. Use the board menu to verify which slots are populated.

Program Structure

The DSW Interrupt Ethernet sample is split across multiple source files:

  • DSW_Interrupt_Ethernet.c — the application entry point. Contains main() and Run_DSW_Interrupt_Basic_Ethernet(), which orchestrates the Gen4 check, user prompts, IDR setup, interrupt configuration, IDR server execution, and cleanup.

  • nai_dsw_int_ether.c — Ethernet IDR-specific code shared with the DSW_Interrupt full variant. Contains setupIDRConfiguration_DSW(), IDR command construction functions (InitDSWIDRCommands(), MakeDSWReadRegsCommand(), MakeDSWWriteRegsCommand()), and HandleDSWEtherInterrupt() which decodes incoming IDR packets.

  • nai_dsw_int.c — shared interrupt configuration logic. Contains configureDSWToInterrupt(), enableDSWInterrupts(), GetDSWLatchStatusTriggerMode(), and handleDSWInterrupt().

  • nai_dsw_cfg.c — shared discrete switch configuration. Contains initializeDSWConfigurations().

Shared Data Structures

The sample uses three key structures to track configuration state:

/* From nai_dsw_cfg.h */
typedef struct
{
   int32_t cardIndex;
   int32_t module;
   uint32_t modid;
   int32_t channel;
   int32_t maxChannel;
   int32_t minChannel;
} DswConfig;

DswConfig captures the discrete switch module identification and channel settings. In the Ethernet variant, channel specifies the single channel to monitor for interrupts.

/* From naiapp_interrupt.h */
typedef struct _InterruptConfig
{
   bool_t  bPromptForInterruptClear;
   bool_t  bProcessOnboardInterrupts;
   bool_t  displayData;
   int32_t interrupt_Edge_Trigger;
   int32_t steering;
   int32_t irq;
   int32_t cardIndex;
} InterruptConfig;

InterruptConfig captures the interrupt delivery preferences: trigger mode (edge vs. level), steering destination, and whether the IDR commands target the board’s onboard interface or an offboard (PCI) interface. The bProcessOnboardInterrupts flag determines which board interface the IDR uses.

/* From naiapp_interrupt_ether.h */
typedef struct _IDRConfig
{
   int32_t  cardIndex;
   nai_intf_t boardInterface;
   uint16_t protocol;
   uint16_t port;
   uint8_t  *ipAddress;
   uint8_t  ipLength;
   uint8_t  *commands;
   uint16_t cmdcount;
   uint16_t cmdlength;
   uint16_t idrId;
} IDRConfig;

IDRConfig captures the Ethernet IDR network settings: the UDP protocol, destination IP address and port where interrupt notifications are sent, and the command buffer that stores the read/write operations the board executes when an interrupt fires. The cmdcount and cmdlength fields track the number and total byte length of the embedded commands.

Gen4 Ethernet Requirement Check

The first thing Run_DSW_Interrupt_Basic_Ethernet() does after determining the channel count is verify that the connected board supports Gen4 Ethernet commands. This is a hard requirement — earlier board generations do not have the IDR engine.

inputDSWConfig.maxChannel = naibrd_DSW_GetChannelCount(inputDSWConfig.modid);
inputDSWConfig.minChannel = 1;

/* check if DSW module supports GEN 4 Ethernet */
bGen4DSWIDRCommands = SupportsGen4Ether(inputDSWConfig.cardIndex);
if (!bGen4DSWIDRCommands)
{
   printf("DSW Ethernet Interrupt Support Prior to Generation 4 Ethernet commands currently not supported\n");
   bQuit = TRUE;
}

SupportsGen4Ether() is a shared utility function that queries the board’s Ethernet generation capability. If the board does not support Gen4, the application exits the interrupt flow immediately with an error message. There is no fallback to an older protocol — you must use a Gen4 or later board for Ethernet IDR.

In your own application, always call SupportsGen4Ether() before attempting any IDR configuration. Calling naibrd_Ether_SetIDRConfig() on a pre-Gen4 board will fail.

Important

Common Errors

  • "Generation 4 Ethernet commands currently not supported" — the connected board does not support IDR. Verify you are using a Gen4 or later board. Check the board’s firmware version if you believe the hardware should support Gen4.

User Configuration Prompts

After the Gen4 check passes, the sample prompts the user for several configuration parameters before setting up the IDR and interrupt system. In your own application, you would set these values programmatically rather than prompting interactively.

bQuit = naiapp_query_ChannelNumber(inputDSWConfig.maxChannel, inputDSWConfig.minChannel,
                                   &inputDSWConfig.channel);

bQuit = QueryIDRConfigInformation(&inputIDRConfig);

bQuit = QueryUserForOnboardOffboardInterrupts(&inputInterruptConfig.bProcessOnboardInterrupts);

bQuit = QueryUserForEtherIDRMsgDisplay(&bDisplayEtherUPR);

The prompts collect:

  • Channel number — which discrete channel to monitor for interrupts (1 through the module’s maximum channel count).

  • IDR configuration — QueryIDRConfigInformation() prompts for the destination IP address, port, and protocol. Defaults are 192.168.1.100, port 52802, UDP protocol.

  • Onboard/offboard processing — determines the board interface and interrupt steering. Onboard uses NAI_INTF_ONBOARD with NAIBRD_INT_STEERING_ON_BOARD_1 steering. Offboard uses NAI_INTF_PCI with NAIBRD_INT_STEERING_CPCI_APP steering.

  • IDR message display — whether to show the raw Ethernet IDR message on the console.

IDR Configuration

The IDR (Interrupt Driven Response) is the core mechanism that makes Ethernet-based interrupt delivery work. When an interrupt fires, the board’s IDR engine executes a preconfigured sequence of register read/write commands, packages the results into a UDP packet, and sends it to the specified IP address and port. Your application never needs to issue separate register read commands after the interrupt — all the data arrives in a single network message.

The DSW sample configures two IDR IDs — one for Lo-Hi transitions (DEF_ETHERNET_DSW_LOHI_IDR_ID) and one for Hi-Lo transitions (DEF_ETHERNET_DSW_HILO_IDR_ID). Both are bound to the same IDR command set but trigger on different interrupt vectors (NAI_DSW_LOHI_INTERRUPT_VECTOR and NAI_DSW_HILO_INTERRUPT_VECTOR).

Setting Up the IDR

After the user selects onboard or offboard processing, the sample configures the board interface and steering, then calls setupIDRConfiguration_DSW() to build and install the IDR command set:

if (inputInterruptConfig.bProcessOnboardInterrupts == TRUE)
{
   inputIDRConfig.cardIndex = inputDSWConfig.cardIndex;
   inputIDRConfig.boardInterface = NAI_INTF_ONBOARD;
   inputInterruptConfig.steering = NAIBRD_INT_STEERING_ON_BOARD_1;
}
else /* OffBoard Interrupt */
{
   inputIDRConfig.cardIndex = 0;
   inputIDRConfig.boardInterface = NAI_INTF_PCI;
   inputInterruptConfig.steering = NAIBRD_INT_STEERING_CPCI_APP;
}

setupIDRConfiguration_DSW(inputDSWConfig, &inputIDRConfig, bGen4DSWIDRCommands);
check_status(naibrd_Ether_StartIDR(inputIDRConfig.cardIndex, (uint16_t)DEF_ETHERNET_DSW_LOHI_IDR_ID));
check_status(naibrd_Ether_StartIDR(inputIDRConfig.cardIndex, (uint16_t)DEF_ETHERNET_DSW_HILO_IDR_ID));

The steering value NAIBRD_INT_STEERING_ON_BOARD_1 tells the module to route the interrupt to the board’s onboard processor, which then triggers the IDR engine. Note that naibrd_Ether_StartIDR() is called twice — once for each IDR ID — because Lo-Hi and Hi-Lo transitions use separate interrupt vectors.

Building IDR Commands

setupIDRConfiguration_DSW() in nai_dsw_int_ether.c clears any previous IDR configuration and then constructs the command buffer for both IDR IDs:

void setupIDRConfiguration_DSW(DswConfig inputDSWConfig, IDRConfig* inputIDRConfig,
                               bool_t bGen4DSWIDRCommands)
{
   int32_t cardIndex = inputIDRConfig->cardIndex;
   uint16_t protocol = inputIDRConfig->protocol;
   uint16_t port = inputIDRConfig->port;
   uint8_t* ipAddress = inputIDRConfig->ipAddress;
   uint8_t ipLength = inputIDRConfig->ipLength;
   int32_t vector1 = NAI_DSW_LOHI_INTERRUPT_VECTOR;
   int32_t vector2 = NAI_DSW_HILO_INTERRUPT_VECTOR;
   uint8_t *commands = inputIDRConfig->commands;
   uint16_t *cmdcount = &inputIDRConfig->cmdcount;
   uint16_t *cmdlength = &inputIDRConfig->cmdlength;
   uint32_t addr = NAI_DSW_GEN5_REG_LO_HI_TRANS_LATCHED_STATUS_ADD;

   check_status(naibrd_Ether_ClearIDRConfig(cardIndex, (uint16_t)DEF_ETHERNET_DSW_LOHI_IDR_ID));
   InitDSWIDRCommands(inputDSWConfig, inputIDRConfig, bGen4DSWIDRCommands, addr);
   check_status(naibrd_Ether_SetIDRConfig(cardIndex, (uint16_t)DEF_ETHERNET_DSW_LOHI_IDR_ID,
      protocol, ipLength, ipAddress, port, vector1, *cmdcount, *cmdlength, commands));
   check_status(naibrd_Ether_ClearIDRConfig(cardIndex, (uint16_t)DEF_ETHERNET_DSW_HILO_IDR_ID));
   check_status(naibrd_Ether_SetIDRConfig(cardIndex, (uint16_t)DEF_ETHERNET_DSW_HILO_IDR_ID,
      protocol, ipLength, ipAddress, port, vector2, *cmdcount, *cmdlength, commands));
}

The key API calls are:

  • naibrd_Ether_ClearIDRConfig() — clears any existing IDR configuration for the specified IDR ID. Always call this before reconfiguring an IDR to avoid stale command data.

  • InitDSWIDRCommands() — builds the embedded Ethernet read command that reads the Lo-Hi and Hi-Lo transition latched status registers when the interrupt fires. The read uses a stride of 16 bytes to capture both registers in one command.

  • naibrd_Ether_SetIDRConfig() — installs the complete IDR configuration on the board: destination protocol, IP address, port, interrupt vector to match, command count, command byte length, and the command buffer itself. This is called twice — once per IDR ID, each bound to a different interrupt vector.

IDR Read Command Construction

InitDSWIDRCommands() calls MakeDSWReadRegsCommand() to construct a Gen4 Ethernet read command targeting the transition status registers:

void MakeDSWReadRegsCommand(IDRConfig* inputIDRConfig, uint32_t boardAddress,
   int32_t moduleOffset, bool_t bGen4Ether, uint16_t startIndex, uint32_t addr)
{
   uint16_t msgIndex = startIndex;
   uint16_t seqno;
   uint32_t count, stride;

   if (bGen4Ether)
   {
      seqno = 0;
      addr = boardAddress + moduleOffset + addr;
      count = DSW_INTERRUPT_RESPONSE_REG_COUNT;
      stride = 16;

      msgIndex = (uint16_t)nai_ether_MakeReadMessage(&inputIDRConfig->commands[startIndex],
         seqno, NAI_ETHER_GEN4, (nai_intf_t)inputIDRConfig->boardInterface,
         addr, stride, count, NAI_REG32);

      inputIDRConfig->cmdlength = inputIDRConfig->cmdlength + msgIndex;
      command_index_interrupt_status = inputIDRConfig->cmdcount;
      inputIDRConfig->cmdcount++;
   }
}

The function computes the absolute register address by adding the board base address, the module offset, and the Lo-Hi transition latched status register offset. The stride is set to 16 so that the single read command captures both the Lo-Hi and Hi-Lo transition latched status registers (they are 16 bytes apart in the register map). DSW_INTERRUPT_RESPONSE_REG_COUNT is 2, meaning two 32-bit registers are read. The command_index_interrupt_status variable records which command index in the IDR response contains the status register values.

You can also add write commands to the IDR buffer using MakeDSWWriteRegsCommand(). This constructs a write command that clears the BIT latched status register to re-arm interrupts automatically as part of the IDR response:

void MakeDSWWriteRegsCommand(DswConfig inputDSWConfig, IDRConfig* inputIDRConfig,
   uint32_t boardAddress, int32_t moduleOffset, bool_t bGen4Ether, uint16_t startIndex)
{
   uint16_t msgIndex = startIndex;
   uint16_t seqno;
   uint32_t count, stride;
   uint32_t regaddr;
   uint32_t data = 0x1 << (inputDSWConfig.channel - 1);
   uint32_t addr = NAI_DSW_GEN5_REG_BIT_LATCHED_STATUS_ADD;

   if (bGen4Ether)
   {
      seqno = 0;
      regaddr = boardAddress + moduleOffset + addr;
      count = 1;
      stride = 4;

      msgIndex = (uint16_t)nai_ether_BeginWriteMessage(&inputIDRConfig->commands[startIndex],
         seqno, NAI_ETHER_GEN4, (nai_intf_t)inputIDRConfig->boardInterface,
         regaddr, stride, count, NAI_REG32);
      msgIndex = (uint16_t)nai_ether_WriteMessageData(&inputIDRConfig->commands[startIndex],
         msgIndex, NAI_REG32, &data, NAI_REG32, count);
      msgIndex = (uint16_t)nai_ether_FinishMessage(&inputIDRConfig->commands[startIndex],
         msgIndex, NAI_ETHER_GEN4);

      inputIDRConfig->cmdlength = inputIDRConfig->cmdlength + msgIndex;
      inputIDRConfig->cmdcount++;
   }
}

The write command uses the three-step message construction pattern: nai_ether_BeginWriteMessage() writes the header, nai_ether_WriteMessageData() appends the data payload (a bitmask for the selected channel), and nai_ether_FinishMessage() finalizes the message. Including this write in the IDR means the board clears its own status register immediately after sending the notification, so interrupts re-arm without requiring a separate API call from the host.

Important

Common Errors

  • naibrd_Ether_SetIDRConfig() fails — verify the IDR ID is valid and that no other IDR is already configured with the same ID. Always call naibrd_Ether_ClearIDRConfig() first.

  • Incorrect register address — the board address and module offset must be queried at runtime with naibrd_GetAddress() and naibrd_GetModuleOffset(). Hardcoded addresses will fail on different board configurations.

  • Wrong board interface — NAI_INTF_ONBOARD is for onboard processing; NAI_INTF_PCI is for offboard. Using the wrong interface causes the IDR read/write commands to target the wrong bus.

Interrupt Configuration

After the IDR is configured and started, the sample configures the discrete switch module to generate interrupts on Lo-Hi and Hi-Lo transitions. This uses the same interrupt configuration functions as the standard (ISR-based) variant.

Module Interrupt Setup

configureDSWToInterrupt() performs the following steps on all channels:

void configureDSWToInterrupt(InterruptConfig inputInterruptConfig, DswConfig inputDSWConfig)
{
   int32_t cardIndex = inputDSWConfig.cardIndex;
   int32_t module = inputDSWConfig.module;
   int32_t interrupt_Edge_Trigger = inputInterruptConfig.interrupt_Edge_Trigger;
   int32_t steering = inputInterruptConfig.steering;
   uint32_t rawstatus = 0;
   int32_t chan;

   enableDSWInterrupts(inputDSWConfig, FALSE);

   check_status(naibrd_DSW_GetGroupStatusRaw(cardIndex, module, 1,
      NAI_DSW_STATUS_LO_HI_TRANS_LATCHED, &rawstatus));
   check_status(naibrd_DSW_ClearGroupStatusRaw(cardIndex, module, 1,
      NAI_DSW_STATUS_LO_HI_TRANS_LATCHED, rawstatus));
   check_status(naibrd_DSW_GetGroupStatusRaw(cardIndex, module, 1,
      NAI_DSW_STATUS_HI_LO_TRANS_LATCHED, &rawstatus));
   check_status(naibrd_DSW_ClearGroupStatusRaw(cardIndex, module, 1,
      NAI_DSW_STATUS_HI_LO_TRANS_LATCHED, rawstatus));

   check_status(naibrd_DSW_SetGroupInterruptVector(cardIndex, module, 1,
      NAI_DSW_STATUS_LO_HI_TRANS_LATCHED, NAI_DSW_LOHI_INTERRUPT_VECTOR));
   check_status(naibrd_DSW_SetGroupInterruptVector(cardIndex, module, 1,
      NAI_DSW_STATUS_HI_LO_TRANS_LATCHED, NAI_DSW_HILO_INTERRUPT_VECTOR));

   for (chan = 1; chan <= inputDSWConfig.maxChannel; chan++)
   {
      check_status(naibrd_DSW_SetEdgeLevelInterrupt(cardIndex, module, chan,
         NAI_DSW_STATUS_LO_HI_TRANS_LATCHED, (nai_dsw_interrupt_t)interrupt_Edge_Trigger));
      check_status(naibrd_DSW_SetEdgeLevelInterrupt(cardIndex, module, chan,
         NAI_DSW_STATUS_HI_LO_TRANS_LATCHED, (nai_dsw_interrupt_t)interrupt_Edge_Trigger));
   }

   check_status(naibrd_DSW_SetGroupInterruptSteering(cardIndex, module, 1,
      NAI_DSW_STATUS_LO_HI_TRANS_LATCHED, steering));
   check_status(naibrd_DSW_SetGroupInterruptSteering(cardIndex, module, 1,
      NAI_DSW_STATUS_HI_LO_TRANS_LATCHED, steering));
}

The steps are:

  1. Disable interrupts — enableDSWInterrupts() with FALSE disables all interrupt sources to prevent spurious triggers during configuration.

  2. Clear latched status — naibrd_DSW_GetGroupStatusRaw() reads the current latched status, then naibrd_DSW_ClearGroupStatusRaw() writes it back to clear. This prevents stale status from triggering an immediate interrupt.

  3. Set vectors — naibrd_DSW_SetGroupInterruptVector() assigns separate vectors for Lo-Hi and Hi-Lo transitions. These vectors must match the vectors specified in the naibrd_Ether_SetIDRConfig() calls so the IDR engine knows which interrupts to service.

  4. Set trigger mode — naibrd_DSW_SetEdgeLevelInterrupt() configures edge (0) or level (1) triggering for each channel and each transition direction.

  5. Set steering — naibrd_DSW_SetGroupInterruptSteering() routes the interrupt to the appropriate destination. For Ethernet IDR, this is NAIBRD_INT_STEERING_ON_BOARD_1 (onboard) so the interrupt reaches the IDR engine.

Enable Interrupts

After configuration, enableDSWInterrupts() enables both transition types on all channels:

enableDSWInterrupts(inputDSWConfig, TRUE);

This calls naibrd_DSW_SetInterruptEnable() for both NAI_DSW_STATUS_LO_HI_TRANS_LATCHED and NAI_DSW_STATUS_HI_LO_TRANS_LATCHED on every channel from minChannel to maxChannel. From this point forward, any Lo-Hi or Hi-Lo transition on any channel will trigger an interrupt, which the IDR engine intercepts and sends as a UDP packet to the configured host.

Important

Common Errors

  • No interrupts received — verify that naibrd_DSW_SetGroupInterruptSteering() used the correct steering constant for Ethernet IDR (NAIBRD_INT_STEERING_ON_BOARD_1 for onboard). Using the wrong steering routes the interrupt to a different destination.

  • Interrupt vector mismatch — the vectors passed to naibrd_DSW_SetGroupInterruptVector() must match the vectors in the two naibrd_Ether_SetIDRConfig() calls. A mismatch means the IDR engine will not recognize the interrupt.

  • Stale interrupts fire immediately — always clear status with naibrd_DSW_ClearGroupStatusRaw() before enabling interrupts. Latched status from a previous run will trigger immediately if not cleared.

IDR Server and UDP Message Handling

Once the IDR is started and interrupts are enabled, the sample launches the IDR server to listen for incoming UDP packets from the board:

dswEtherIntFunc = HandleDSWEtherInterrupt;
bQuit = runIDRServer(inputIDRConfig);

The function pointer assignment registers HandleDSWEtherInterrupt() as the callback used by the IDR server framework. runIDRServer() is a shared utility that opens a UDP socket on the configured port and enters a receive loop. Each time a packet arrives, it dispatches to the registered handler function.

Decoding IDR Packets

HandleDSWEtherInterrupt() in nai_dsw_int_ether.c processes each incoming IDR packet. The IDR response contains the read command result with the Lo-Hi and Hi-Lo transition latched status register values:

void HandleDSWEtherInterrupt(uint16_t msglen, uint8_t msg[], uint16_t tdr_idr_id)
{
   uint16_t seq;
   nai_ether_typecode_t tc;
   nai_ether_gen_t gen = NAI_ETHER_GEN4;
   int32_t size;
   int32_t offset;
   uint16_t datacnt = 0;
   uint32_t data;
   uint32_t dswstatus_int[DSW_INTERRUPT_RESPONSE_REG_COUNT];
   nai_dsw_status_type_t dsw_status_type = NAI_DSW_STATUS_BIT_LATCHED;
   int32_t i;
   offset = nai_ether_DecodeMessageHeader(msg, msglen, &seq, &tc, gen, &size);

   switch (tc)
   {
      case NAI_ETHER_TYPECODE_RSP_COMMAND_COMPLETE_READ_4:
         datacnt = (msglen - 10) / NAI_REG32;
         for (i = 0; i < datacnt; i++)
         {
            data = 0;
            data = msg[offset++] << 24;
            data |= msg[offset++] << 16;
            data |= msg[offset++] << 8;
            data |= msg[offset++];
            if (i < DSW_INTERRUPT_RESPONSE_REG_COUNT)
               dswstatus_int[i] = data;
         }
         break;
   }

The handler performs the following steps:

  1. Decode the message header — nai_ether_DecodeMessageHeader() extracts the sequence number, type code, and payload size from the raw UDP packet.

  2. Extract status registers — for read command completions (NAI_ETHER_TYPECODE_RSP_COMMAND_COMPLETE_READ_4), the handler extracts the register data. Because the IDR read used a stride of 16 and count of 2, the response contains two 32-bit values: the Lo-Hi transition latched status (index 0) and the Hi-Lo transition latched status (index 1).

  3. Display and clear per status type — the handler iterates through the status array, identifies which transition occurred based on the index, prints the status, and calls naibrd_DSW_ClearGroupStatusRaw() to clear each active status and re-arm the interrupt:

   if (datacnt == DSW_INTERRUPT_RESPONSE_REG_COUNT)
   {
      for (i = 0; i < DSW_INTERRUPT_RESPONSE_REG_COUNT; i++)
      {
         switch (i)
         {
            case 0:
               dsw_status_type = NAI_DSW_STATUS_LO_HI_TRANS_LATCHED;
               break;
            case 1:
               dsw_status_type = NAI_DSW_STATUS_HI_LO_TRANS_LATCHED;
               break;
         }
         if (dswstatus_int[i] != 0)
         {
            /* Print and clear the transition status */
            check_status(naibrd_DSW_ClearGroupStatusRaw(inputDSWConfig.cardIndex,
               inputDSWConfig.module, 1, dsw_status_type, dswstatus_int[i]));
         }
      }
   }
}

The status bitmask encodes which channels triggered the transition. Each bit position corresponds to a channel number (bit 0 = channel 1, bit 1 = channel 2, etc.). The handler clears the status by writing the same bitmask back to the latched status register with naibrd_DSW_ClearGroupStatusRaw(), which re-arms the interrupt for the next event.

Important

Common Errors

  • No IDR packets received — verify the destination IP address matches the host running the application. Check that no firewall is blocking UDP port 52802. Confirm the board has network connectivity.

  • IDR packets arrive but show status 0x0 — the interrupt may have already been cleared by a write command in the IDR, or no transition has occurred on the monitored channels. Verify the discrete input signal is toggling.

  • Only Lo-Hi or only Hi-Lo transitions reported — both IDR IDs must be started with naibrd_Ether_StartIDR(). If one is missing, interrupts for that transition direction will not generate IDR packets.

Cleanup

When the user quits the IDR server loop, the sample performs orderly cleanup of both module and board configurations:

/***** 7. Clear Module Configurations *****/
enableDSWInterrupts(inputDSWConfig, FALSE);

/***** 8. Clear Board Configurations *****/
check_status(naibrd_Ether_StopIDR(inputIDRConfig.cardIndex,
   (uint16_t)DEF_ETHERNET_DSW_LOHI_IDR_ID));
check_status(naibrd_Ether_ClearIDRConfig(inputIDRConfig.cardIndex,
   (uint16_t)DEF_ETHERNET_DSW_LOHI_IDR_ID));

The cleanup sequence is:

  1. Disable interrupts — enableDSWInterrupts() with FALSE disables the interrupt enable for all channels and both transition types.

  2. Stop the IDR — naibrd_Ether_StopIDR() halts the IDR engine on the board. After this call, the board will no longer send UDP notifications for this IDR ID.

  3. Clear the IDR configuration — naibrd_Ether_ClearIDRConfig() removes the IDR command buffer and network settings from the board.

Always stop the IDR before clearing its configuration. Clearing the configuration while the IDR is still running can result in undefined behavior.

Configuration File

The sample uses the configuration file default_DSW_Interrupt_Ethernet.txt to store board connection settings. This file is not included in the SSK — it is created when you save your connection settings from the board menu during the first run. The file stores the board interface type, IP address or bus address, and other connection parameters so that subsequent runs can skip the interactive menu and connect automatically.

The default IDR network settings (IP address 192.168.1.100, port 52802, UDP protocol) are hardcoded in the source as compile-time defaults. To change them, either modify the source constants or respond to the interactive prompts when the application runs.

static uint8_t DEF_RX_RESPONSE_IPv4_ADDR[] = {192,168,1,100};

#define DEF_RX_RESPONSE_PORT        52802
#define DEF_RX_RESPONSE_PROTOCOL    ETHER_GEN4_UDP_PROTOCOL
#define DEF_RX_RESPONSE_IPv4_LENGTH ETHER_GEN4_IPv4_ADDR_LEN
#define DSW_INTERRUPT_RESPONSE_REG_COUNT  2

Troubleshooting Reference

Note
This section summarizes errors covered in the preceding sections and provides additional network-specific diagnostics. Consult your module’s manual for hardware-specific diagnostics.
Error / Symptom Possible Causes Suggested Resolution

"Generation 4 Ethernet commands currently not supported"

Board does not support Gen4 Ethernet protocol.

Use a Gen4 or later board. Check firmware version with your NAI support contact.

No IDR packets received

Destination IP address does not match the host. Firewall blocking UDP port. Board has no network connectivity. IDR not started.

Verify IP address matches the host running the application. Open UDP port 52802 in the firewall. Ping the board to confirm connectivity. Confirm naibrd_Ether_StartIDR() was called for both Lo-Hi and Hi-Lo IDR IDs.

IDR packets arrive but show status 0x0

Interrupt already cleared by an embedded write command. No transition occurred on monitored channels.

Verify the discrete input signal is actively toggling between states. Check that the IDR read command targets the correct register address.

Only Lo-Hi transitions reported (or only Hi-Lo)

Only one IDR ID was started. Vector mismatch for the missing transition direction.

Confirm naibrd_Ether_StartIDR() was called for both DEF_ETHERNET_DSW_LOHI_IDR_ID and DEF_ETHERNET_DSW_HILO_IDR_ID. Verify both vectors match their respective naibrd_Ether_SetIDRConfig() calls.

naibrd_Ether_SetIDRConfig() returns error

Stale IDR configuration not cleared. Invalid IDR ID. Board does not support IDR.

Call naibrd_Ether_ClearIDRConfig() before naibrd_Ether_SetIDRConfig(). Verify the IDR ID is within the valid range for your board.

Interrupts fire once but do not re-arm

Latched status not cleared after processing. Missing naibrd_DSW_ClearGroupStatusRaw() call in the handler.

Ensure the handler calls naibrd_DSW_ClearGroupStatusRaw() after processing each interrupt. Alternatively, include a write command in the IDR that clears the status register automatically.

No board found / Connection timeout

Board not powered or connected. Incorrect interface or address in configuration file.

Verify physical connection. Delete the configuration file and re-run to enter settings interactively.

Invalid card or module index

Zero-based card index or one-based module index mismatch.

Cards are zero-indexed, modules are one-indexed. Verify values match your hardware setup.

Module not present at selected slot

Discrete switch module not installed in the selected slot.

Use the board menu to verify which slots are populated with K7, DT2, or DT5 modules.

Full Source

DSW_Interrupt_Ethernet.c

Full Source — DSW_Interrupt_Ethernet.c (SSK 1.x)
/**************************************************************************************************************/
/**
<summary>

The DSW_Interrupt_Ethernet program demonstrates how to perform an interrupt when a single channel receives
a message. The purpose of this program is to demonstrate the method calls in the naibrd library for performing
the interrupt. More information on this process can be found in the naibrd SSK Quick Guide(Interrupts) file.

</summary>
*/
/**************************************************************************************************************/

/************************/
/* Include Declarations */
/************************/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>

/*Common Module Specific Sample Program include files*/
#include "nai_dsw_int.h"
#include "nai_dsw_cfg.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"
#include "nai_dsw_int_ether.h"

/* naibrd include files */
#include "nai.h"
#include "naibrd.h"

/* Module Specific NAI Board Library files */
#include "functions/naibrd_dsw.h"
#include "maps/nai_map_dsw.h"

static uint8_t DEF_RX_RESPONSE_IPv4_ADDR[] =   {192,168,1,100};
static uint8_t COMMANDS[MAX_ETHER_IDR_CMD_CNT*MAX_ETHER_BLOCK_REG_CNT];

etherIntFuncDef dswEtherIntFunc;
bool_t bDisplayEtherUPR;
IDRConfig inputIDRConfig;

/* Extern Functions or Variables*/
extern DswConfig inputDSWConfig;
extern InterruptConfig inputInterruptConfig;

/*********************************************/
/* Application Name and Revision Declaration */
/*********************************************/
static const int8_t *CONFIG_FILE = (int8_t *)"default_DSW_Interrupt_Ethernet.txt";

/********************************/
/* Internal Function Prototypes */
/********************************/
static bool_t Run_DSW_Interrupt_Basic_Ethernet();

/**************************************************************************************************************/
/*****                                     Main Routine                                                   *****/
/**************************************************************************************************************/

/**************************************************************************************************************/
/**
<summary>

The main routine assists in gaining access to the board.

The following routines from the nai_sys_cfg.c file are
called to assist with accessing and configuring the board.

 - ConfigDevice
 - DisplayDeviceCfg
 - GetBoardSNModCfg
 - CheckModule

</summary>

*/
/*****************************************************************************/
#if defined (__VXWORKS__)
int32_t DSW_Interrupt_Basic_Ethernet(void)
#else
int32_t main(void)
#endif
{
   bool_t stop = FALSE;
   int32_t cardIndex;
   int32_t moduleCnt;
   int32_t module;
   int8_t inputBuffer[80];
   int32_t inputResponseCnt;

   initializeDSWConfigurations(0, 0, 0, 0, 0, 0);
   initializeInterruptConfigurations(FALSE, FALSE, FALSE, 0, NAIBRD_INT_STEERING_ON_BOARD_1, -1, 0);
   initializeIDRConfigurations(0, 0, DEF_RX_RESPONSE_PROTOCOL, DEF_RX_RESPONSE_PORT, DEF_RX_RESPONSE_IPv4_ADDR, DEF_RX_RESPONSE_IPv4_LENGTH, COMMANDS, 0, 0, DEF_ETHERNET_DSW_LOHI_IDR_ID);

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

            /* Query the user for the module number */
            stop = naiapp_query_ModuleNumber(moduleCnt, 1, &module);
            inputDSWConfig.module = module;
            if (stop != TRUE)
            {
               inputDSWConfig.modid = naibrd_GetModuleID(cardIndex, module);
               if ((inputDSWConfig.modid != 0))
               {
                  Run_DSW_Interrupt_Basic_Ethernet();
               }
            }
         }
         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 is broken into the following major steps. These steps correspond with the steps provided
in the naibrd SSK Quick Guide(Interrupts) file.

2a. Ethernet Interrupt Handling - Setup IDR to handle interrupt

   API CALLS - naibrd_Ether_SetIDRConfig, naibrd_Ether_StartIDR,naibrd_Ether_ClearIDRConfig

3. Enable Module Interrupts- Configures module to interrupt when channel receives DSW message.

   API CALLS - naibrd_DSW_SetInterruptEdgeLevel, naibrd_DSW_SetIntVector, naibrd_DSW_SetInterruptSteering, naibrd_DSW_SetIntEnable

4. Not applicable to DSW module

5. Show Interrupt Handling - The IDR server will listen on the boards ports for IDRs indicating an interrupt.
   These results will be decoded and displayed to the user.

6. Re-arming Interrupts - Clear the status register to allow interrupts to occur again. This is done by writing to the status register.
   In this program, the write command is included in the IDR.

   API CALLS - nai_ether_BeginWriteMessage, nai_ether_WriteMessageData, nai_ether_FinishMessage

7. Clear Module Configurations

   API CALLS - naibrd_DSW_SetRxEnable, naibrd_DSW_ClearStatus

8. Clear Board Configurations

   API CALLS - naibrd_Ether_StopIDR, naibrd_Ether_ClearIDRConfig

</summary>
*/
/**************************************************************************************************************/
static bool_t Run_DSW_Interrupt_Basic_Ethernet()
{
   bool_t bQuit = FALSE;
   bool_t bGen4DSWIDRCommands;

   inputDSWConfig.maxChannel = naibrd_DSW_GetChannelCount(inputDSWConfig.modid);
   inputDSWConfig.minChannel = 1;

   /* check if DSW module supports GEN 4 Ethernet */
   bGen4DSWIDRCommands = SupportsGen4Ether(inputDSWConfig.cardIndex);
    if (!bGen4DSWIDRCommands)
   {
        printf("DSW Ethernet Interrupt Support Prior to Generation 4 Ethernet commands currently not supported\n");
        bQuit = TRUE;
   }
   if (!bQuit)
   {
      bQuit = naiapp_query_ChannelNumber(inputDSWConfig.maxChannel,inputDSWConfig.minChannel,&inputDSWConfig.channel);
   }
   if (!bQuit)
   {
      bQuit = QueryIDRConfigInformation(&inputIDRConfig);

   }
   if (!bQuit)
   {
      bQuit = QueryUserForOnboardOffboardInterrupts(&inputInterruptConfig.bProcessOnboardInterrupts);
   }
   if (!bQuit)
   {
      bQuit = QueryUserForEtherIDRMsgDisplay(&bDisplayEtherUPR);
   }

   if (!bQuit)
   {

      /****2. Setup IDR to Handle Interrupt (also contains step 6) ****/
      if (inputInterruptConfig.bProcessOnboardInterrupts == TRUE)
      {
         inputIDRConfig.cardIndex = inputDSWConfig.cardIndex;
         inputIDRConfig.boardInterface =  NAI_INTF_ONBOARD;
         inputInterruptConfig.steering = NAIBRD_INT_STEERING_ON_BOARD_1;
      }
      else /*OffBoard Interrupt*/
      {
         inputIDRConfig.cardIndex = 0;
         inputIDRConfig.boardInterface = NAI_INTF_PCI;

         inputInterruptConfig.steering =  NAIBRD_INT_STEERING_CPCI_APP;
      }

      setupIDRConfiguration_DSW(inputDSWConfig,&inputIDRConfig,bGen4DSWIDRCommands);
      check_status(naibrd_Ether_StartIDR(inputIDRConfig.cardIndex,(uint16_t)DEF_ETHERNET_DSW_LOHI_IDR_ID));
      check_status(naibrd_Ether_StartIDR(inputIDRConfig.cardIndex,(uint16_t)DEF_ETHERNET_DSW_HILO_IDR_ID));

      /****3. configure module To Interrupt****/
      configureDSWToInterrupt(inputInterruptConfig,inputDSWConfig);
      enableDSWInterrupts(inputDSWConfig,TRUE);

      /****5. Show Interrupt Handling****/
      dswEtherIntFunc = HandleDSWEtherInterrupt;
      bQuit = runIDRServer(inputIDRConfig);

      /*****7. Clear Module Configurations*****/
      enableDSWInterrupts(inputDSWConfig,FALSE);

      /*****8. Clear Board Configurations *****/
      check_status(naibrd_Ether_StopIDR(inputIDRConfig.cardIndex, (uint16_t)DEF_ETHERNET_DSW_LOHI_IDR_ID));
      check_status(naibrd_Ether_ClearIDRConfig(inputIDRConfig.cardIndex, (uint16_t)DEF_ETHERNET_DSW_LOHI_IDR_ID));
   }

   return bQuit;
}

nai_dsw_int_ether.c

Full Source — nai_dsw_int_ether.c (SSK 1.x)
/* 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"

/* Common DSW Sample Program include files */
#include "nai_dsw_int_ether.h"
#include "nai_dsw_cfg.h"

/* naibrd include files */
#include "functions/naibrd_dsw.h"
#include "maps/nai_map_dsw.h"
#include "advanced/nai_ether_adv.h"

int32_t command_index_interrupt_status;

/* Extern Functions or Variables*/
extern DswConfig inputDSWConfig;

/**************************************************************************************************************/
/**
<summary>
Constructs the ethernet commands that are part of the IDR. Configures the IDR on the board.
</summary>
*/
/**************************************************************************************************************/
void setupIDRConfiguration_DSW(DswConfig inputDSWConfig, IDRConfig* inputIDRConfig, bool_t bGen4DSWIDRCommands) {

   int32_t cardIndex = inputIDRConfig->cardIndex;
   uint16_t protocol = inputIDRConfig->protocol;
   uint16_t port = inputIDRConfig->port;
   uint8_t* ipAddress = inputIDRConfig->ipAddress;
   uint8_t ipLength = inputIDRConfig->ipLength;

   int32_t vector1 = NAI_DSW_LOHI_INTERRUPT_VECTOR;
   int32_t vector2 = NAI_DSW_HILO_INTERRUPT_VECTOR;
   uint8_t *commands = inputIDRConfig->commands;				/*Stores the ethernet commands that are going to be executed as part of the IDR*/
   uint16_t *cmdcount = &inputIDRConfig->cmdcount;
   uint16_t *cmdlength = &inputIDRConfig->cmdlength;

   uint32_t addr = NAI_DSW_GEN5_REG_LO_HI_TRANS_LATCHED_STATUS_ADD;

   check_status(naibrd_Ether_ClearIDRConfig(cardIndex, (uint16_t)DEF_ETHERNET_DSW_LOHI_IDR_ID));/* clear IDR config */
   InitDSWIDRCommands(inputDSWConfig, inputIDRConfig, bGen4DSWIDRCommands, addr);
   check_status(naibrd_Ether_SetIDRConfig(cardIndex, (uint16_t)DEF_ETHERNET_DSW_LOHI_IDR_ID, protocol, ipLength, ipAddress, port, vector1, *cmdcount, *cmdlength, commands));
   check_status(naibrd_Ether_ClearIDRConfig(cardIndex, (uint16_t)DEF_ETHERNET_DSW_HILO_IDR_ID));/* clear IDR config */
   check_status(naibrd_Ether_SetIDRConfig(cardIndex, (uint16_t)DEF_ETHERNET_DSW_HILO_IDR_ID, protocol, ipLength, ipAddress, port, vector2, *cmdcount, *cmdlength, commands));

}
/**************************************************************************************************************/
/**
<summary>
This function configures the IDR (Interrupt Driven Response) commands when a DSW Rx interrupt occurs.
There are four Ethernet commands that will be processed by the board when a DSW Rx interrupt occurs.

</summary>
*/
/**************************************************************************************************************/
void InitDSWIDRCommands(DswConfig inputDSWConfig, IDRConfig* inputIDRConfig, bool_t bGen4DSWIDRCommands, uint32_t addr)
{
   nai_status_t status = NAI_SUCCESS;

   uint16_t msgIndex = 0;
   uint32_t boardAddress;
   uint32_t moduleOffset;

   boardAddress = 0;

   status = check_status(naibrd_GetModuleOffset(inputDSWConfig.cardIndex, inputDSWConfig.module, &moduleOffset));
   if (status == NAI_SUCCESS)
      status = check_status(naibrd_GetAddress(inputDSWConfig.cardIndex, &boardAddress));

   if (status == NAI_SUCCESS)
   {
      if (bGen4DSWIDRCommands)
      {
         msgIndex = inputIDRConfig->cmdlength;
         MakeDSWReadRegsCommand(inputIDRConfig, boardAddress, moduleOffset, bGen4DSWIDRCommands, msgIndex, addr);
      }
   }
}
/**************************************************************************************************************/
/**
<summary>
This function constructs an ethernet read reg command and stores it in the IDR Configuration. The read will be performed
on the modules latched status interrupt register. This function will read two registers based on the stride being set to
16 and addr being set to the first register that needs to be read
</summary>
*/
/**************************************************************************************************************/
void MakeDSWReadRegsCommand(IDRConfig* inputIDRConfig, uint32_t boardAddress, int32_t moduleOffset, bool_t bGen4Ether, uint16_t startIndex, uint32_t addr)
{

   uint16_t msgIndex = startIndex;
   uint16_t seqno;
   uint32_t count, stride;

   if (bGen4Ether)
   {
      /* By setting the stride to 16 and base addr sat to Lo-Hi latched status, */
      /* two registers will be read using the command array, the Lo-hi and Hi-Lo latched status registers */
      seqno = 0;
      addr = boardAddress + moduleOffset + addr;
      count = DSW_INTERRUPT_RESPONSE_REG_COUNT;
      stride = 16;

      msgIndex = (uint16_t)nai_ether_MakeReadMessage(&inputIDRConfig->commands[startIndex], seqno, NAI_ETHER_GEN4, (nai_intf_t)inputIDRConfig->boardInterface, addr, stride, count, NAI_REG32);
      inputIDRConfig->cmdlength = inputIDRConfig->cmdlength + msgIndex;
      command_index_interrupt_status = inputIDRConfig->cmdcount;
      inputIDRConfig->cmdcount++;
   }
}
/**************************************************************************************************************/
/**
<summary>
HandleDSWEtherInterrupt is called by the decodeUPRIDRMessages() routine in nai_sys_int_ether.c when an
unprompted (UPR) Ethernet message is received with the TDR/IDR Index equal to DEF_ETHERNET_DT_IDR_ID.
This routine will parse the message to retrieve the information requested in the SetupDTEtherIDRconfig()
routine.
</summary>
*/
/**************************************************************************************************************/
void HandleDSWEtherInterrupt(uint16_t msglen, uint8_t msg[], uint16_t tdr_idr_id)
{
   uint16_t seq;
   nai_ether_typecode_t tc;
   nai_ether_gen_t gen = NAI_ETHER_GEN4;
   int32_t size;
   int32_t offset;
   uint16_t datacnt = 0;
   uint32_t data;
   uint32_t dswstatus_int[DSW_INTERRUPT_RESPONSE_REG_COUNT];
   nai_dsw_status_type_t dsw_status_type = NAI_DSW_STATUS_BIT_LATCHED;
   int32_t i;
   offset = nai_ether_DecodeMessageHeader(msg, msglen, &seq, &tc, gen, &size);

   switch (tc)
   {
      case NAI_ETHER_TYPECODE_RSP_COMMAND_COMPLETE_READ_4:
         datacnt = (msglen - 10) / NAI_REG32;
         for (i = 0; i < datacnt; i++)
         {
            data = 0;
            data = msg[offset++] << 24;
            data |= msg[offset++] << 16;
            data |= msg[offset++] << 8;
            data |= msg[offset++];
            if (i < DSW_INTERRUPT_RESPONSE_REG_COUNT)
               dswstatus_int[i] = data;
         }
         break;
   }
   printf("\n\n");
   printf("IDR ID : %d\n", tdr_idr_id);

  /* Check to make sure we got all 4 status elements (BIT, Lo-Hi, Hi-Lo, Overcurrent) */
   if (datacnt == DSW_INTERRUPT_RESPONSE_REG_COUNT)
   {

      for (i = 0; i < DSW_INTERRUPT_RESPONSE_REG_COUNT; i++)
      {
         switch (i)
         {
            case 0:
               dsw_status_type = NAI_DSW_STATUS_LO_HI_TRANS_LATCHED;
               break;
            case 1:
               dsw_status_type = NAI_DSW_STATUS_HI_LO_TRANS_LATCHED;
               break;
         }
         if (dswstatus_int[i] != 0)
         {
            switch (i)
            {
               case 0:
                  printf("Received DSW Lo-Hi Interrupt: (Interrupt_status) 0x%08X\n", dswstatus_int[i]);
                  break;
               case 1:
                  printf("Received DSW Hi-Lo Interrupt: (Interrupt_status) 0x%08X\n", dswstatus_int[i]);
                  break;
            }

            check_status(naibrd_DSW_ClearGroupStatusRaw(inputDSWConfig.cardIndex, inputDSWConfig.module, 1, dsw_status_type, dswstatus_int[i]));
            switch (i)
            {
               case 0:
                  printf("Cleared DSW Lo-Hi Interrupt: 0x%08X\n", dswstatus_int[i]);
                  break;
               case 1:
                  printf("Cleared DSW Hi-Lo Interrupt: 0x%08X\n", dswstatus_int[i]);
                  break;
            }
         }
      }
   }
}

/**************************************************************************************************************/
/**
<summary>
This function constructs an ethernet write reg command and stores it in the IDR Configuration. The write will be performed
on the modules latched status interrupt register. The purpose of this write is to clear the interrupt status register and re-arm the interrupts
after one has occurred.
</summary>
*/
/**************************************************************************************************************/
void MakeDSWWriteRegsCommand(DswConfig inputDSWConfig, IDRConfig* inputIDRConfig, uint32_t boardAddress, int32_t moduleOffset, bool_t bGen4Ether, uint16_t startIndex)
{

   uint16_t msgIndex = startIndex;
   uint16_t seqno;
   uint32_t count, stride;
   uint32_t regaddr;
   uint32_t data = 0x1 << (inputDSWConfig.channel - 1);   /* Clear Rx interrupt bits */
   uint32_t addr = NAI_DSW_GEN5_REG_BIT_LATCHED_STATUS_ADD;

   if (bGen4Ether)
   {

      seqno = 0;
      regaddr = boardAddress + moduleOffset + addr;
      count = 1;
      stride = 4;

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

         if (msgIndex >= 0)
         {
            msgIndex = (uint16_t)nai_ether_FinishMessage(&inputIDRConfig->commands[startIndex], msgIndex, NAI_ETHER_GEN4);
         }
      }
      inputIDRConfig->cmdlength = inputIDRConfig->cmdlength + msgIndex;
      inputIDRConfig->cmdcount++;
   }
}

Help Bot

X