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

DT Interrupt

DT Interrupts Sample Application (SSK 1.x)

Overview

The DT Interrupts sample application demonstrates how to configure and handle hardware interrupts on discrete (DT) I/O modules using the NAI Software Support Kit (SSK 1.x). The sample covers two interrupt delivery mechanisms: standard (onboard/offboard ISR) and Ethernet IDR (network-based Interrupt Driven Response). Both variants configure and enable the same four interrupt types: fault (BIT), low-to-high transition, high-to-low transition, and overcurrent.

This sample supports the following DT module types: DT1, DT4, DTB, CF1, IF3, D1I, D1P, D4I, and D4P. It also works with combination modules that include DT functionality: CM1, CM2, and CM8.

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

Prerequisites

Before running this sample, make sure you have:

  • An NAI board with a DT module installed (DT1, DT4, DTB, CF1, IF3, D1I, D1P, D4I, D4P, or a combination module such as CM1, CM2, CM8).

  • 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.

  • For the Ethernet IDR variant: a Gen4 or later board with an Ethernet connection.

How to Run

This sample ships as two executables that share common configuration code:

  • DT_Interrupt — standard interrupt delivery (onboard or offboard ISR).

  • DT_Ethernet_IDR — Ethernet-based interrupt delivery using IDR commands.

Launch either executable from your build output directory. On startup the application looks for a configuration file (default_DT_Interrupt.txt for the standard variant, default_DT_Ethernet_Int.txt for the Ethernet variant). 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 interrupt settings and begins waiting for interrupt events.

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 DT.

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_DT_Interrupt.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_access_SystemSNModCfg() to acquire the system serial number and module configuration.

  3. Call PromptUserInput_DTInterrupt() to query the user for card index, module slot, channel, and trigger mode.

  4. Retrieve interrupt clearing and steering preferences before configuring the module.

#if defined (__VXWORKS__)
void DT_Interrupt(void)
#else
int32_t main(void)
#endif
{
   bool_t bQuit = FALSE;
   bool_t bSuccess = FALSE;

   DisplayMessage_DTInterrupt(MSG_BANNER_DT_INT);
   if (naiapp_RunBoardMenu(CONFIG_FILE) == TRUE)
   {
      while (!bQuit)
      {
         naiapp_access_SystemSNModCfg();
         bQuit = PromptUserInput_DTInterrupt(&bSuccess);
         if ((!bQuit) & bSuccess)
         {
            bQuit = DT_QueryUserForClearingInterruptPrompts();
            if (!bQuit)
            {
               bQuit = QueryUserForOnboardOffbordInterrupts();
               if (!bQuit)
               {
                  if ( bProcessOnboardInterrupts == TRUE )
                  {
                     printf("\nOnboard Interrupts selected.\n");
                     ConfigDTInterrupt(ONBOARD_INT);
                     InitInterruptAppThread(ONBOARD_INT, 0);
                     /* Set the dtIntProcessFunc global function pointer to point to the routine that will handle
                        Interrupt messages associated with the Discrete Interrupt Vector (DEF_ETHERNET_DT_IDR_ID).
                     */
                     dtIntProcessFunc = HandleDTInterrupt;

                     if ( naibrd_InstallISR(userInput_DTInt.cardIndex, NAIBRD_IRQ_ID_ON_BOARD_0, (nai_isr_t)IntOnboardIsr, (void*)&userInput_DTInt.cardIndex) == NAI_SUCCESS)
                     {
                        DisplayMessage_DTInterrupt(MSG_USER_TRIGGER_DT_INT);
                        EnableDTInterrupt(TRUE);
                        /* Add a small delay to make sure the Interrupt State Machine Task has completed initialization */
                        nai_msDelay(10);
                        UpdateThreadState(RUN);
                     }
                     else
                     {
                        printf("\n***** Error - naibrd_InstallISR (Onboard) FAILED - Interrupts will not work. *****\n");
                        bQuit = TRUE;
                     }
                  }
                  else
                  {
                     printf("\nOffboard Interrupts selected.\n");
                     if( isPCIE == TRUE )
                     {
                        ConfigDTInterrupt(MASTER_PCIE_BUS_OFFBOARD_INT);
                        InitInterruptAppThread(MASTER_PCIE_BUS_OFFBOARD_INT, 0);
                     }
                     else
                     {
                        ConfigDTInterrupt(MASTER_PCIBUS_OFFBOARD_INT);
                        InitInterruptAppThread(MASTER_PCIBUS_OFFBOARD_INT, 0);
                     }

                     /* Set the dtIntProcessFunc global function pointer to point to the routine that will handle
                        Interrupt messages associated with the Discrete Interrupt Vector (DEF_ETHERNET_DT_IDR_ID).
                     */
                     dtIntProcessFunc = HandleDTInterrupt;

                     if ( naibrd_InstallISR(userInput_DTInt.cardIndex, NAIBRD_IRQ_ID_DONT_CARE, (nai_isr_t)IntOffboardIsr, (void*)&userInput_DTInt.cardIndex) == NAI_SUCCESS)
                     {
                        DisplayMessage_DTInterrupt(MSG_USER_TRIGGER_DT_INT);
                        EnableDTInterrupt(TRUE);
                        /* Add a small delay to make sure the Interrupt State Machine Task has completed initialization */
                        nai_msDelay(10);
                        UpdateThreadState(RUN);
                     }
                     else
                     {
                        printf("\n***** Error - naibrd_InstallISR (Offboard) FAILED - Interrupts will not work. *****\n");
                        bQuit = TRUE;
                     }
                  }
               }
               else
               {
                  UpdateThreadState(TERMINATED);
               }
            }
            else
            {
               UpdateThreadState(TERMINATED);
            }
            bQuit = TRUE;
        }
    }
}
   ExitApp_DTInterrupt();
#if !defined (__VXWORKS__)
   return(0);
#endif
}
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 DT module. Use the board menu to verify which slots are populated.

Program Structure

The DT Interrupts sample is split across three source files. Two variant-specific files provide the main() entry point and interrupt delivery logic, while a shared common file handles module configuration and interrupt enable/disable:

  • DT_Interrupt.c — standard interrupt variant. Uses onboard or offboard ISR delivery via naibrd_InstallISR().

  • DT_Ethernet_IDR.c — Ethernet IDR variant. Delivers interrupt notifications over the network using IDR commands.

  • DT_Interrupt_Common.c — shared configuration and enable logic used by both variants.

Each variant has its own entry point:

  • Standard: main() (or DT_Interrupt() on VxWorks).

  • Ethernet IDR: main() (or DT_Ethernet_IDR() on VxWorks).

After the board connection is established, both variants follow the same user selection flow:

  1. Select a card index, module slot, channel, and interrupt trigger mode (edge or level).

  2. Choose whether to be prompted before clearing each interrupt, or clear automatically.

  3. For the standard variant: choose onboard, offboard PCI, or offboard PCIe interrupt steering. For the Ethernet IDR variant: configure the Ethernet IDR connection parameters.

  4. Call the shared ConfigDTInterrupt() and EnableDTInterrupt() functions to set up the module registers.

The difference between the two variants is only in how the interrupt notification reaches your application — the underlying module configuration is identical.

Shared Data Structures

Both variants use two structures defined in DT_Interrupt_Common.h to track user selections and board state:

typedef struct _UserInput_DTInt
{
   int32_t cardIndex;
   int32_t moduleNumber;
   int32_t channel;
   int32_t intTriggerType;
} UserInput_DTInt, *PUserInput_DTInt;

typedef struct _BoardState
{
   int32_t cardIndex;
   int32_t moduleNumber;
   int32_t channel;
   int32_t maxChannels;
   uint32_t interruptState;
   uint32_t revIntVector;
   uint32_t revIntCount;
} BoardState_DTInt, *PBoardState_DTInt;

UserInput_DTInt captures the values collected during the interactive prompts: the card and module to target, the specific channel, and whether to use edge or level triggering (intTriggerType is set to INT_TRIGGER_MODE_EDGE or INT_TRIGGER_MODE_LEVEL).

BoardState_DTInt tracks runtime state as interrupts arrive. It records the current interruptState, the last received interrupt vector (revIntVector), and a running count of interrupts received (revIntCount). The maxChannels field is populated during configuration so the interrupt handler knows the valid channel range for the installed module.

Both structures are declared as global externs so that the variant-specific entry point and the common configuration code can share them.

Interrupt Status Types

The DT module exposes four distinct interrupt status types. Each type monitors a different hardware condition and latches when that condition is detected. Understanding what each type reports will help you decide which ones to enable in your application.

BIT (Built-In Test) / Fault

NAI_DT_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 discrete channel, checking for conditions such as open inputs, stuck outputs, or internal reference failures. When BIT detects a problem, it latches the corresponding status bit and, if enabled, raises an interrupt.

Enable BIT interrupts for health monitoring, safety-critical applications, or continuous hardware validation. In systems where a failed channel must be flagged immediately — rather than discovered during a periodic status poll — BIT interrupts provide the fastest notification path.

Low-to-High Transition

NAI_DT_STATUS_LO_HI_TRANS_LATCHED

A discrete 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: switch closures, signal activation, event counting, or detecting when an external condition becomes active. This is the most common trigger type for applications that need to respond the moment an input asserts.

High-to-Low Transition

NAI_DT_STATUS_HI_LO_TRANS_LATCHED

A discrete input transitioned from high to low. Like its low-to-high counterpart, the module captures the falling edge and latches it for reliable software consumption.

Enable high-to-low transition interrupts for falling-edge detection: switch openings, 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, which is useful for measuring pulse widths or tracking state changes.

Overcurrent

NAI_DT_STATUS_OVERCURRENT_LATCHED

An output channel detected an overcurrent condition. The module’s current-sensing circuitry monitors each output and latches this status when the channel is sourcing or sinking more current than its rated limit. An overcurrent event typically indicates a wiring fault, a short circuit, or an unexpectedly heavy load.

Enable overcurrent interrupts for output protection, fault detection, and load monitoring. In applications that drive external relays, solenoids, or indicator lamps, an overcurrent interrupt lets you react immediately — disabling the output, alerting the operator, or switching to a backup channel — before damage occurs.

The sample enables all four 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

This configuration applies to both the standard and Ethernet IDR interrupt mechanisms. Both variants call the same configuration functions to set up the module before enabling interrupts.

The ConfigDTInterrupt() function in DT_Interrupt_Common.c performs five steps in sequence: disable interrupts, clear status registers, set the interrupt vector, configure the trigger mode, and set interrupt steering. Each step is explained below with the corresponding code.

Step 1: Disable Interrupts Before Reconfiguring

Always disable interrupts before changing configuration to avoid spurious interrupts during setup. The function begins by calling EnableDTInterrupt(FALSE), which iterates over every channel and disables all four interrupt status types.

/* Disable Interrupts */
EnableDTInterrupt(FALSE);

Step 2: Clear All Status Registers

Stale latched status from a previous run will trigger an immediate interrupt if not cleared. The pattern is: read the current status, then write back the value to clear it. The sample repeats this read-and-clear sequence for all four status types — BIT, low-to-high transition, high-to-low transition, and overcurrent.

/* Clear the Interrupt Status (Read the status and write back "1" to statuses which are set to clear the status) */
check_status(naibrd_DT_GetGroupStatusRaw(userInput_DTInt.cardIndex, userInput_DTInt.moduleNumber, 1, NAI_DT_STATUS_BIT_LATCHED, &rawstatus));
check_status(naibrd_DT_ClearGroupStatusRaw(userInput_DTInt.cardIndex, userInput_DTInt.moduleNumber, 1, NAI_DT_STATUS_BIT_LATCHED, rawstatus));
check_status(naibrd_DT_GetGroupStatusRaw(userInput_DTInt.cardIndex, userInput_DTInt.moduleNumber, 1, NAI_DT_STATUS_LO_HI_TRANS_LATCHED, &rawstatus));
check_status(naibrd_DT_ClearGroupStatusRaw(userInput_DTInt.cardIndex, userInput_DTInt.moduleNumber, 1, NAI_DT_STATUS_LO_HI_TRANS_LATCHED, rawstatus));
check_status(naibrd_DT_GetGroupStatusRaw(userInput_DTInt.cardIndex, userInput_DTInt.moduleNumber, 1, NAI_DT_STATUS_HI_LO_TRANS_LATCHED, &rawstatus));
check_status(naibrd_DT_ClearGroupStatusRaw(userInput_DTInt.cardIndex, userInput_DTInt.moduleNumber, 1, NAI_DT_STATUS_HI_LO_TRANS_LATCHED, rawstatus));
check_status(naibrd_DT_GetGroupStatusRaw(userInput_DTInt.cardIndex, userInput_DTInt.moduleNumber, 1, NAI_DT_STATUS_OVERCURRENT_LATCHED, &rawstatus));
check_status(naibrd_DT_ClearGroupStatusRaw(userInput_DTInt.cardIndex, userInput_DTInt.moduleNumber, 1, NAI_DT_STATUS_OVERCURRENT_LATCHED, rawstatus));

Step 3: Set Interrupt Vector

The vector identifies which interrupt source generated the event. The sample assigns the same vector (NAI_DT_INTERRUPT_VECTOR) to all four status types so that a single ISR can service every DT interrupt on the module. If you need to distinguish sources inside the ISR without reading status registers, you can assign a different vector to each type.

/* Setup the Interrupt Vector - map to the same vector */
check_status(naibrd_DT_SetGroupInterruptVector(userInput_DTInt.cardIndex, userInput_DTInt.moduleNumber, 1, NAI_DT_STATUS_BIT_LATCHED, NAI_DT_INTERRUPT_VECTOR));
check_status(naibrd_DT_SetGroupInterruptVector(userInput_DTInt.cardIndex, userInput_DTInt.moduleNumber, 1, NAI_DT_STATUS_LO_HI_TRANS_LATCHED, NAI_DT_INTERRUPT_VECTOR));
check_status(naibrd_DT_SetGroupInterruptVector(userInput_DTInt.cardIndex, userInput_DTInt.moduleNumber, 1, NAI_DT_STATUS_HI_LO_TRANS_LATCHED, NAI_DT_INTERRUPT_VECTOR));
check_status(naibrd_DT_SetGroupInterruptVector(userInput_DTInt.cardIndex, userInput_DTInt.moduleNumber, 1, NAI_DT_STATUS_OVERCURRENT_LATCHED, NAI_DT_INTERRUPT_VECTOR));

Step 4: Set Trigger Mode

The trigger mode is set per-channel across all four status types. The user’s selection (intTriggerType) is cast to a uint8_t and passed to naibrd_DT_SetEdgeLevelInterrupt(). A value of 0 selects edge-triggered mode, where the interrupt fires once when the condition is first detected. A value of 1 selects level-triggered mode, where the interrupt continues to assert as long as the condition remains active. For detailed theory on edge vs. level triggering and when to use each mode, see the Interrupts API Guide.

/* Setup the Latched Status Mode */
interrupt_t = (uint8_t)userInput_DTInt.intTriggerType;
for (chan = 1; chan <= boardState_DTInt.maxChannels; chan++)
{
   check_status(naibrd_DT_SetEdgeLevelInterrupt(userInput_DTInt.cardIndex, userInput_DTInt.moduleNumber, chan, NAI_DT_STATUS_BIT_LATCHED, interrupt_t));
   check_status(naibrd_DT_SetEdgeLevelInterrupt(userInput_DTInt.cardIndex, userInput_DTInt.moduleNumber, chan, NAI_DT_STATUS_LO_HI_TRANS_LATCHED, interrupt_t));
   check_status(naibrd_DT_SetEdgeLevelInterrupt(userInput_DTInt.cardIndex, userInput_DTInt.moduleNumber, chan, NAI_DT_STATUS_HI_LO_TRANS_LATCHED, interrupt_t));
   check_status(naibrd_DT_SetEdgeLevelInterrupt(userInput_DTInt.cardIndex, userInput_DTInt.moduleNumber, chan, NAI_DT_STATUS_OVERCURRENT_LATCHED, interrupt_t));
}

Step 5: Set Interrupt Steering

Interrupt steering determines how the interrupt signal is delivered from the module to your application. The sample selects the steering mode based on the interruptCommType passed into ConfigDTInterrupt(). Each steering option sets all four status types to the same routing.

/* Setup the Interrupt Steering */
switch (interruptCommType)
{
case ETHERNET_INT:
   check_status(naibrd_DT_SetGroupInterruptSteering(userInput_DTInt.cardIndex, userInput_DTInt.moduleNumber, 1, NAI_DT_STATUS_BIT_LATCHED, NAIBRD_INT_STEERING_ON_BOARD_1));
   check_status(naibrd_DT_SetGroupInterruptSteering(userInput_DTInt.cardIndex, userInput_DTInt.moduleNumber, 1, NAI_DT_STATUS_LO_HI_TRANS_LATCHED, NAIBRD_INT_STEERING_ON_BOARD_1));
   check_status(naibrd_DT_SetGroupInterruptSteering(userInput_DTInt.cardIndex, userInput_DTInt.moduleNumber, 1, NAI_DT_STATUS_HI_LO_TRANS_LATCHED, NAIBRD_INT_STEERING_ON_BOARD_1));
   check_status(naibrd_DT_SetGroupInterruptSteering(userInput_DTInt.cardIndex, userInput_DTInt.moduleNumber, 1, NAI_DT_STATUS_OVERCURRENT_LATCHED, NAIBRD_INT_STEERING_ON_BOARD_1));
   break;

   case MASTER_PCIBUS_OFFBOARD_INT:
   check_status(naibrd_DT_SetGroupInterruptSteering(userInput_DTInt.cardIndex, userInput_DTInt.moduleNumber, 1, NAI_DT_STATUS_BIT_LATCHED, NAIBRD_INT_STEERING_CPCI_APP));
   check_status(naibrd_DT_SetGroupInterruptSteering(userInput_DTInt.cardIndex, userInput_DTInt.moduleNumber, 1, NAI_DT_STATUS_LO_HI_TRANS_LATCHED, NAIBRD_INT_STEERING_CPCI_APP));
   check_status(naibrd_DT_SetGroupInterruptSteering(userInput_DTInt.cardIndex, userInput_DTInt.moduleNumber, 1, NAI_DT_STATUS_HI_LO_TRANS_LATCHED, NAIBRD_INT_STEERING_CPCI_APP));
   check_status(naibrd_DT_SetGroupInterruptSteering(userInput_DTInt.cardIndex, userInput_DTInt.moduleNumber, 1, NAI_DT_STATUS_OVERCURRENT_LATCHED, NAIBRD_INT_STEERING_CPCI_APP));
   break;

   case MASTER_PCIE_BUS_OFFBOARD_INT:
   check_status(naibrd_DT_SetGroupInterruptSteering(userInput_DTInt.cardIndex, userInput_DTInt.moduleNumber, 1, NAI_DT_STATUS_BIT_LATCHED, NAIBRD_INT_STEERING_PCIE_APP));
   check_status(naibrd_DT_SetGroupInterruptSteering(userInput_DTInt.cardIndex, userInput_DTInt.moduleNumber, 1, NAI_DT_STATUS_LO_HI_TRANS_LATCHED, NAIBRD_INT_STEERING_PCIE_APP));
   check_status(naibrd_DT_SetGroupInterruptSteering(userInput_DTInt.cardIndex, userInput_DTInt.moduleNumber, 1, NAI_DT_STATUS_HI_LO_TRANS_LATCHED, NAIBRD_INT_STEERING_PCIE_APP));
   check_status(naibrd_DT_SetGroupInterruptSteering(userInput_DTInt.cardIndex, userInput_DTInt.moduleNumber, 1, NAI_DT_STATUS_OVERCURRENT_LATCHED, NAIBRD_INT_STEERING_PCIE_APP));
   break;

   case ONBOARD_INT:
#if defined (PPC_XILINX)
   check_status(naibrd_DT_SetGroupInterruptSteering(userInput_DTInt.cardIndex, userInput_DTInt.moduleNumber, 1, NAI_DT_STATUS_BIT_LATCHED, NAIBRD_INT_STEERING_PCIE_APP));
   check_status(naibrd_DT_SetGroupInterruptSteering(userInput_DTInt.cardIndex, userInput_DTInt.moduleNumber, 1, NAI_DT_STATUS_LO_HI_TRANS_LATCHED, NAIBRD_INT_STEERING_PCIE_APP));
   check_status(naibrd_DT_SetGroupInterruptSteering(userInput_DTInt.cardIndex, userInput_DTInt.moduleNumber, 1, NAI_DT_STATUS_HI_LO_TRANS_LATCHED, NAIBRD_INT_STEERING_PCIE_APP));
   check_status(naibrd_DT_SetGroupInterruptSteering(userInput_DTInt.cardIndex, userInput_DTInt.moduleNumber, 1, NAI_DT_STATUS_OVERCURRENT_LATCHED, NAIBRD_INT_STEERING_PCIE_APP));
#else
   check_status(naibrd_DT_SetGroupInterruptSteering(userInput_DTInt.cardIndex, userInput_DTInt.moduleNumber, 1, NAI_DT_STATUS_BIT_LATCHED, NAIBRD_INT_STEERING_ON_BOARD_0));
   check_status(naibrd_DT_SetGroupInterruptSteering(userInput_DTInt.cardIndex, userInput_DTInt.moduleNumber, 1, NAI_DT_STATUS_LO_HI_TRANS_LATCHED, NAIBRD_INT_STEERING_ON_BOARD_0));
   check_status(naibrd_DT_SetGroupInterruptSteering(userInput_DTInt.cardIndex, userInput_DTInt.moduleNumber, 1, NAI_DT_STATUS_HI_LO_TRANS_LATCHED, NAIBRD_INT_STEERING_ON_BOARD_0));
   check_status(naibrd_DT_SetGroupInterruptSteering(userInput_DTInt.cardIndex, userInput_DTInt.moduleNumber, 1, NAI_DT_STATUS_OVERCURRENT_LATCHED, NAIBRD_INT_STEERING_ON_BOARD_0));
#endif
   break;
}

The steering options are:

  • Ethernet (NAIBRD_INT_STEERING_ON_BOARD_1) — triggers an Ethernet IDR response. The board’s onboard processor intercepts the interrupt and sends a notification over Ethernet to the host application. Use this mode with the DT_Ethernet_IDR variant.

  • cPCI offboard (NAIBRD_INT_STEERING_CPCI_APP) — routes the interrupt to the CompactPCI backplane host. The host’s bus driver receives the interrupt and dispatches it to the installed ISR.

  • PCIe offboard (NAIBRD_INT_STEERING_PCIE_APP) — routes the interrupt to the PCIe host. This is the standard choice for desktop or rack-mount systems with a PCIe backplane connection.

  • Onboard (NAIBRD_INT_STEERING_ON_BOARD_0) — handled locally on the board’s processor. This applies to any onboard application, whether running on an x86 or ARM (PetaLinux) platform. The ISR runs directly on the board without traversing a bus. (Exception: PPC_XILINX platforms use PCIE_APP instead — see below.)

  • Onboard on PPC_XILINX — PowerPC processor boards (e.g., 68PPC2) route interrupts through PCIe (NAIBRD_INT_STEERING_PCIE_APP) even for onboard handling. The #ifdef PPC_XILINX conditional in the source automatically selects PCIE_APP steering instead of ON_BOARD_0 when compiled for this platform. This does not apply to ARM (PetaLinux) boards, which use ON_BOARD_0.

For a full description of each steering mode and the hardware paths involved, refer to your module manual and the Interrupts API Guide.

Important

Common interrupt configuration errors:

  • ISR installation failure — naibrd_InstallISR() returns an error when the steering mode does not match your hardware configuration or bus type. For example, selecting CPCI_APP steering on a PCIe-only system will fail because no CompactPCI interrupt path exists. Verify that your steering selection matches the physical bus connection.

  • Interrupts not firing after enable — this is the most common cause of silent failures. If latched status registers are not cleared before enabling interrupts, stale status bits from a previous run will not generate a new edge and the interrupt controller will never fire. Always perform the read-and-clear sequence in Step 2 before calling EnableDTInterrupt(TRUE).

  • Wrong steering mode — selecting onboard steering (ON_BOARD_0) when the ISR is installed as offboard (or vice versa) results in interrupts being routed to a path with no handler. Double-check that interruptCommType passed to ConfigDTInterrupt() matches the NAIBRD_IRQ_ID used in naibrd_InstallISR().

  • PPC_XILINX platform mismatch — PowerPC boards must use NAIBRD_INT_STEERING_PCIE_APP for onboard interrupts, not NAIBRD_INT_STEERING_ON_BOARD_0. If you are compiling for a PowerPC target and interrupts do not fire, confirm that PPC_XILINX is defined in your build so the correct steering path is selected.

Standard Interrupt Handling

This section walks through the standard (non-Ethernet) interrupt path: installing an ISR, starting the interrupt processing thread, handling interrupts as they arrive, and enabling interrupt generation on the module. All code is from DT_Interrupt.c unless noted otherwise.

ISR Installation

The SSK provides two ISR installation patterns depending on whether the interrupt is handled onboard (on the board’s own processor) or offboard (on the host through a PCI/PCIe bus).

Onboard:

naibrd_InstallISR(userInput_DTInt.cardIndex, NAIBRD_IRQ_ID_ON_BOARD_0,
                  (nai_isr_t)IntOnboardIsr, (void*)&userInput_DTInt.cardIndex)

Offboard:

naibrd_InstallISR(userInput_DTInt.cardIndex, NAIBRD_IRQ_ID_DONT_CARE,
                  (nai_isr_t)IntOffboardIsr, (void*)&userInput_DTInt.cardIndex)

The two calls differ in two arguments: the IRQ ID and the ISR function pointer. NAIBRD_IRQ_ID_ON_BOARD_0 targets the first onboard interrupt vector — this tells the library to register the ISR with the board’s local interrupt controller. NAIBRD_IRQ_ID_DONT_CARE is used for offboard delivery, where the bus (PCI or PCIe) manages the IRQ assignment and the host OS dispatches the interrupt to your handler. Make sure the IRQ ID you pass here matches the steering mode you configured in ConfigDTInterrupt() — a mismatch will silently prevent interrupts from reaching your ISR.

Thread Setup

Before installing the ISR, the application initializes the interrupt processing thread and wires up the handler callback. The full onboard sequence is:

ConfigDTInterrupt(ONBOARD_INT);
InitInterruptAppThread(ONBOARD_INT, 0);
/* Set the dtIntProcessFunc global function pointer to point to the routine that will handle
   Interrupt messages associated with the Discrete Interrupt Vector (DEF_ETHERNET_DT_IDR_ID).
*/
dtIntProcessFunc = HandleDTInterrupt;

if ( naibrd_InstallISR(userInput_DTInt.cardIndex, NAIBRD_IRQ_ID_ON_BOARD_0, (nai_isr_t)IntOnboardIsr, (void*)&userInput_DTInt.cardIndex) == NAI_SUCCESS)
{
   DisplayMessage_DTInterrupt(MSG_USER_TRIGGER_DT_INT);
   EnableDTInterrupt(TRUE);
   /* Add a small delay to make sure the Interrupt State Machine Task has completed initialization */
   nai_msDelay(10);
   UpdateThreadState(RUN);
}

InitInterruptAppThread() creates the background thread that runs the interrupt state machine. The dtIntProcessFunc function pointer is set to HandleDTInterrupt so the thread knows which callback to invoke when an interrupt message arrives. After the ISR is successfully installed, EnableDTInterrupt(TRUE) turns on interrupt generation at the module level, a 10 ms delay ensures the thread’s state machine has completed its initialization cycle, and UpdateThreadState(RUN) transitions the thread from its idle startup state into active processing. Skipping the delay can cause the first interrupt to arrive before the thread is ready, resulting in a missed event.

Interrupt Handler

HandleDTInterrupt() is called by the interrupt thread each time the ISR posts a message. The handler iterates over all four status types, reads the raw group status for each, reports which ones fired, optionally waits for user confirmation, then clears the status to re-arm the interrupt.

void HandleDTInterrupt(uint32_t nVector)
{
   int32_t i;
   uint32_t dtstatus_int[DT_INTERRUPT_RESPONSE_REG_COUNT];
   nai_dt_status_type_t dt_status_type = NAI_DT_STATUS_BIT_LATCHED;

   /* Check all 4 status elements (BIT, Lo-Hi, Hi-Lo, Overcurrent) */
   printf("\n\n");
   for (i = 0; i < DT_INTERRUPT_RESPONSE_REG_COUNT; i++)
   {
      switch (i)
      {
      case 0:
         dt_status_type = NAI_DT_STATUS_BIT_LATCHED;
         break;
      case 1:
         dt_status_type = NAI_DT_STATUS_LO_HI_TRANS_LATCHED;
         break;
      case 2:
         dt_status_type = NAI_DT_STATUS_HI_LO_TRANS_LATCHED;
         break;
      case 3:
         dt_status_type = NAI_DT_STATUS_OVERCURRENT_LATCHED;
         break;
      }

      check_status(naibrd_DT_GetGroupStatusRaw(userInput_DTInt.cardIndex, userInput_DTInt.moduleNumber, 1, dt_status_type, &dtstatus_int[i]));

      if (dtstatus_int[i] != 0)
      {
         switch (i)
         {
         case 0:
            printf("Received DT Bit Interrupt: (Interrupt_status) 0x%08X\n", dtstatus_int[i]);
         break;
         case 1:
            printf("Received DT Lo-Hi Interrupt: (Interrupt_status) 0x%08X\n", dtstatus_int[i]);
         break;
         case 2:
            printf("Received DT Hi-Lo Interrupt: (Interrupt_status) 0x%08X\n", dtstatus_int[i]);
         break;
         case 3:
            printf("Received DT Overcurrent Interrupt: (Interrupt_status) 0x%08X\n", dtstatus_int[i]);
         break;
         }
         if (bPromptForInterruptClear)
         {
            /* Prompt the user t to clear the interrupt received */
            SetUserRequestClearInt(FALSE);
            DisplayMessage_DTInterrupt(MSG_USER_CLEAR_DT_INT);
            /* Wait for the user to respond */
            while (!GetUserRequestClearInt())
            {
               nai_msDelay(10);
            }
         }
         /* Clear the status state to re-arm the interrupts */
         check_status(naibrd_DT_ClearGroupStatusRaw(userInput_DTInt.cardIndex, userInput_DTInt.moduleNumber, 1, dt_status_type, dtstatus_int[i]));
      }
   }
}

The handler calls naibrd_DT_GetGroupStatusRaw() for each status type to read which channels triggered. A non-zero return means at least one channel in the group has a latched status. After reporting, it calls naibrd_DT_ClearGroupStatusRaw() with the same value to clear exactly the bits that were set, which re-arms the interrupt for the next event. If you omit the clear step, edge-triggered interrupts will never fire again because the latched status remains set and no new edge is generated.

Auto-Clear vs. Prompt-Clear

The sample provides two interrupt clearing modes controlled by the bPromptForInterruptClear flag:

if (bPromptForInterruptClear)
{
   /* Prompt the user t to clear the interrupt received */
   SetUserRequestClearInt(FALSE);
   DisplayMessage_DTInterrupt(MSG_USER_CLEAR_DT_INT);
   /* Wait for the user to respond */
   while (!GetUserRequestClearInt())
   {
      nai_msDelay(10);
   }
}
/* Clear the status state to re-arm the interrupts */
check_status(naibrd_DT_ClearGroupStatusRaw(userInput_DTInt.cardIndex, userInput_DTInt.moduleNumber, 1, dt_status_type, dtstatus_int[i]));

The user is asked at startup whether to enable prompt-clear mode:

static bool_t DT_QueryUserForClearingInterruptPrompts(void)
{
   bool_t bQuit = FALSE;
   int8_t inputBuffer[80];
   int32_t inputResponseCnt;

   /* Query the user to determine if he wants to be prompted before clearing the interrupt */
   printf("\nWould you like to be prompted to clear interrupts? (Y or N) (Default: Y): ");
   bQuit = naiapp_query_ForQuitResponse(sizeof(inputBuffer), NAI_QUIT_CHAR, inputBuffer, &inputResponseCnt);
   if (!bQuit)
   {
      if (inputResponseCnt != 0)
      {
         if ((inputBuffer[0] == 'N') || (inputBuffer[0] == 'n'))
         {
            bPromptForInterruptClear = FALSE;
         }
         else
         {
            bPromptForInterruptClear = TRUE;
         }
      }
      else
      {
         bPromptForInterruptClear = TRUE;
      }
   }
   return bQuit;
}

When prompt-clear is active (Y, the default), the handler pauses after each status report and prints Press "C" to clear interrupts…​. It polls GetUserRequestClearInt() in a 10 ms loop until the user thread signals that the user pressed 'C'. This mode is useful for learning and debugging because it lets you observe the latched status before it is cleared.

When auto-clear is active (N), the if (bPromptForInterruptClear) block is skipped entirely and the handler proceeds directly to naibrd_DT_ClearGroupStatusRaw(). This is the recommended mode for production use — it minimizes interrupt latency and avoids the risk of missed interrupts while waiting for user input.

Enable Interrupts

The EnableDTInterrupt() function in DT_Interrupt_Common.c enables or disables interrupt generation for every channel across all four status types:

void EnableDTInterrupt(bool_t enabled)
{
   int32_t chan;
   for (chan = 1; chan <= boardState_DTInt.maxChannels; chan++)
   {
      check_status(naibrd_DT_SetInterruptEnable(userInput_DTInt.cardIndex, userInput_DTInt.moduleNumber, chan, NAI_DT_STATUS_BIT_LATCHED, enabled));
      check_status(naibrd_DT_SetInterruptEnable(userInput_DTInt.cardIndex, userInput_DTInt.moduleNumber, chan, NAI_DT_STATUS_OVERCURRENT_LATCHED, enabled));
      check_status(naibrd_DT_SetInterruptEnable(userInput_DTInt.cardIndex, userInput_DTInt.moduleNumber, chan, NAI_DT_STATUS_LO_HI_TRANS_LATCHED, enabled));
      check_status(naibrd_DT_SetInterruptEnable(userInput_DTInt.cardIndex, userInput_DTInt.moduleNumber, chan, NAI_DT_STATUS_HI_LO_TRANS_LATCHED, enabled));
   }
}

The function loops from channel 1 through maxChannels (determined during module detection) and calls naibrd_DT_SetInterruptEnable() once per status type per channel. Pass TRUE to enable or FALSE to disable. In your own application, you can selectively enable only the status types and channels you need rather than enabling everything.

Important

Common interrupt handling errors:

  • Handler never called — the interrupt processing thread was not started (InitInterruptAppThread() was not called or failed), the ISR was installed with the wrong IRQ ID for the steering mode, or the steering configuration does not match the physical interrupt path. Verify all three: thread running, IRQ ID correct, steering matches bus type.

  • Interrupts stop after first event (edge-triggered) — the handler did not clear the latched status register. With edge triggering, the interrupt fires on the transition into the latched state. If the status is never cleared, no new edge occurs and the interrupt controller will not fire again. Always call naibrd_DT_ClearGroupStatusRaw() in your handler.

  • Interrupts fire continuously (level-triggered) — this is expected behavior. In level-triggered mode, the interrupt re-asserts as long as the condition remains active. If you do not want continuous interrupts, switch to edge-triggered mode or resolve the underlying hardware condition (such as an ongoing overcurrent fault).

Ethernet IDR Interrupt Handling

The Ethernet IDR (Interrupt Driven Response) variant delivers interrupt notifications over the network instead of through a hardware ISR. Use this approach when your application runs on a remote host connected via Ethernet, when a hardware ISR is not available or practical for your deployment, or when you want all four latched status values delivered in a single UDP message rather than reading each register separately.

Prerequisites

Ethernet IDR requires a Generation 4 or later board with Ethernet support. The application verifies this at startup before proceeding with IDR configuration:

bSuccess = CheckNaiEtherProtocolVersion(userInput_DTInt.cardIndex);
if (bSuccess)
   ConfigETHERInterrupt(steering);
else
   printf("ERROR: Ethernet Interrupt Support Prior to Generation 4 Ethernet commands are currently NOT supported.\n");

If the check fails, the board’s firmware does not support the Gen4 Ethernet protocol and IDR commands will not work. You may need to update the board firmware.

IDR Configuration

The SetupDTEtherIDRconfig() function builds and registers the IDR command that the board will execute each time an interrupt fires. The board then sends the result back to your application as a UDP message.

bool_t SetupDTEtherIDRconfig(uint16_t protocol, int32_t IDRcardIndex, int32_t boardInterface)
{
   bool_t bSuccess = FALSE;
   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;
   uint8_t commands[MAX_ETHER_IDR_CMD_CNT*MAX_ETHER_BLOCK_REG_CNT];
   int32_t vector = NAI_DT_INTERRUPT_VECTOR;
   uint32_t stride = 0x10;  /* Register offset between the latched status register for each type of status */
   uint16_t cmdcount = 0;
   uint16_t cmdlength = 0;

   /* Clear the Ethernet Interrupt Driven Response Configuration associated with the ID: DEF_ETHERNET_DT_IDR_ID */
   status = naibrd_Ether_ClearIDRConfig(IDRcardIndex,(uint16_t)DEF_ETHERNET_DT_IDR_ID);
   if (status == NAI_SUCCESS)
   {
      status = check_status(naibrd_GetModuleOffset(userInput_DTInt.cardIndex, userInput_DTInt.moduleNumber, &moduleOffset));
      if (status == NAI_SUCCESS)
      {
         /* Perform ReadRegs command starting with NAI_DT_GEN5_REG_BIT_LATCHED_STATUS_ADD */
         /* This reads:
            - NAI_DT_GEN5_REG_BIT_LATCHED_STATUS_ADD,
            - NAI_DT_GEN5_REG_LO_HI_TRANS_LATCHED_STATUS_ADD,
            - NAI_DT_GEN5_REG_HI_LO_TRANS_LATCHED_STATUS_ADD
            - NAI_DT_GEN5_REG_OVERCURRENT_LATCHED_STATUS_ADD
         */
         MakeIDRDTboardReadRegsCommand(msgIndex, moduleOffset, NAI_DT_GEN5_REG_BIT_LATCHED_STATUS_ADD, DT_INTERRUPT_RESPONSE_REG_COUNT, stride, commands, &ethcmdlen, boardInterface);
         msgIndex += ethcmdlen;
         idrcmdlen += ethcmdlen;
         idrcmdcnt++;

         cmdcount = idrcmdcnt;
         cmdlength = msgIndex;
      }

      status = check_status(naibrd_Ether_SetIDRConfig(IDRcardIndex,(uint16_t)DEF_ETHERNET_DT_IDR_ID,protocol,DEF_RESPONSE_IP_LEN,dt_ether_int_rx_ip4,dt_ether_int_rx_port,vector,cmdcount,cmdlength,commands));
   }
   if (status == NAI_SUCCESS)
      bSuccess = TRUE;
   return bSuccess;
}

The configuration flow proceeds in four steps:

  1. Clear any previous IDR configuration — naibrd_Ether_ClearIDRConfig() removes any existing IDR registered under DEF_ETHERNET_DT_IDR_ID so the new configuration starts clean.

  2. Get the module register base — naibrd_GetModuleOffset() returns the base address for the installed module, which is needed to build absolute register addresses for the IDR read command.

  3. Build the read command — MakeIDRDTboardReadRegsCommand() constructs a single Ethernet read command that reads four latched status registers (BIT, low-to-high, high-to-low, overcurrent) starting at NAI_DT_GEN5_REG_BIT_LATCHED_STATUS_ADD with a stride of 0x10 between each register. This means all four status values are retrieved in one network round-trip.

  4. Register the IDR — naibrd_Ether_SetIDRConfig() programs the board with the complete IDR definition: the response IP address, port, protocol, interrupt vector, and the command payload to execute when the vector fires.

Starting and Stopping the IDR

Once the IDR is configured, start it with naibrd_Ether_StartIDR() so the board begins sending UDP notifications when interrupts occur:

status = naibrd_Ether_StartIDR(IDRcardIndex, (uint16_t)DEF_ETHERNET_DT_IDR_ID);

When the application exits, stop the IDR and close the board connection:

void ExitApp_DTEtherIDR(int32_t IDRcardIndex)
{
   ExitInterruptThreads();
   if (userInput_DTInt.cardIndex >= 0)
   {
      check_status(naibrd_Ether_StopIDR(IDRcardIndex, (uint16_t)DEF_ETHERNET_DT_IDR_ID));
      naibrd_Close(userInput_DTInt.cardIndex);
   }
}

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

Ethernet Interrupt Handler

HandleDTEtherInterrupt() is called when the application’s Ethernet listener receives a UDP message matching the IDR ID. Unlike the standard handler which reads status registers directly, this handler parses the status values out of the incoming network message — the board has already read the registers and packaged the results.

void HandleDTEtherInterrupt(uint16_t msglen, uint8_t msg[],uint16_t tdr_idr_id)
{
   uint16_t seq;
   nai_ether_typecode_t tc;
   nai_ether_gen_t gen;
   int32_t size;
   int32_t offset;
   uint16_t datacnt = 0;
   uint32_t data;
   uint32_t dtstatus_int[DT_INTERRUPT_RESPONSE_REG_COUNT];
   nai_dt_status_type_t dt_status_type = NAI_DT_STATUS_BIT_LATCHED;
   int32_t i;

   gen = NAI_ETHER_GEN4;
   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 < DT_INTERRUPT_RESPONSE_REG_COUNT)
            dtstatus_int[i] = data;
      }
      break;
   }

   /* Check to make sure we got all 4 status elements (BIT, Lo-Hi, Hi-Lo, Overcurrent) */
   if (datacnt == DT_INTERRUPT_RESPONSE_REG_COUNT)
   {
      for (i = 0; i < DT_INTERRUPT_RESPONSE_REG_COUNT; i++)
      {
         /* ... status checking, reporting, and clearing identical to standard handler ... */
      }
   }
}

The handler works as follows:

  1. Parse the message header — nai_ether_DecodeMessageHeader() extracts the sequence number, typecode, and payload offset from the raw UDP message.

  2. Verify the typecode — the handler checks for NAI_ETHER_TYPECODE_RSP_COMMAND_COMPLETE_READ_4, which indicates a successful 32-bit register read response. Other typecodes are ignored.

  3. Extract register values — each 32-bit register value is assembled from four bytes in big-endian order (msg[offset] << 24 | msg[offset+1] << 16 | …​). The four values correspond to the four latched status registers requested during IDR configuration.

  4. Check and clear status — the same status-checking and clearing logic from the standard handler applies here. Each non-zero status is reported, optionally the user is prompted before clearing (prompt-clear vs. auto-clear), and naibrd_DT_ClearGroupStatusRaw() is called to re-arm the interrupt.

Efficiency Advantage

The key advantage of the Ethernet IDR approach is that all four latched status register values arrive in a single UDP message. The standard handler must issue four separate naibrd_DT_GetGroupStatusRaw() calls — each one a register read over the bus — to retrieve the same information. For remote monitoring scenarios where the host communicates with the board over Ethernet, the IDR approach eliminates four network round-trips per interrupt event, reducing both latency and network traffic.

Important

Common Ethernet IDR errors:

  • "Ethernet Interrupt Support Prior to Generation 4…​" — the board firmware is older than Generation 4 and does not support IDR commands. Update the board firmware to Gen4 or later to use Ethernet IDR.

  • 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 UDP traffic on the configured port, and confirm that naibrd_Ether_StartIDR() was called after naibrd_Ether_SetIDRConfig().

  • Message parsing errors — if datacnt does not equal DT_INTERRUPT_RESPONSE_REG_COUNT (4), the IDR read command was not constructed correctly or the board returned an unexpected response. Verify that the protocol generation matches (NAI_ETHER_GEN4) and that MakeIDRDTboardReadRegsCommand() was called with count set to DT_INTERRUPT_RESPONSE_REG_COUNT and the correct stride value (0x10).

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.

Debugging Interrupts That Are Not Firing

When interrupts are not being delivered, use this two-step approach to isolate the problem:

  1. Check whether the status registers are changing. Call naibrd_DT_GetGroupStatusRaw() to read the latched status registers for the interrupt type you expect. If the status bits are changing when the hardware condition occurs, the module is detecting the event correctly — the issue is in your interrupt delivery path (steering, ISR installation, or thread setup).

  2. If the status registers are NOT changing, the issue is at the hardware or channel configuration level. Verify that the correct channel is configured, the trigger mode matches the signal behavior, and the physical signal is actually present at the input. You can also read the status registers directly at their register addresses to bypass the API layer entirely. Consult your module’s manual for the specific register addresses for each status type.

This approach quickly narrows down whether the problem is on the hardware/configuration side or the interrupt delivery side, saving significant debugging time.

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 DT

No DT module installed at the selected slot, incorrect module number, or a non-DT module is present

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

ISR installation failure

Steering mode does not match hardware configuration, driver not loaded, or bus access issue

Verify steering mode matches your bus architecture. On Linux, check that the NAI driver is loaded. On Windows, verify the device appears in Device Manager.

Interrupts not firing after enable

Status registers not cleared before enabling, wrong steering mode, ISR not installed, or thread not started

Follow the full setup sequence: disable, clear status, configure, install ISR, enable, start thread. See the debugging technique above.

Wrong steering mode

Using onboard steering from an external host, or offboard steering from the onboard processor

Match steering to where your application executes. Onboard: ON_BOARD_0 (or PCIE_APP on PPC_XILINX). External PCI: CPCI_APP. External PCIe: PCIE_APP.

PPC_XILINX platform mismatch

PowerPC boards require PCIE_APP steering for onboard interrupts, not ON_BOARD_0

Check for the PPC_XILINX build flag and use NAIBRD_INT_STEERING_PCIE_APP on these platforms

Handler never called (standard)

Thread not started, ISR not installed for correct IRQ, or steering mismatch

Verify UpdateThreadState(RUN) was called, ISR was installed with the correct IRQ ID, and steering matches bus type

Interrupts stop after first (edge-triggered)

Status not cleared in handler — edge interrupts require clearing to re-arm

Ensure naibrd_DT_ClearGroupStatusRaw() is called in the handler for each status type that fired

Interrupts fire continuously (level-triggered)

The underlying condition persists — this is expected for level-triggered interrupts

Switch to edge triggering if continuous firing is not desired, or address the underlying hardware condition

Gen4 Ethernet not supported

Board Ethernet firmware is older than Gen4

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

No IDR messages received (Ethernet)

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

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

Ethernet message parsing errors

Protocol generation mismatch between board and application

Verify both use Gen4 protocol. Check that the received message contains the expected number of status registers (4).

Status registers not changing (debugging)

Channel not configured correctly, trigger mode mismatch, no physical signal present

Verify channel configuration, trigger mode, and that the expected signal is present at the input. Read registers directly — consult module manual for addresses.

Full Source

The complete source for this sample is provided below for reference. The sections above explain each part in detail. This sample consists of three source files: the standard interrupt application, the Ethernet IDR variant, and shared configuration code used by both.

Full Source — DT_Interrupt.c (SSK 1.x)
/**************************************************************************************************************/
/**
<summary>
The DT_Ethernet_IDR program that handle multiple channel interrupts for the Discrete module using the
Ethernet IDR (Interrupt Driven Response) commands.

Interrupts for Fault, Low-to-High Transition, High-to-Low Transition and Overcurrent are enabled.
</summary>
*/
/**************************************************************************************************************/

/************************/
/* Include Declarations */
/************************/
#if defined (WIN32)
 #include <winsock2.h>
 #include <ws2tcpip.h>
 #pragma comment (lib, "Ws2_32.lib")
#endif

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <stdint.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"

/* Generic NAI Board Library include files */
#include "nai.h"
#include "naibrd.h"
#include "naibrd_ether.h"
#include "advanced/nai_ether_adv.h"

/* Module Specific NAI Board Library files */
#include "functions/naibrd_dt.h"
#include "maps/nai_map_dt.h"

/* Module Specific sample code include files */
#include "DT_Interrupt_Common.h"

/* Extern Functions or Variables*/
extern IntProcessFuncDef dtIntProcessFunc;

/*********************************************/
/* Application Name and Revision Declaration */
/*********************************************/
/*
static const int8_t *App_Name = "DT Interrupt";
static const int8_t *App_Rev = "1.0";
*/

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

/* Number of Registers to retrieve with each interrupt message:
   Fault, Low-to-High Transition, High-to-Low Transition and Overcurrent.
*/
#define DT_INTERRUPT_RESPONSE_REG_COUNT     4

static bool_t bPromptForInterruptClear = TRUE;
static bool_t bProcessOnboardInterrupts = TRUE;
static bool_t isPCIE                    = FALSE;

/********************************/
/* Internal Function Prototypes */
/********************************/
static bool_t DT_QueryUserForClearingInterruptPrompts(void);
static bool_t QueryUserForOnboardOffbordInterrupts(void);
void HandleDTInterrupt(uint32_t nVector);
void ExitApp_DTInterrupt(void);

/**************************************************************************************************************/
/*****                                     Main Routine                                                   *****/
/**************************************************************************************************************/
/**************************************************************************************************************/
/**
<summary>
The purpose of the DT_Interrupt is to illustrate the methods to call in the naibrd library to configure the
discrete module to generate interrupts on any channel for the following events:
 - Fault,
 - Low-to-High Transition,
 - High-to-Low Transition, or
 - Overcurrent

The following routines from the DT_Interrupt_Common.c file are called to assist with displaying, handling prompting
the user for inputs and configurating the channels on the discrete modules:
 - DisplayMessage_DTInterrupt
 - PromptUserInput_DTInterrupt
 - ConfigDTInterrupt
 - EnableDTInterrupt

The following routines from the nai_sys_int.c file are called to assist with setup the threads used by this
application to handle the interrupt and user interface:
 - InitInterruptAppThread
 - UpdateThreadState

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 DT routines.
 - ConfigDevice
 - DisplayDeviceCfg
 - GetBoardSNModCfg

</summary>
*/
/**************************************************************************************************************/
#if defined (__VXWORKS__)
void DT_Interrupt(void)
#else
int32_t main(void)
#endif
{
   bool_t bQuit = FALSE;
   bool_t bSuccess = FALSE;

   DisplayMessage_DTInterrupt(MSG_BANNER_DT_INT);
   if (naiapp_RunBoardMenu(CONFIG_FILE) == TRUE)
   {
      while (!bQuit)
      {
         naiapp_access_SystemSNModCfg();
         bQuit = PromptUserInput_DTInterrupt(&bSuccess);
         if ((!bQuit) & bSuccess)
         {
            bQuit = DT_QueryUserForClearingInterruptPrompts();
            if (!bQuit)
            {
               bQuit = QueryUserForOnboardOffbordInterrupts();
               if (!bQuit)
               {
                  if ( bProcessOnboardInterrupts == TRUE )
                  {
                     printf("\nOnboard Interrupts selected.\n");
                     ConfigDTInterrupt(ONBOARD_INT);
                     InitInterruptAppThread(ONBOARD_INT, 0);
                     /* Set the dtIntProcessFunc global function pointer to point to the routine that will handle
                        Interrupt messages associated with the Discrete Interrupt Vector (DEF_ETHERNET_DT_IDR_ID).
                     */
                     dtIntProcessFunc = HandleDTInterrupt;

                     if ( naibrd_InstallISR(userInput_DTInt.cardIndex, NAIBRD_IRQ_ID_ON_BOARD_0, (nai_isr_t)IntOnboardIsr, (void*)&userInput_DTInt.cardIndex) == NAI_SUCCESS)
                     {
                        DisplayMessage_DTInterrupt(MSG_USER_TRIGGER_DT_INT);
                        EnableDTInterrupt(TRUE);
                        /* Add a small delay to make sure the Interrupt State Machine Task has completed initialization */
                        nai_msDelay(10);
                        UpdateThreadState(RUN);
                     }
                     else
                     {
                        printf("\n***** Error - naibrd_InstallISR (Onboard) FAILED - Interrupts will not work. *****\n");
                        bQuit = TRUE;
                     }
                  }
                  else
                  {
                     printf("\nOffboard Interrupts selected.\n");
                     if( isPCIE == TRUE )
                     {
                        ConfigDTInterrupt(MASTER_PCIE_BUS_OFFBOARD_INT);
                        InitInterruptAppThread(MASTER_PCIE_BUS_OFFBOARD_INT, 0);
                     }
                     else
                     {
                        ConfigDTInterrupt(MASTER_PCIBUS_OFFBOARD_INT);
                        InitInterruptAppThread(MASTER_PCIBUS_OFFBOARD_INT, 0);
                     }

                     /* Set the dtIntProcessFunc global function pointer to point to the routine that will handle
                        Interrupt messages associated with the Discrete Interrupt Vector (DEF_ETHERNET_DT_IDR_ID).
                     */
                     dtIntProcessFunc = HandleDTInterrupt;

                     if ( naibrd_InstallISR(userInput_DTInt.cardIndex, NAIBRD_IRQ_ID_DONT_CARE, (nai_isr_t)IntOffboardIsr, (void*)&userInput_DTInt.cardIndex) == NAI_SUCCESS)
                     {
                        DisplayMessage_DTInterrupt(MSG_USER_TRIGGER_DT_INT);
                        EnableDTInterrupt(TRUE);
                        /* Add a small delay to make sure the Interrupt State Machine Task has completed initialization */
                        nai_msDelay(10);
                        UpdateThreadState(RUN);
                     }
                     else
                     {
                        printf("\n***** Error - naibrd_InstallISR (Offboard) FAILED - Interrupts will not work. *****\n");
                        bQuit = TRUE;
                     }
                  }
               }
               else
               {
                  UpdateThreadState(TERMINATED);
               }
            }
            else
            {
               UpdateThreadState(TERMINATED);
            }
            bQuit = TRUE;
        }
    }
}
   ExitApp_DTInterrupt();
#if !defined (__VXWORKS__)
   return(0);
#endif
}

/**************************************************************************************************************/
/*****                                  Internal Functions                                                *****/
/**************************************************************************************************************/

/**************************************************************************************************************/
/**
<summary>
DT_QueryUserForClearingInterruptPrompts handles querying the user to see if he wants to be prompted to clear
the interrupts when an interrupt is received. If the user specifies 'N', the interrupts will automatically
be cleared when an interrupt is received. Otherwise, the program will prompt the user to enter a 'C' to
clear the interrupts.
</summary>
*/
/**************************************************************************************************************/
static bool_t DT_QueryUserForClearingInterruptPrompts(void)
{
   bool_t bQuit = FALSE;
   int8_t inputBuffer[80];
   int32_t inputResponseCnt;

   /* Query the user to determine if he wants to be prompted before clearing the interrupt */
   printf("\nWould you like to be prompted to clear interrupts? (Y or N) (Default: Y): ");
   bQuit = naiapp_query_ForQuitResponse(sizeof(inputBuffer), NAI_QUIT_CHAR, inputBuffer, &inputResponseCnt);
   if (!bQuit)
   {
      if (inputResponseCnt != 0)
      {
         if ((inputBuffer[0] == 'N') || (inputBuffer[0] == 'n'))
         {
            bPromptForInterruptClear = FALSE;
         }
         else
         {
            bPromptForInterruptClear = TRUE;
         }
      }
      else
      {
         bPromptForInterruptClear = TRUE;
      }
   }
   return bQuit;
}

/**************************************************************************************************************/
/**
<summary>
QueryUserForOnboardOffbordInterrupts handles querying the user to see if he wants process Onboard or
Offboard interrupts. If the user specifies 'O', Onboard interrupts will be processed, else Offboard (External)
interrupt will be processed.
</summary>
*/
/**************************************************************************************************************/
static bool_t QueryUserForOnboardOffbordInterrupts(void)
{
   bool_t bQuit = FALSE;
   int8_t inputBuffer[80];
   int32_t inputResponseCnt;

   /* Query the user to determine if he wants Onboard or external Offbord Interrupts */
   printf("\nWould you like to be process Onboard(O) or external Offbord_PCI(P) Offbord_PCIE(E) Interrupts? (Default: O): ");
   bQuit = naiapp_query_ForQuitResponse(sizeof(inputBuffer), NAI_QUIT_CHAR, inputBuffer, &inputResponseCnt);
   if (!bQuit)
   {
      if (inputResponseCnt != 0)
      {
         if ( (inputBuffer[0] == 'E') || (inputBuffer[0] == 'e') || (inputBuffer[0] == 'P') || (inputBuffer[0] == 'p') )
         {
            if( (inputBuffer[0] == 'E') || (inputBuffer[0] == 'e') )
               isPCIE = TRUE;
            bProcessOnboardInterrupts = FALSE;
         }
         else
         {
            bProcessOnboardInterrupts = TRUE;
         }
      }
      else
      {
         bProcessOnboardInterrupts = TRUE;
      }
   }
   return bQuit;
}

/**************************************************************************************************************/
/**
<summary>
HandleDTInterrupt is called by the HandleDTInterrupt() routine in nai_sys_int.c when an
a message is received from the interrupt service routine.
</summary>
*/
/**************************************************************************************************************/

void HandleDTInterrupt(uint32_t nVector)
{
   int32_t i;
   uint32_t dtstatus_int[DT_INTERRUPT_RESPONSE_REG_COUNT];
   nai_dt_status_type_t dt_status_type = NAI_DT_STATUS_BIT_LATCHED;

   /* Check all 4 status elements (BIT, Lo-Hi, Hi-Lo, Overcurrent) */
   printf("\n\n");
   for (i = 0; i < DT_INTERRUPT_RESPONSE_REG_COUNT; i++)
   {
      switch (i)
      {
      case 0:
         dt_status_type = NAI_DT_STATUS_BIT_LATCHED;
         break;
      case 1:
         dt_status_type = NAI_DT_STATUS_LO_HI_TRANS_LATCHED;
         break;
      case 2:
         dt_status_type = NAI_DT_STATUS_HI_LO_TRANS_LATCHED;
         break;
      case 3:
         dt_status_type = NAI_DT_STATUS_OVERCURRENT_LATCHED;
         break;
      }

      check_status(naibrd_DT_GetGroupStatusRaw(userInput_DTInt.cardIndex, userInput_DTInt.moduleNumber, 1, dt_status_type, &dtstatus_int[i]));

      if (dtstatus_int[i] != 0)
      {
         switch (i)
         {
         case 0:
            printf("Received DT Bit Interrupt: (Interrupt_status) 0x%08X\n", dtstatus_int[i]);
         break;
         case 1:
            printf("Received DT Lo-Hi Interrupt: (Interrupt_status) 0x%08X\n", dtstatus_int[i]);
         break;
         case 2:
            printf("Received DT Hi-Lo Interrupt: (Interrupt_status) 0x%08X\n", dtstatus_int[i]);
         break;
         case 3:
            printf("Received DT Overcurrent Interrupt: (Interrupt_status) 0x%08X\n", dtstatus_int[i]);
         break;
         }
         if (bPromptForInterruptClear)
         {
            /* Prompt the user t to clear the interrupt received */
            SetUserRequestClearInt(FALSE);
            DisplayMessage_DTInterrupt(MSG_USER_CLEAR_DT_INT);
            /* Wait for the user to respond */
            while (!GetUserRequestClearInt())
            {
               nai_msDelay(10);
            }
         }
         /* Clear the status state to re-arm the interrupts */
         check_status(naibrd_DT_ClearGroupStatusRaw(userInput_DTInt.cardIndex, userInput_DTInt.moduleNumber, 1, dt_status_type, dtstatus_int[i]));
         switch (i)
         {
         case 0:
            printf("Cleared DT Bit Interrupt: 0x%08X\n", dtstatus_int[i]);
         break;
         case 1:
            printf("Cleared DT Lo-Hi Interrupt: 0x%08X\n", dtstatus_int[i]);
         break;
         case 2:
            printf("Cleared DT Hi-Lo Interrupt: 0x%08X\n", dtstatus_int[i]);
         break;
         case 3:
            printf("Cleared DT Overcurrent Interrupt: 0x%08X\n", dtstatus_int[i]);
         break;
         }
      }
   }
}

void ExitApp_DTInterrupt(void)
{
   ExitInterruptThreads();
   if (userInput_DTInt.cardIndex >= 0)
   {
      naibrd_Close(userInput_DTInt.cardIndex);
   }
}
Full Source — DT_Ethernet_IDR.c (SSK 1.x)
/**************************************************************************************************************/
/**
<summary>
The DT_Ethernet_IDR program that handle multiple channel interrupts for the Discrete module using the
Ethernet IDR (Interrupt Driven Response) commands.

Interrupts for Fault, Low-to-High Transition, High-to-Low Transition and Overcurrent are enabled.
</summary>
*/
/**************************************************************************************************************/

/************************/
/* Include Declarations */
/************************/
#if defined (WIN32)
 #include <winsock2.h>
 #include <ws2tcpip.h>
 #pragma comment (lib, "Ws2_32.lib")
#endif

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <stdint.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"

/* Generic NAI Board Library include files */
#include "nai.h"
#include "naibrd.h"
#include "naibrd_ether.h"
#include "advanced/nai_ether_adv.h"

/* Module Specific NAI Board Library files */
#include "functions/naibrd_dt.h"
#include "maps/nai_map_dt.h"

/* Module Specific sample code include files */
#include "DT_Interrupt_Common.h"

bool_t bDisplayEtherUPR;
etherIntFuncDef dtEtherIntFunc;

/*********************************************/
/* Application Name and Revision Declaration */
/*********************************************/
/*
static const int8_t *App_Name = "DT ETHERNET INTERRUPT";
static const int8_t *App_Rev = "1.0";
*/

static const int8_t *DEF_CONFIG_FILE = (int8_t *)"default_DT_Ethernet_Int.txt";

/*****************************/
/* Ethernet IDR Declarations */
/*****************************/
/* Default Definitions for Ethernet IDR */
#define DEF_RESPONSE_IP_LEN              ETHER_GEN4_IPv4_ADDR_LEN
#define DEF_RESPONSE_PROTOCOL            ETHER_GEN4_UDP_PROTOCOL
uint16_t DEF_DT_RX_RESPONSE_PORT         =  52802;
uint8_t  DEF_DT_RX_RESPONSE_IP4_ADDR[]   = {192,168,1,200};

/* IP Address and Ethernet Port to receive the interrupt messages */
uint16_t dt_ether_int_rx_port;
uint8_t  dt_ether_int_rx_ip4[4];
uint16_t dt_ether_int_protocol;

/* Number of Registers to retrieve with each interrupt message:
   Fault, Low-to-High Transition, High-to-Low Transition and Overcurrent.
*/
#define DT_INTERRUPT_RESPONSE_REG_COUNT     4

bool_t bPromptForInterruptClear = TRUE;

/********************************/
/* Internal Function Prototypes */
/********************************/
bool_t SetupDTEtherIDRconfig(uint16_t protocol, int32_t IDRcardIndex, int32_t boardInterface);
bool_t QueryUserForClearingDTInterruptPrompts(void);
bool_t QueryUserForOnboardOffboardDTInterrupts();
void MakeIDRDTboardReadRegsCommand(uint16_t startIndex, uint32_t moduleOffset, uint32_t regAddr, uint32_t count, uint32_t stride, uint8_t commands[], uint16_t *cmdlen,int32_t boardInterface);
void HandleDTEtherInterrupt(uint16_t msglen, uint8_t msg[], uint16_t tdr_idr_id);void StartDTEtherIDR(int32_t IDRcardIndex);
void ExitApp_DTEtherIDR(int32_t IDRcardIndex);
void ConfigETHERInterrupt(naibrd_int_steering_t steering);

/**************************************************************************************************************/
/*****                                     Main Routine                                                   *****/
/**************************************************************************************************************/
/**************************************************************************************************************/
/**
<summary>
The purpose of the DT_Ethernet_IDR is to illustrate the methods to call in the naibrd library to configure the
discrete module to generate interrupts on any channel for the following events:
 - Fault,
 - Low-to-High Transition,
 - High-to-Low Transition, or
 - Overcurrent

The following routines from the DT_Interrupt_Common.c file are called to assist with displaying, handling prompting
the user for inputs and configuring the channels on the discrete modules:
 - DisplayMessage_DTInterrupt
 - PromptUserInput_DTInterrupt
 - ConfigDTInterrupt
 - EnableDTInterrupt

The following routines from the nai_sys_cfg.c file are called to assist with handling prompting
the user for inputs specific to configuring the discrete modules for Ethernet interrupts:
 - QueryUnpromptedEtherResponseIP4Addr
 - SetUPREtherPort

The following routines from the nai_sys_int_ether.c file are called to verify that the Ethernet Protocol
is supported by this application:
 - CheckNaiEtherProtocolVersion

The following routines from the nai_sys_int.c file are called to assist with setup the threads used by this
application to handle the interrupt and user interface:
 - InitInterruptAppThread
 - UpdateThreadState

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 DT routines.
 - ConfigDevice
 - DisplayDeviceCfg
 - GetBoardSNModCfg

</summary>
*/
/**************************************************************************************************************/
#if defined (__VXWORKS__)
void DT_Ethernet_IDR(void)
#else
int32_t main(void)
#endif
{
   bool_t bQuit = FALSE;
   bool_t bSuccess = FALSE;
   bool_t bProcessOnboardInterrupts = FALSE;
   bool_t bPromptforInterruptClear = FALSE;
   int32_t IDRcardIndex=0;
   naibrd_int_steering_t steering;
   int32_t boardInterface;

   DisplayMessage_DTInterrupt(MSG_BANNER_DT_INT);
   if (naiapp_RunBoardMenu(DEF_CONFIG_FILE) == TRUE)
   {
      while (!bQuit)
      {
         naiapp_access_SystemSNModCfg();
         bQuit = PromptUserInput_DTInterrupt(&bSuccess);
         if ((!bQuit) & bSuccess)
         {
            bQuit = QueryUnpromptedEtherResponseIP4Addr(DEF_DT_RX_RESPONSE_IP4_ADDR, DEF_DT_RX_RESPONSE_PORT, DEF_RESPONSE_PROTOCOL, dt_ether_int_rx_ip4, &dt_ether_int_rx_port, &dt_ether_int_protocol);
            if (!bQuit)
               bQuit = QueryUserForEtherIDRMsgDisplay(&bDisplayEtherUPR);
            if (!bQuit)
               bQuit = QueryUserForClearingInterruptPrompts(&bPromptforInterruptClear);
           if(!bQuit){
            bQuit = QueryUserForOnboardOffboardInterrupts(&bProcessOnboardInterrupts);
            }
            if (!bQuit)
            {
             if(bProcessOnboardInterrupts == TRUE)
              {
               IDRcardIndex = userInput_DTInt.cardIndex;
               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;
              }

               naiapp_utils_SetUPREtherPort(dt_ether_int_rx_port);
               bSuccess = CheckNaiEtherProtocolVersion(userInput_DTInt.cardIndex);
               if (bSuccess)
                  ConfigETHERInterrupt(steering);
               else
                  printf("ERROR: Ethernet Interrupt Support Prior to Generation 4 Ethernet commands are currently NOT supported.\n");
               if (bSuccess)
               {
                  InitInterruptAppThread(ETHERNET_INT, dt_ether_int_protocol);
                  /* Set the dtEtherIntFunc global function pointer to point to the routine that will handle
                     Interrupt messages associated with the Discrete Interrupt Vector (DEF_ETHERNET_DT_IDR_ID).
                  */
                  dtEtherIntFunc = HandleDTEtherInterrupt;
                  if (SetupDTEtherIDRconfig(dt_ether_int_protocol, IDRcardIndex, boardInterface))
                  {
                     DisplayMessage_DTInterrupt(MSG_USER_TRIGGER_DT_INT);
                     StartDTEtherIDR(IDRcardIndex);
                     EnableDTInterrupt(TRUE);
                     UpdateThreadState(RUN);
                  }
                  else
                     bQuit = TRUE;
               }
            }
            else
            {
               UpdateThreadState(TERMINATED);
            }
            bQuit = TRUE;
         }
      }
   }
   ExitApp_DTEtherIDR(IDRcardIndex);

#if !defined (__VXWORKS__)
   return(0);
#endif

}

/**************************************************************************************************************/
/*****                                  Internal Functions                                                *****/
/**************************************************************************************************************/

/**************************************************************************************************************/
/**
<summary>
SetupDTEtherIDRconfig calls the routines in the naibrd library to clear and setup the Ethernet IDR
(Interrupt Driven Response) command for the Discrete module. The DEF_ETHERNET_DT_IDR_ID and NAI_DT_INTERRUPT_VECTOR
specified in the nai_sys_int_common.h file are used as the IDR_ID and interrupt vector for this application.
The MakeIDROnboardReadRegsCommand() routine in the nai_sys_int_ether.c file is called to create a Ethernet
IDR command that consists of one ReadRegs command which retrieves and returns the contents in the Latched Status
registers for the BIT (Fault), Low-to-High Transition, High-to-Low Transition and Overcurrent when an interrupt
is detected.
</summary>
*/
/**************************************************************************************************************/
bool_t SetupDTEtherIDRconfig(uint16_t protocol, int32_t IDRcardIndex, int32_t boardInterface)
{
   bool_t bSuccess = FALSE;
   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;
   uint8_t commands[MAX_ETHER_IDR_CMD_CNT*MAX_ETHER_BLOCK_REG_CNT];
   int32_t vector = NAI_DT_INTERRUPT_VECTOR;
   uint32_t stride = 0x10;  /* Register offset between the latched status register for each type of status */
   uint16_t cmdcount = 0;
   uint16_t cmdlength = 0;

   /* Clear the Ethernet Interrupt Driven Response Configuration associated with the ID: DEF_ETHERNET_DT_IDR_ID */
   status = naibrd_Ether_ClearIDRConfig(IDRcardIndex,(uint16_t)DEF_ETHERNET_DT_IDR_ID);
   if (status == NAI_SUCCESS)
   {
      status = check_status(naibrd_GetModuleOffset(userInput_DTInt.cardIndex, userInput_DTInt.moduleNumber, &moduleOffset));
      if (status == NAI_SUCCESS)
      {
         /* First command */
         /* Perform ReadRegs command starting with NAI_DT_GEN5_REG_BIT_LATCHED_STATUS_ADD */
         /* This reads:
            - NAI_DT_GEN5_REG_BIT_LATCHED_STATUS_ADD,
            - NAI_DT_GEN5_REG_LO_HI_TRANS_LATCHED_STATUS_ADD,
            - NAI_DT_GEN5_REG_HI_LO_TRANS_LATCHED_STATUS_ADD
            - NAI_DT_GEN5_REG_OVERCURRENT_LATCHED_STATUS_ADD
         */
         MakeIDRDTboardReadRegsCommand(msgIndex, moduleOffset, NAI_DT_GEN5_REG_BIT_LATCHED_STATUS_ADD, DT_INTERRUPT_RESPONSE_REG_COUNT, stride, commands, &ethcmdlen, boardInterface);
         msgIndex += ethcmdlen;
         idrcmdlen += ethcmdlen;
         idrcmdcnt++;

         cmdcount = idrcmdcnt;
         cmdlength = msgIndex;
      }

      status = check_status(naibrd_Ether_SetIDRConfig(IDRcardIndex,(uint16_t)DEF_ETHERNET_DT_IDR_ID,protocol,DEF_RESPONSE_IP_LEN,dt_ether_int_rx_ip4,dt_ether_int_rx_port,vector,cmdcount,cmdlength,commands));
   }
   if (status == NAI_SUCCESS)
      bSuccess = TRUE;
   return bSuccess;
}

/**************************************************************************************************************/
/**
<summary>
StartDTEtherIDR calls the routines in the naibrd library to start/enable the Ethernet IDR
(Interrupt Driven Response) command associated with DEF_ETHERNET_DT_IDR_ID for the Discrete module.
</summary>
*/
/**************************************************************************************************************/
void StartDTEtherIDR(int32_t IDRcardIndex)
{
   nai_status_t status;

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

/**************************************************************************************************************/
/**
<summary>
HandleDTEtherInterrupt 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 HandleDTEtherInterrupt(uint16_t msglen, uint8_t msg[],uint16_t tdr_idr_id)
{
   uint16_t seq;
   nai_ether_typecode_t tc;
   nai_ether_gen_t gen;
   int32_t size;
   int32_t offset;
   uint16_t datacnt = 0;
   uint32_t data;
   uint32_t dtstatus_int[DT_INTERRUPT_RESPONSE_REG_COUNT];
   nai_dt_status_type_t dt_status_type = NAI_DT_STATUS_BIT_LATCHED;
   int32_t i;

   gen = NAI_ETHER_GEN4;
   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 < DT_INTERRUPT_RESPONSE_REG_COUNT)
            dtstatus_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 == DT_INTERRUPT_RESPONSE_REG_COUNT)
   {
      for (i = 0; i < DT_INTERRUPT_RESPONSE_REG_COUNT; i++)
      {
         switch (i)
         {
         case 0:
            dt_status_type = NAI_DT_STATUS_BIT_LATCHED;
            break;
         case 1:
            dt_status_type = NAI_DT_STATUS_LO_HI_TRANS_LATCHED;
            break;
         case 2:
            dt_status_type = NAI_DT_STATUS_HI_LO_TRANS_LATCHED;
            break;
         case 3:
            dt_status_type = NAI_DT_STATUS_OVERCURRENT_LATCHED;
            break;
         }
         if (dtstatus_int[i] != 0)
         {
            switch (i)
            {
            case 0:
               printf("Received DT Bit Interrupt: (Interrupt_status) 0x%08X\n", dtstatus_int[i]);
            break;
            case 1:
               printf("Received DT Lo-Hi Interrupt: (Interrupt_status) 0x%08X\n", dtstatus_int[i]);
            break;
            case 2:
               printf("Received DT Hi-Lo Interrupt: (Interrupt_status) 0x%08X\n", dtstatus_int[i]);
            break;
            case 3:
               printf("Received DT Overcurrent Interrupt: (Interrupt_status) 0x%08X\n", dtstatus_int[i]);
            break;
            }
            if (bPromptForInterruptClear)
            {
               /* Prompt the user t to clear the interrupt received */
               SetUserRequestClearInt(FALSE);
               DisplayMessage_DTInterrupt(MSG_USER_CLEAR_DT_INT);
               /* Wait for the user to respond */
               while (!GetUserRequestClearInt())
               {
                  nai_msDelay(10);
               }
            }
            /* Clear the status state to re-arm the interrupts */
            check_status(naibrd_DT_ClearGroupStatusRaw(userInput_DTInt.cardIndex, userInput_DTInt.moduleNumber, 1, dt_status_type, dtstatus_int[i]));
            switch (i)
            {
            case 0:
               printf("Cleared DT Bit Interrupt: 0x%08X\n", dtstatus_int[i]);
            break;
            case 1:
               printf("Cleared DT Lo-Hi Interrupt: 0x%08X\n", dtstatus_int[i]);
            break;
            case 2:
               printf("Cleared DT Hi-Lo Interrupt: 0x%08X\n", dtstatus_int[i]);
            break;
            case 3:
               printf("Cleared DT Overcurrent Interrupt: 0x%08X\n", dtstatus_int[i]);
            break;
            }
         }
      }
   }
}

/**************************************************************************************************************/
/**
<summary>
ExitApp_DTEtherIDR calls ExitInterruptThreads() in the nai_sys_int.c file to kill the threads created by
this application and calls the routines in the naibrd library to stop/disable) the Ethernet IDR
(Interrupt Driven Response) command associated with DEF_ETHERNET_DT_IDR_ID for the Discrete module and
close communication connection to the board.
</summary>
*/
/**************************************************************************************************************/
void ExitApp_DTEtherIDR(int32_t IDRcardIndex)
{
   ExitInterruptThreads();
   if (userInput_DTInt.cardIndex >= 0)
   {
      check_status(naibrd_Ether_StopIDR(IDRcardIndex, (uint16_t)DEF_ETHERNET_DT_IDR_ID));
      naibrd_Close(userInput_DTInt.cardIndex);
   }
}

/* QueryUserForOnboardOffbordDTInterrupts handles querying the user to see if she wants process Onboard or */

/**************************************************************************************************************/
/**
<summary>
MakeIDROnboardReadRegsCommand calls nai_ether_MakeReadMessage() in the naibrd library build the Read Register
command for the IDR message.
</summary>
*/
/**************************************************************************************************************/
void MakeIDRDTboardReadRegsCommand(uint16_t startIndex, uint32_t moduleOffset, uint32_t regAddr, uint32_t count, uint32_t stride, uint8_t commands[], uint16_t *cmdlen, int32_t boardInterface)
{
   uint16_t msgIndex = startIndex;
   uint16_t seqno;
   uint32_t regaddr;

   seqno = 0;
   regaddr = moduleOffset + regAddr;
   msgIndex = (uint16_t)nai_ether_MakeReadMessage(&commands[startIndex],seqno,NAI_ETHER_GEN4,(nai_intf_t)boardInterface,regaddr,stride,count,NAI_REG32);

   *cmdlen = msgIndex;
}

/**************************************************************************************************************/
/**
<summary>
ConfigDTInterrupt handles disabling the discrete interrupts, clearing any latched statuses, setting the
interrupt vector (NAI_DT_INTERRUPT_VECTOR), and latch status mode (Edge/Level). The interrupt steering
configuration is configuration based on the interruptCommType that is passed in.
</summary>
*/
/**************************************************************************************************************/
void ConfigETHERInterrupt(naibrd_int_steering_t steering)
{
   uint32_t rawstatus = 0;
   int32_t chan;
   uint8_t interrupt_t;

   /* Disable Interrupts */
   EnableDTInterrupt(FALSE);

   /* Clear the Interrupt Status (Read the status and write back "1" to statuses which are set to clear the status) */
   check_status(naibrd_DT_GetGroupStatusRaw(userInput_DTInt.cardIndex, userInput_DTInt.moduleNumber, 1, NAI_DT_STATUS_BIT_LATCHED, &rawstatus));
   check_status(naibrd_DT_ClearGroupStatusRaw(userInput_DTInt.cardIndex, userInput_DTInt.moduleNumber, 1, NAI_DT_STATUS_BIT_LATCHED, rawstatus));
   check_status(naibrd_DT_GetGroupStatusRaw(userInput_DTInt.cardIndex, userInput_DTInt.moduleNumber, 1, NAI_DT_STATUS_LO_HI_TRANS_LATCHED, &rawstatus));
   check_status(naibrd_DT_ClearGroupStatusRaw(userInput_DTInt.cardIndex, userInput_DTInt.moduleNumber, 1, NAI_DT_STATUS_LO_HI_TRANS_LATCHED, rawstatus));
   check_status(naibrd_DT_GetGroupStatusRaw(userInput_DTInt.cardIndex, userInput_DTInt.moduleNumber, 1, NAI_DT_STATUS_HI_LO_TRANS_LATCHED, &rawstatus));
   check_status(naibrd_DT_ClearGroupStatusRaw(userInput_DTInt.cardIndex, userInput_DTInt.moduleNumber, 1, NAI_DT_STATUS_HI_LO_TRANS_LATCHED, rawstatus));
   check_status(naibrd_DT_GetGroupStatusRaw(userInput_DTInt.cardIndex, userInput_DTInt.moduleNumber, 1, NAI_DT_STATUS_OVERCURRENT_LATCHED, &rawstatus));
   check_status(naibrd_DT_ClearGroupStatusRaw(userInput_DTInt.cardIndex, userInput_DTInt.moduleNumber, 1, NAI_DT_STATUS_OVERCURRENT_LATCHED, rawstatus));

   /* Setup the Interrupt Vector - map to the same vector */
   check_status(naibrd_DT_SetGroupInterruptVector(userInput_DTInt.cardIndex, userInput_DTInt.moduleNumber, 1, NAI_DT_STATUS_BIT_LATCHED, NAI_DT_INTERRUPT_VECTOR));
   check_status(naibrd_DT_SetGroupInterruptVector(userInput_DTInt.cardIndex, userInput_DTInt.moduleNumber, 1, NAI_DT_STATUS_LO_HI_TRANS_LATCHED, NAI_DT_INTERRUPT_VECTOR));
   check_status(naibrd_DT_SetGroupInterruptVector(userInput_DTInt.cardIndex, userInput_DTInt.moduleNumber, 1, NAI_DT_STATUS_HI_LO_TRANS_LATCHED, NAI_DT_INTERRUPT_VECTOR));
   check_status(naibrd_DT_SetGroupInterruptVector(userInput_DTInt.cardIndex, userInput_DTInt.moduleNumber, 1, NAI_DT_STATUS_OVERCURRENT_LATCHED, NAI_DT_INTERRUPT_VECTOR));

   /* Setup the Latched Status Mode */
   interrupt_t = (uint8_t)userInput_DTInt.intTriggerType;
   for (chan = 1; chan <= boardState_DTInt.maxChannels; chan++)
   {
      check_status(naibrd_DT_SetEdgeLevelInterrupt(userInput_DTInt.cardIndex, userInput_DTInt.moduleNumber, chan, NAI_DT_STATUS_BIT_LATCHED, interrupt_t));
      check_status(naibrd_DT_SetEdgeLevelInterrupt(userInput_DTInt.cardIndex, userInput_DTInt.moduleNumber, chan, NAI_DT_STATUS_LO_HI_TRANS_LATCHED, interrupt_t));
      check_status(naibrd_DT_SetEdgeLevelInterrupt(userInput_DTInt.cardIndex, userInput_DTInt.moduleNumber, chan, NAI_DT_STATUS_HI_LO_TRANS_LATCHED, interrupt_t));
      check_status(naibrd_DT_SetEdgeLevelInterrupt(userInput_DTInt.cardIndex, userInput_DTInt.moduleNumber, chan, NAI_DT_STATUS_OVERCURRENT_LATCHED, interrupt_t));
   }

   /* Setup the Interrupt Steering */

      check_status(naibrd_DT_SetGroupInterruptSteering(userInput_DTInt.cardIndex, userInput_DTInt.moduleNumber, 1, NAI_DT_STATUS_BIT_LATCHED,         steering));
      check_status(naibrd_DT_SetGroupInterruptSteering(userInput_DTInt.cardIndex, userInput_DTInt.moduleNumber, 1, NAI_DT_STATUS_LO_HI_TRANS_LATCHED, steering));
      check_status(naibrd_DT_SetGroupInterruptSteering(userInput_DTInt.cardIndex, userInput_DTInt.moduleNumber, 1, NAI_DT_STATUS_HI_LO_TRANS_LATCHED, steering));
      check_status(naibrd_DT_SetGroupInterruptSteering(userInput_DTInt.cardIndex, userInput_DTInt.moduleNumber, 1, NAI_DT_STATUS_OVERCURRENT_LATCHED, steering));
}
Full Source — DT_Interrupt_Common.c (SSK 1.x)
/**************************************************************************************************************/
/**
<summary>
The DT_Interrupt_Common file contains routines that used by the Discrete Interrupt Sample Applications.
</summary>
*/
/**************************************************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <stdint.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"

/* NAI Board Library include files */
#include "nai.h"
#include "naibrd.h"
#include "functions/naibrd_dt.h"
#include "naibrd_ether.h"
#include "advanced/nai_ether_adv.h"
#if defined (WIN32)
 #include "../../src/maps/nai_map_dt.h"
#else
 #include "maps/nai_map_dt.h"
#endif

#if defined (__VXWORKS__)
 #include "naibrd_config.h"
#endif

#include "DT_Interrupt_Common.h"

UserInput_DTInt userInput_DTInt;
BoardState_DTInt boardState_DTInt;

/***********************/
/* Function Prototypes */
/***********************/
bool_t GetDTLatchStatusTriggerMode();

/**************************************************************************************************************/
/*****                               Functions Invoked Externally                                         *****/
/**************************************************************************************************************/

/**************************************************************************************************************/
/**
<summary>
DisplayMessage_DTInterrupt handles displaying the messages associated with the msgId passed in.
</summary>
*/
/**************************************************************************************************************/
void DisplayMessage_DTInterrupt(int32_t msgId)
{
   switch (msgId)
   {
      case (int32_t)MSG_BANNER_DT_INT:
      {
         printf("\n********************************************************************************");
         printf("\n******                      DISCRETE INTERRUPT                            ******");
         printf("\nAn interrupt will occur when a Discrete module generates any of the following:  ");
         printf("\nFault, Low-to-High Transition, High-to-Low Transition, or Overcurrent           ");
         printf("\n********************************************************************************");
      }
      break;

      case (int32_t)MSG_USER_TRIGGER_DT_INT:
      {
         printf("\nPress \"Q\" to quit the application.\nPlease trigger Discrete interrupt (Fault, Lo-Hi Transition, Hi-Lo Transition or Overcurrent ...");
      }
      break;

      case (int32_t)MSG_USER_CLEAR_DT_INT:
      {
         printf("Press \"C\" to clear interrupts... ");
      }
      break;
   }
}

/**************************************************************************************************************/
/**
<summary>
PromptUserInput_DTInterrupt handles prompting the user for the card index, module number and latched status
trigger mode.
</summary>
*/
/**************************************************************************************************************/
bool_t PromptUserInput_DTInterrupt(bool_t *bValid)
{
   bool_t bQuit;   int32_t cardIndex = -1, module = 1;
   int32_t MaxModule, MaxChannel;
   uint32_t ModuleID;
   uint32_t ModuleVer;
   uint32_t ModuleRev;
   uint32_t ModInfo_Special;

   /* Initialize the bValid return state */
   *bValid = FALSE;

   /* Query user to select card number and module number */
   bQuit = naiapp_query_CardIndex(naiapp_GetBoardCnt(), 0, &cardIndex);
   if (!bQuit)
   {
      userInput_DTInt.cardIndex = cardIndex;
      check_status(naibrd_GetModuleCount(cardIndex, &MaxModule));
      bQuit = naiapp_query_ModuleNumber(MaxModule, 1, &module);
      if (!bQuit)
      {
         bQuit = GetDTLatchStatusTriggerMode();
         if (!bQuit)
         {
            userInput_DTInt.moduleNumber = module;
            naibrd_GetModuleInfo(cardIndex, module, &ModuleID, &ModuleVer, &ModuleRev, &ModInfo_Special);
            MaxChannel = naibrd_DT_GetChannelCount(ModuleID);

            if (MaxChannel == 0)
               printf(" *** Module selection not recognized as DT module. ***\n\n");
            else
            {
               boardState_DTInt.cardIndex = userInput_DTInt.cardIndex;
               boardState_DTInt.moduleNumber = userInput_DTInt.moduleNumber;
               boardState_DTInt.channel = 1;
               userInput_DTInt.channel = 1;
               boardState_DTInt.maxChannels = MaxChannel;
               *bValid = TRUE;
               printf("\nDiscrete Module Info: CardIndex=%d, ModuleNumber=%d, MaxChannels=%d",userInput_DTInt.cardIndex, userInput_DTInt.moduleNumber, MaxChannel);
            }
         }
      }
   }
   return bQuit;
}

/**************************************************************************************************************/
/**
<summary>
ConfigDTInterrupt handles disabling the discrete interrupts, clearing any latched statuses, setting the
interrupt vector (NAI_DT_INTERRUPT_VECTOR), and latch status mode (Edge/Level). The interrupt steering
configuration is configured based on the interruptCommType that is passed in.
</summary>
*/
/**************************************************************************************************************/
void ConfigDTInterrupt(interruptCommType_t interruptCommType)
{
   uint32_t rawstatus = 0;
   int32_t chan;
   uint8_t interrupt_t;

   /* Disable Interrupts */
   EnableDTInterrupt(FALSE);

   /* Clear the Interrupt Status (Read the status and write back "1" to statuses which are set to clear the status) */
   check_status(naibrd_DT_GetGroupStatusRaw(userInput_DTInt.cardIndex, userInput_DTInt.moduleNumber, 1, NAI_DT_STATUS_BIT_LATCHED, &rawstatus));
   check_status(naibrd_DT_ClearGroupStatusRaw(userInput_DTInt.cardIndex, userInput_DTInt.moduleNumber, 1, NAI_DT_STATUS_BIT_LATCHED, rawstatus));
   check_status(naibrd_DT_GetGroupStatusRaw(userInput_DTInt.cardIndex, userInput_DTInt.moduleNumber, 1, NAI_DT_STATUS_LO_HI_TRANS_LATCHED, &rawstatus));
   check_status(naibrd_DT_ClearGroupStatusRaw(userInput_DTInt.cardIndex, userInput_DTInt.moduleNumber, 1, NAI_DT_STATUS_LO_HI_TRANS_LATCHED, rawstatus));
   check_status(naibrd_DT_GetGroupStatusRaw(userInput_DTInt.cardIndex, userInput_DTInt.moduleNumber, 1, NAI_DT_STATUS_HI_LO_TRANS_LATCHED, &rawstatus));
   check_status(naibrd_DT_ClearGroupStatusRaw(userInput_DTInt.cardIndex, userInput_DTInt.moduleNumber, 1, NAI_DT_STATUS_HI_LO_TRANS_LATCHED, rawstatus));
   check_status(naibrd_DT_GetGroupStatusRaw(userInput_DTInt.cardIndex, userInput_DTInt.moduleNumber, 1, NAI_DT_STATUS_OVERCURRENT_LATCHED, &rawstatus));
   check_status(naibrd_DT_ClearGroupStatusRaw(userInput_DTInt.cardIndex, userInput_DTInt.moduleNumber, 1, NAI_DT_STATUS_OVERCURRENT_LATCHED, rawstatus));

   /* Setup the Interrupt Vector - map to the same vector */
   check_status(naibrd_DT_SetGroupInterruptVector(userInput_DTInt.cardIndex, userInput_DTInt.moduleNumber, 1, NAI_DT_STATUS_BIT_LATCHED, NAI_DT_INTERRUPT_VECTOR));
   check_status(naibrd_DT_SetGroupInterruptVector(userInput_DTInt.cardIndex, userInput_DTInt.moduleNumber, 1, NAI_DT_STATUS_LO_HI_TRANS_LATCHED, NAI_DT_INTERRUPT_VECTOR));
   check_status(naibrd_DT_SetGroupInterruptVector(userInput_DTInt.cardIndex, userInput_DTInt.moduleNumber, 1, NAI_DT_STATUS_HI_LO_TRANS_LATCHED, NAI_DT_INTERRUPT_VECTOR));
   check_status(naibrd_DT_SetGroupInterruptVector(userInput_DTInt.cardIndex, userInput_DTInt.moduleNumber, 1, NAI_DT_STATUS_OVERCURRENT_LATCHED, NAI_DT_INTERRUPT_VECTOR));

   /* Setup the Latched Status Mode */
   interrupt_t = (uint8_t)userInput_DTInt.intTriggerType;
   for (chan = 1; chan <= boardState_DTInt.maxChannels; chan++)
   {
      check_status(naibrd_DT_SetEdgeLevelInterrupt(userInput_DTInt.cardIndex, userInput_DTInt.moduleNumber, chan, NAI_DT_STATUS_BIT_LATCHED, interrupt_t));
      check_status(naibrd_DT_SetEdgeLevelInterrupt(userInput_DTInt.cardIndex, userInput_DTInt.moduleNumber, chan, NAI_DT_STATUS_LO_HI_TRANS_LATCHED, interrupt_t));
      check_status(naibrd_DT_SetEdgeLevelInterrupt(userInput_DTInt.cardIndex, userInput_DTInt.moduleNumber, chan, NAI_DT_STATUS_HI_LO_TRANS_LATCHED, interrupt_t));
      check_status(naibrd_DT_SetEdgeLevelInterrupt(userInput_DTInt.cardIndex, userInput_DTInt.moduleNumber, chan, NAI_DT_STATUS_OVERCURRENT_LATCHED, interrupt_t));
   }

   /* Setup the Interrupt Steering */
   switch (interruptCommType)
   {
   case ETHERNET_INT:
      check_status(naibrd_DT_SetGroupInterruptSteering(userInput_DTInt.cardIndex, userInput_DTInt.moduleNumber, 1, NAI_DT_STATUS_BIT_LATCHED, NAIBRD_INT_STEERING_ON_BOARD_1));
      check_status(naibrd_DT_SetGroupInterruptSteering(userInput_DTInt.cardIndex, userInput_DTInt.moduleNumber, 1, NAI_DT_STATUS_LO_HI_TRANS_LATCHED, NAIBRD_INT_STEERING_ON_BOARD_1));
      check_status(naibrd_DT_SetGroupInterruptSteering(userInput_DTInt.cardIndex, userInput_DTInt.moduleNumber, 1, NAI_DT_STATUS_HI_LO_TRANS_LATCHED, NAIBRD_INT_STEERING_ON_BOARD_1));
      check_status(naibrd_DT_SetGroupInterruptSteering(userInput_DTInt.cardIndex, userInput_DTInt.moduleNumber, 1, NAI_DT_STATUS_OVERCURRENT_LATCHED, NAIBRD_INT_STEERING_ON_BOARD_1));
      break;

      case MASTER_PCIBUS_OFFBOARD_INT:
      check_status(naibrd_DT_SetGroupInterruptSteering(userInput_DTInt.cardIndex, userInput_DTInt.moduleNumber, 1, NAI_DT_STATUS_BIT_LATCHED, NAIBRD_INT_STEERING_CPCI_APP));
      check_status(naibrd_DT_SetGroupInterruptSteering(userInput_DTInt.cardIndex, userInput_DTInt.moduleNumber, 1, NAI_DT_STATUS_LO_HI_TRANS_LATCHED, NAIBRD_INT_STEERING_CPCI_APP));
      check_status(naibrd_DT_SetGroupInterruptSteering(userInput_DTInt.cardIndex, userInput_DTInt.moduleNumber, 1, NAI_DT_STATUS_HI_LO_TRANS_LATCHED, NAIBRD_INT_STEERING_CPCI_APP));
      check_status(naibrd_DT_SetGroupInterruptSteering(userInput_DTInt.cardIndex, userInput_DTInt.moduleNumber, 1, NAI_DT_STATUS_OVERCURRENT_LATCHED, NAIBRD_INT_STEERING_CPCI_APP));
      break;

      case MASTER_PCIE_BUS_OFFBOARD_INT:
      check_status(naibrd_DT_SetGroupInterruptSteering(userInput_DTInt.cardIndex, userInput_DTInt.moduleNumber, 1, NAI_DT_STATUS_BIT_LATCHED, NAIBRD_INT_STEERING_PCIE_APP));
      check_status(naibrd_DT_SetGroupInterruptSteering(userInput_DTInt.cardIndex, userInput_DTInt.moduleNumber, 1, NAI_DT_STATUS_LO_HI_TRANS_LATCHED, NAIBRD_INT_STEERING_PCIE_APP));
      check_status(naibrd_DT_SetGroupInterruptSteering(userInput_DTInt.cardIndex, userInput_DTInt.moduleNumber, 1, NAI_DT_STATUS_HI_LO_TRANS_LATCHED, NAIBRD_INT_STEERING_PCIE_APP));
      check_status(naibrd_DT_SetGroupInterruptSteering(userInput_DTInt.cardIndex, userInput_DTInt.moduleNumber, 1, NAI_DT_STATUS_OVERCURRENT_LATCHED, NAIBRD_INT_STEERING_PCIE_APP));
      break;

      case ONBOARD_INT:
#if defined (PPC_XILINX)
      check_status(naibrd_DT_SetGroupInterruptSteering(userInput_DTInt.cardIndex, userInput_DTInt.moduleNumber, 1, NAI_DT_STATUS_BIT_LATCHED, NAIBRD_INT_STEERING_PCIE_APP));
      check_status(naibrd_DT_SetGroupInterruptSteering(userInput_DTInt.cardIndex, userInput_DTInt.moduleNumber, 1, NAI_DT_STATUS_LO_HI_TRANS_LATCHED, NAIBRD_INT_STEERING_PCIE_APP));
      check_status(naibrd_DT_SetGroupInterruptSteering(userInput_DTInt.cardIndex, userInput_DTInt.moduleNumber, 1, NAI_DT_STATUS_HI_LO_TRANS_LATCHED, NAIBRD_INT_STEERING_PCIE_APP));
      check_status(naibrd_DT_SetGroupInterruptSteering(userInput_DTInt.cardIndex, userInput_DTInt.moduleNumber, 1, NAI_DT_STATUS_OVERCURRENT_LATCHED, NAIBRD_INT_STEERING_PCIE_APP));
#else
      check_status(naibrd_DT_SetGroupInterruptSteering(userInput_DTInt.cardIndex, userInput_DTInt.moduleNumber, 1, NAI_DT_STATUS_BIT_LATCHED, NAIBRD_INT_STEERING_ON_BOARD_0));
      check_status(naibrd_DT_SetGroupInterruptSteering(userInput_DTInt.cardIndex, userInput_DTInt.moduleNumber, 1, NAI_DT_STATUS_LO_HI_TRANS_LATCHED, NAIBRD_INT_STEERING_ON_BOARD_0));
      check_status(naibrd_DT_SetGroupInterruptSteering(userInput_DTInt.cardIndex, userInput_DTInt.moduleNumber, 1, NAI_DT_STATUS_HI_LO_TRANS_LATCHED, NAIBRD_INT_STEERING_ON_BOARD_0));
      check_status(naibrd_DT_SetGroupInterruptSteering(userInput_DTInt.cardIndex, userInput_DTInt.moduleNumber, 1, NAI_DT_STATUS_OVERCURRENT_LATCHED, NAIBRD_INT_STEERING_ON_BOARD_0));
#endif
      break;
   }
}

/**************************************************************************************************************/
/**
<summary>
EnableDTInterrupt handles enabling/disabling the discrete interrupts.
</summary>
*/
/**************************************************************************************************************/
void EnableDTInterrupt(bool_t enabled)
{
   int32_t chan;
   for (chan = 1; chan <= boardState_DTInt.maxChannels; chan++)
   {
      check_status(naibrd_DT_SetInterruptEnable(userInput_DTInt.cardIndex, userInput_DTInt.moduleNumber, chan, NAI_DT_STATUS_BIT_LATCHED, enabled));
      check_status(naibrd_DT_SetInterruptEnable(userInput_DTInt.cardIndex, userInput_DTInt.moduleNumber, chan, NAI_DT_STATUS_OVERCURRENT_LATCHED, enabled));
      check_status(naibrd_DT_SetInterruptEnable(userInput_DTInt.cardIndex, userInput_DTInt.moduleNumber, chan, NAI_DT_STATUS_LO_HI_TRANS_LATCHED, enabled));
      check_status(naibrd_DT_SetInterruptEnable(userInput_DTInt.cardIndex, userInput_DTInt.moduleNumber, chan, NAI_DT_STATUS_HI_LO_TRANS_LATCHED, enabled));
   }
}

/**************************************************************************************************************/
/*****                                  Internal Functions                                                *****/
/**************************************************************************************************************/
/**************************************************************************************************************/
/**
<summary>
GetDTLatchStatusTriggerMode handles prompting the user for the trigger mode for the latched status register
(Edge Triggered or Level Triggered).
</summary>
*/
/**************************************************************************************************************/
bool_t GetDTLatchStatusTriggerMode()
{
   bool_t bQuit;
   uint32_t temp;
   int8_t inputBuffer[80];
   int32_t inputResponseCnt;

   printf("\nEnter Latched Status Trigger Mode (Edge=0, Level=1) (Default=0): ");
   bQuit = naiapp_query_ForQuitResponse(sizeof(inputBuffer), NAI_QUIT_CHAR, inputBuffer, &inputResponseCnt);
   if(!bQuit)
   {
      if(inputResponseCnt > 0)
      {
         temp = (int32_t)atol((const char*)inputBuffer);

         if( temp == 0 || temp == 1)
         {
            userInput_DTInt.intTriggerType = temp;
         }
         else
         {
            printf("ERROR: Invalid Interrupt Trigger Mode.\n");
         }
      }
      else
         userInput_DTInt.intTriggerType = 0;
   }
   return(bQuit);
}

Help Bot

X