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

SER Interrupts

SER Interrupts Sample Application (SSK 1.x)

Overview

The SER Interrupts sample application demonstrates how to configure and handle hardware interrupts on Serial (SER) modules using the NAI Software Support Kit (SSK 1.x). The sample configures all available serial channels for interrupt monitoring, assigns a unique interrupt vector to each channel, and enters a continuous loop that detects and reports interrupt events. It supports two interrupt delivery modes controlled by a compile-time flag: ISR mode (hardware interrupt with an installed callback) and polling mode (software polling of latched status registers). Both modes use the same underlying module configuration.

This sample supports the following SER module types: P8, PC, PD, Px, KB, SC, and CMH (combination module with serial channels).

Serial modules can generate interrupts on several latched status conditions:

  • Transmit Complete (NAI_SER_GEN5_INT_TXCOMPLETE) — the channel has finished transmitting all data in its transmit FIFO.

  • Receive Data Available — data has arrived in the channel’s receive FIFO.

  • BIT (Built-In Test) — the module’s self-test has detected a hardware fault on a channel.

  • Other serial events — protocol-specific status changes such as framing errors, parity errors, or break detection.

As shipped, the sample monitors only NAI_SER_GEN5_INT_TXCOMPLETE (transmit complete) on all channels. To monitor additional status conditions, modify the NAI_SER_GEN5_INT_TXCOMPLETE bitmask in Setup_SER_Interrupts() and ClearInterrupt() to include the status bits you want to track.

For serial loopback testing and basic async configuration, see the SER ASync LOOPBACK sample application guide. For an overview of serial receive data handling across multiple channels, see the SER Recv Summary sample application guide. For background on interrupt concepts — including edge vs. level triggering, interrupt vector numbering, and steering architecture — see the Interrupts API Guide.

Prerequisites

Before running this sample, make sure you have:

  • An NAI board with a serial module installed (P8, PC, PD, Px, KB, SC, or CMH).

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

  • To use ISR mode: compile with the RUN_ISR preprocessor macro defined.

How to Run

Launch the SER_Interrupts executable from your build output directory. On startup the application looks for a configuration file (default_SerInterrupts.txt). On the first run, this file will not exist — the application will present an interactive board menu where you configure a board connection, card index, and module slot. You can save this configuration so that subsequent runs skip the menu and connect automatically. Once connected, the application prompts you to select a card and module, configures transmit complete interrupt monitoring on all serial channels, and enters a continuous wait loop, printing each interrupt event as it is detected.

To select interrupt delivery mode, rebuild with or without the RUN_ISR preprocessor define:

  • RUN_ISR defined — the application installs a hardware ISR via naibrd_InstallISR(). The ISR fires when the configured status condition occurs, and the main loop processes the event.

  • RUN_ISR not defined (default) — the application polls the latched status register for each channel on each loop iteration using naibrd_SER_GetChannelStatus(). No ISR is installed.

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

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

  1. Call naiapp_RunBoardMenu() to load a saved configuration file or present the interactive board menu. The configuration file (default_SerInterrupts.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. Query the user for card index with naiapp_query_CardIndex().

  3. Query the user for module number with naiapp_query_ModuleNumber().

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

  5. Call Run_SER_Interrupts() to begin interrupt configuration on all channels.

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

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

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

   return 0;
}
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 serial module. Use the board menu to verify which slots are populated.

Program Structure

The SER Interrupts sample is contained in a single source file (SER_Interrupts.c). All configuration, ISR, polling, and event handling logic lives in one file.

Entry Point

main() (or SER_Interrupt_Sample() on VxWorks) handles the board connection and module selection loop described above, then calls Run_SER_Interrupts().

Global State

The application uses global volatile variables to communicate between the ISR (or polling function) and the main processing loop:

volatile uint32_t irqSERCount = 0;
volatile static uint8_t isrLock = 0;
volatile static uint32_t receivedVector = 0;
volatile static nai_ser_status_t receivedChannelStatus = 0;
volatile static nai_ser_status_type_t receivedType = NAI_SER_STATUS_GEN5_ENUM_COUNT;
volatile static interrupt_status_type_t interruptStatus = INTERRUPT_WAITING;
  • irqSERCount — running count of interrupts received.

  • isrLock — simple lock flag set to 1 while the ISR is updating shared state, preventing the main loop from reading partial data.

  • receivedVector — the interrupt vector reported by the most recent event.

  • receivedChannelStatus — the latched channel status register value read after the interrupt.

  • receivedType — the nai_ser_status_type_t value identifying which channel’s latched status register to read.

  • interruptStatus — tracks the current interrupt state: INTERRUPT_WAITING, INTERRUPT_RECEIVED, or INTERRUPT_ERROR_UNEXPECTED_VECTOR.

Per-Channel Interrupt Vectors and Status Types

Each serial channel is assigned a unique interrupt vector and a corresponding latched status type. The sample defines these as parallel arrays:

#define SER_CHANNEL1_INTERRUPT_VECTOR 0x000000A1u
#define SER_CHANNEL2_INTERRUPT_VECTOR 0x000000A2u
/* ... through channel 8 ... */
#define SER_CHANNEL8_INTERRUPT_VECTOR 0x000000A8u

const static nai_ser_status_type_t type[] = {
   NAI_SER_STATUS_CHANNEL1_LATCHED, NAI_SER_STATUS_CHANNEL2_LATCHED,
   NAI_SER_STATUS_CHANNEL3_LATCHED, NAI_SER_STATUS_CHANNEL4_LATCHED,
   NAI_SER_STATUS_CHANNEL5_LATCHED, NAI_SER_STATUS_CHANNEL6_LATCHED,
   NAI_SER_STATUS_CHANNEL7_LATCHED, NAI_SER_STATUS_CHANNEL8_LATCHED
};

const static uint32_t vector[] = {
   SER_CHANNEL1_INTERRUPT_VECTOR, SER_CHANNEL2_INTERRUPT_VECTOR,
   SER_CHANNEL3_INTERRUPT_VECTOR, SER_CHANNEL4_INTERRUPT_VECTOR,
   SER_CHANNEL5_INTERRUPT_VECTOR, SER_CHANNEL6_INTERRUPT_VECTOR,
   SER_CHANNEL7_INTERRUPT_VECTOR, SER_CHANNEL8_INTERRUPT_VECTOR
};

Each channel gets its own latched status type (e.g., NAI_SER_STATUS_CHANNEL1_LATCHED) and a unique vector (e.g., 0xA1). When an interrupt fires, the ISR uses the vector to determine which channel triggered the event. The type[] array maps that channel back to the correct status register for reading and clearing.

In your own application, assign unique vectors to each channel so that you can identify the interrupt source without reading every channel’s status register. The vector values (0xA1 through 0xA8) are arbitrary — choose any values that do not conflict with other modules on your board.

99ARM2-SF2 Channel Offset

The FIRST_SER_CHANNEL_IDX constant controls which channel index the application starts from:

/* For 99ARM2-module 3 (SF2), The first 5 channels are GPIO. If running this code
   on that module, then set FIRST_SER_CHANNEL_IDX to 5, otherwise set it to 0. */
#define FIRST_SER_CHANNEL_IDX    0

On the 99ARM2 platform’s SF2 module, the first five channels are GPIO, not serial. If you are running on that module, set FIRST_SER_CHANNEL_IDX to 5 to skip the GPIO channels. For all other modules, leave this at 0.

Interrupt Configuration

The Run_SER_Interrupts() function iterates over all serial channels, clears any stale status, and configures each channel for interrupt monitoring. After configuration, it installs the ISR (in ISR mode) and enters the event processing loop.

Step 1: Clear Stale Status

Before enabling interrupts, clear any latched status from a previous run to prevent spurious interrupts on startup:

for (chanIndex = FIRST_SER_CHANNEL_IDX; chanIndex < channelCount; chanIndex++)
{
   /* Make sure there are no pending interrupts before they are enabled. */
   ClearInterrupt(cardIndex, modNum, type[chanIndex]);

   /* Setup Interrupts */
   Setup_SER_Interrupts(cardIndex, modNum, type[chanIndex], vector[chanIndex]);
}

ClearInterrupt() writes to the latched status register to clear the transmit complete bit and resets all application-level tracking variables:

static void ClearInterrupt(int32_t cardIndex, int32_t modNum,
   nai_ser_status_type_t type)
{
   check_status(naibrd_SER_ClearChannelStatus(cardIndex, modNum, type,
      NAI_SER_GEN5_INT_TXCOMPLETE));

   receivedVector = 0xFFFFFFFF;
   receivedType = NAI_SER_STATUS_GEN5_ENUM_COUNT;
   receivedChannelStatus = 0;
   irqSERCount = 0;
   interruptStatus = INTERRUPT_WAITING;
}

In your own application, always call naibrd_SER_ClearChannelStatus() before enabling interrupts. If you skip this step, a latched status bit from a previous session may immediately trigger an interrupt as soon as the enable is set.

Step 2: Configure Interrupt Parameters

The Setup_SER_Interrupts() function performs the complete interrupt configuration for a single channel in four API calls:

void Setup_SER_Interrupts(int32_t cardIndex, int32_t modNum,
   nai_ser_status_type_t type, uint32_t vector)
{
   check_status(naibrd_SER_SetInterruptEdgeLevel(cardIndex, modNum, type, 0));
   check_status(naibrd_SER_SetInterruptVector(cardIndex, modNum, type, vector));
   check_status(naibrd_SER_SetInterruptSteering(cardIndex, modNum, type,
      NAIBRD_INT_STEERING_CPCI_APP));
   check_status(naibrd_SER_SetInterruptEnable(cardIndex, modNum, type,
      NAI_SER_GEN5_INT_TXCOMPLETE));
}

Each call configures one aspect of the interrupt:

Set Edge/Level Trigger

naibrd_SER_SetInterruptEdgeLevel(cardIndex, modNum, type, 0);

The fourth parameter selects the trigger mode: 0 for edge-triggered, 1 for level-triggered. Edge triggering fires once when the status condition transitions from inactive to active. Level triggering fires continuously while the condition remains active. The sample uses edge triggering (0), which is appropriate for event notification — you want to know when a transmit completes, not be continuously interrupted while the FIFO is empty.

Set Interrupt Vector

naibrd_SER_SetInterruptVector(cardIndex, modNum, type, vector);

Assigns the interrupt vector for the given channel’s status type. The vector is passed to the ISR when the interrupt fires, allowing the ISR to identify which channel triggered the event. Each channel should have a unique vector value.

Set Interrupt Steering

naibrd_SER_SetInterruptSteering(cardIndex, modNum, type,
   NAIBRD_INT_STEERING_CPCI_APP);

Configures how the interrupt signal is routed to your application. The sample steers interrupts to the CompactPCI backplane host (NAIBRD_INT_STEERING_CPCI_APP). Modify the steering parameter to match your hardware configuration:

  • NAIBRD_INT_STEERING_ON_BOARD_0 — handled locally on the board’s processor.

  • NAIBRD_INT_STEERING_CPCI_APP — routed to the CompactPCI backplane host.

  • NAIBRD_INT_STEERING_PCIE_APP — routed to the PCIe host.

If you change the steering, update the IRQ ID in the naibrd_InstallISR() call accordingly.

Enable the Interrupt

naibrd_SER_SetInterruptEnable(cardIndex, modNum, type,
   NAI_SER_GEN5_INT_TXCOMPLETE);

Enables the transmit complete interrupt on the specified channel. The second parameter is a bitmask of status conditions to enable. To monitor additional conditions (receive data available, BIT, framing error), OR the corresponding bits together in this parameter. Consult your module’s manual for the full list of available interrupt status bits.

Step 3: Install ISR (ISR Mode Only)

After configuring all channels, the application installs the ISR when RUN_ISR is defined:

#if defined (RUN_ISR)
check_status(naibrd_InstallISR(cardIndex, NAIBRD_IRQ_ID_DONT_CARE,
   (nai_isr_t)MySERIsr, NULL));
#endif

naibrd_InstallISR() registers the MySERIsr callback to handle hardware interrupts from the board. NAIBRD_IRQ_ID_DONT_CARE allows the library to select the appropriate IRQ line automatically. If you need to target a specific IRQ line (e.g., NAIBRD_IRQ_ID_ON_BOARD_0 for on-board processor steering), specify it explicitly.

Important

Common Errors

  • NAI_ERROR_NOT_SUPPORTED — the selected module does not support the specified status type. Verify you are using a supported serial module (P8, PC, PD, Px, KB, SC, or CMH) and that the status type is valid for your module’s firmware revision.

  • No interrupts fire after configuration — ensure you cleared any latched status from a previous run before enabling interrupts. Also verify that interrupt steering matches your hardware bus configuration and that the IRQ ID in naibrd_InstallISR() is compatible with the steering destination.

  • Wrong steering for your setup — the sample uses NAIBRD_INT_STEERING_CPCI_APP. If you are running on the on-board processor, change to NAIBRD_INT_STEERING_ON_BOARD_0. If you are using PCIe, change to NAIBRD_INT_STEERING_PCIE_APP.

ISR Mechanism

The sample supports two interrupt delivery modes, selected at compile time by the RUN_ISR preprocessor define.

ISR Mode (RUN_ISR Defined)

When RUN_ISR is defined, the MySERIsr callback fires each time the hardware generates an interrupt. The ISR is lightweight — it increments the count, sets the lock, identifies the channel from the vector, and signals the main loop:

void MySERIsr(void* param, uint32_t vector)
{
   irqSERCount++;
   isrLock = 1;

   receivedVector = vector;
   switch (vector)
   {
      case SER_CHANNEL1_INTERRUPT_VECTOR:
         receivedType = type[0];
         interruptStatus = INTERRUPT_RECEIVED;
         break;
      case SER_CHANNEL2_INTERRUPT_VECTOR:
         receivedType = type[1];
         interruptStatus = INTERRUPT_RECEIVED;
         break;
      /* ... cases for channels 3 through 8 ... */
      default:
         receivedType = NAI_SER_STATUS_GEN5_ENUM_COUNT;
         receivedChannelStatus = 0;
         interruptStatus = INTERRUPT_ERROR_UNEXPECTED_VECTOR;
         break;
   }
   isrLock = 0;
}

The switch statement matches the received vector against the known per-channel vectors (0xA1 through 0xA8). When a match is found, the ISR records which channel’s status type triggered the event and sets interruptStatus to INTERRUPT_RECEIVED. An unrecognized vector sets INTERRUPT_ERROR_UNEXPECTED_VECTOR — this typically means another module on the board is generating interrupts with a conflicting vector value.

The isrLock flag prevents the main loop from reading shared state while the ISR is updating it. The main loop checks isrLock == 0 before processing events.

On VxWorks, the ISR signature differs slightly. The ISR must retrieve the vector manually and clear the interrupt at the hardware level:

#if defined (__VXWORKS__)
void MySERIsr(uint32_t nVector)
{
   irqSERCount++;
   isrLock = 1;
   unsigned int vector = nai_Onboard_GetInterruptVector();
   nai_Onboard_ClearInterrupt();
   /* ... same switch logic ... */
   isrLock = 0;
}
#endif

Polling Mode (RUN_ISR Not Defined)

When RUN_ISR is not defined, no ISR is installed. Instead, the main loop calls CheckForStatusChange() on each iteration to poll the latched status register for each channel:

static void CheckForStatusChange(int32_t cardIndex, int32_t modNum,
   int32_t channelCount)
{
   uint32_t channelStatus;
   static int32_t chanIndex = 0;

   do
   {
      check_status(naibrd_SER_GetChannelStatus(cardIndex, modNum,
         type[chanIndex], &channelStatus));
      if (0 != (channelStatus & NAI_SER_GEN5_INT_TXCOMPLETE))
      {
         irqSERCount++;
         receivedVector = vector[chanIndex];
         receivedType = type[chanIndex];
         receivedChannelStatus = channelStatus;
         interruptStatus = INTERRUPT_RECEIVED;
      }
      chanIndex++;
   } while ((chanIndex < channelCount) && (INTERRUPT_RECEIVED != interruptStatus));

   if (chanIndex >= channelCount)
   {
      chanIndex = 0;
   }
}

naibrd_SER_GetChannelStatus() reads the latched status register for one channel at a time. The function uses a static chanIndex to track which channel to poll next, allowing it to round-robin across all channels across successive calls. When it detects a channel with the transmit complete bit set, it records the event and returns immediately so the main loop can process it before checking the remaining channels.

Polling mode is useful for development and debugging because it does not require ISR installation or specific bus interrupt routing. However, it introduces latency proportional to the polling interval and the number of channels. For production systems that require prompt interrupt response, use ISR mode.

Important

Common Errors

  • ISR never fires — verify that interrupt steering matches your hardware bus. The sample uses NAIBRD_INT_STEERING_CPCI_APP (CompactPCI host). If you are running on the on-board processor, change steering to NAIBRD_INT_STEERING_ON_BOARD_0.

  • Unexpected vector in ISR — the ISR received a vector that does not match any channel vector (0xA1 through 0xA8). This typically means another module on the same board is generating interrupts with a conflicting vector. Assign unique vectors per module and per channel.

  • Polling detects no events — the transmit complete condition has not occurred. Send data on the serial channel to trigger a transmit complete event. Verify that the interrupt enable was set successfully.

Event Processing and Status Clearing

The main loop in Run_SER_Interrupts() continuously checks the interruptStatus flag and processes events as they arrive. The loop only processes events when isrLock is 0, ensuring the ISR has finished updating shared state:

do
{
#if !defined (RUN_ISR)
   CheckForStatusChange(cardIndex, modNum, channelCount);
#endif

   if (isrLock == 0)
   {
      switch (interruptStatus)
      {
         case INTERRUPT_RECEIVED:
         {
#if defined (RUN_ISR)
            check_status(naibrd_SER_GetChannelStatus(cardIndex, modNum,
               receivedType, &channelStatus));
            receivedChannelStatus = channelStatus;
#endif
            printf("Interrupt Received: Vector- 0x%X, ChannelStatus- 0x%X, count- %u\n",
               receivedVector, receivedChannelStatus, irqSERCount);

            ClearInterrupt(cardIndex, modNum, receivedType);
            break;
         }
         case INTERRUPT_ERROR_UNEXPECTED_VECTOR:
         {
            printf("Unexpected Interrupt Received: Vector- 0x%X, count- %u\n",
               receivedVector, irqSERCount);
            break;
         }
         case INTERRUPT_WAITING:
            break;
         default:
            break;
      }
   }
} while (bContinue);

When INTERRUPT_RECEIVED is detected, the loop:

  1. In ISR mode, reads the latched channel status register with naibrd_SER_GetChannelStatus() to determine which status bits caused the interrupt. In polling mode, the status was already read by CheckForStatusChange().

  2. Prints the interrupt vector, channel status bitmask, and running count.

  3. Calls ClearInterrupt() to clear the latched status and reset application variables, allowing the next interrupt to be captured.

When INTERRUPT_ERROR_UNEXPECTED_VECTOR is detected, the loop prints the unexpected vector value for diagnostic purposes. This condition does not clear the interrupt automatically — investigate the vector conflict before continuing.

Clearing Latched Status

Subsequent interrupts will not fire until the previous latched status has been cleared. In your own application, you must call naibrd_SER_ClearChannelStatus() after handling each interrupt. Failing to clear the latched status will prevent all subsequent interrupts of the same type on that channel from firing.

Important

Common Errors

  • Only one interrupt is ever received — you forgot to clear the latched status after handling the event. Call naibrd_SER_ClearChannelStatus() after processing each interrupt.

  • Spurious interrupt on startup — latched status from a previous run was not cleared before enabling interrupts. Always clear status before calling naibrd_SER_SetInterruptEnable(). The sample demonstrates this by calling ClearInterrupt() for each channel before Setup_SER_Interrupts().

  • Main loop processes stale data — if the main loop reads shared variables while the ISR is updating them, it may process partial state. The sample uses the isrLock flag to guard against this. In your own code, use appropriate synchronization for your platform.

Troubleshooting Reference

The following table summarizes errors and symptoms covered in preceding sections along with additional diagnostics. Consult your module’s manual for hardware-specific diagnostic procedures.

Error / Symptom Possible Causes Suggested Resolution

No board found

Board not powered or not connected. Configuration file has wrong interface or address.

Verify physical connection and power. Delete the configuration file and re-run to enter settings from scratch.

Connection timeout

Network misconfiguration, firewall blocking traffic, or incorrect bus settings.

Confirm IP settings for Ethernet connections. Check PCI/PCIe bus enumeration for local connections.

Module not present at selected slot

The selected slot does not contain a serial module.

Use the board menu to list populated slots and select the correct module number.

No interrupts fire

Interrupt steering does not match hardware bus. Interrupt enable not set. Transmit complete condition has not occurred.

Verify steering matches your connection type (on-board, cPCI, PCIe). Confirm enable returned success. Send data on the serial channel to trigger the transmit complete condition.

Only one interrupt received

Latched status not cleared after handling.

Call naibrd_SER_ClearChannelStatus() after processing each event.

Spurious interrupt on startup

Stale latched status from a previous run.

Clear all latched status before enabling interrupts. The sample calls ClearInterrupt() on each channel before configuration.

Unexpected vector in ISR

Another module is generating interrupts with a conflicting vector value.

Assign unique vector values per module and per channel. Verify vector assignments across all modules on the board.

NAI_ERROR_NOT_SUPPORTED

Module does not support the specified status type, or firmware revision is too old.

Verify module type is P8, PC, PD, Px, KB, SC, or CMH. Check firmware revision against the module manual requirements.

Polling mode detects nothing

The monitored condition (transmit complete) has not occurred on the hardware.

Transmit data on the serial channel to trigger the condition. Verify the correct status type is configured and that the enable was set.

Wrong channels on 99ARM2-SF2

The first 5 channels on 99ARM2-SF2 module 3 are GPIO, not serial.

Set FIRST_SER_CHANNEL_IDX to 5 when running on this module. For all other modules, leave it at 0.

Interrupt fires but channel status is zero

The latched status was cleared before the main loop could read it, or a race condition between ISR and main loop.

Ensure isrLock synchronization is working. In ISR mode, the main loop reads the status register after the ISR signals the event — verify the receivedType is correct.

Full Source

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

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

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

/* naibrd include files */
#include "nai.h"
#include "naibrd.h"
#include "functions/naibrd_ser.h"
#include "advanced/nai_ether_adv.h"

#define NUM_DATA_TX  8
#define MAX_DATA_RX  20
#define CLEAR_FIFO_TIMEOUT 1000      /* 1 second */

/* For 99ARM2-module 3 (SF2), The first 5 channels are GPIO. If running this code on that module,
    then set FIRST_SER_CHANNEL_IDX to 5, otherwise set it to 0. */
#define FIRST_SER_CHANNEL_IDX    0

#define SER_CHANNEL1_INTERRUPT_VECTOR 0x000000A1u
#define SER_CHANNEL2_INTERRUPT_VECTOR 0x000000A2u
#define SER_CHANNEL3_INTERRUPT_VECTOR 0x000000A3u
#define SER_CHANNEL4_INTERRUPT_VECTOR 0x000000A4u
#define SER_CHANNEL5_INTERRUPT_VECTOR 0x000000A5u
#define SER_CHANNEL6_INTERRUPT_VECTOR 0x000000A6u
#define SER_CHANNEL7_INTERRUPT_VECTOR 0x000000A7u
#define SER_CHANNEL8_INTERRUPT_VECTOR 0x000000A8u

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

typedef enum interrupt_status_type_e
{
   INTERRUPT_WAITING,
   INTERRUPT_RECEIVED,
   INTERRUPT_ERROR_UNEXPECTED_VECTOR
} interrupt_status_type_t;

/* Function prototypes */
void Run_SER_Interrupts(int32_t cardIndex, int32_t modNum, uint32_t modid);
void Setup_SER_Interrupts(int32_t cardIndex, int32_t modNum, nai_ser_status_type_t type,
   uint32_t vector);
#if !defined (RUN_ISR)
static void CheckForStatusChange(int32_t cardIndex, int32_t modNum, int32_t channelCount);
#endif
static void ClearInterrupt(int32_t cardIndex, int32_t module, nai_ser_status_type_t type);

#if defined (__VXWORKS__)
void MySERIsr(uint32_t nVector);
#else
void MySERIsr(void* param, uint32_t vector);
#endif

const static nai_ser_status_type_t type[] = {
   NAI_SER_STATUS_CHANNEL1_LATCHED, NAI_SER_STATUS_CHANNEL2_LATCHED, NAI_SER_STATUS_CHANNEL3_LATCHED,
   NAI_SER_STATUS_CHANNEL4_LATCHED,
   NAI_SER_STATUS_CHANNEL5_LATCHED, NAI_SER_STATUS_CHANNEL6_LATCHED, NAI_SER_STATUS_CHANNEL7_LATCHED,
   NAI_SER_STATUS_CHANNEL8_LATCHED
};
const static uint32_t vector[] = {
   SER_CHANNEL1_INTERRUPT_VECTOR, SER_CHANNEL2_INTERRUPT_VECTOR, SER_CHANNEL3_INTERRUPT_VECTOR,
   SER_CHANNEL4_INTERRUPT_VECTOR,
   SER_CHANNEL5_INTERRUPT_VECTOR, SER_CHANNEL6_INTERRUPT_VECTOR, SER_CHANNEL7_INTERRUPT_VECTOR,
   SER_CHANNEL8_INTERRUPT_VECTOR
};

volatile uint32_t irqSERCount = 0;
volatile static uint8_t isrLock = 0;
volatile static uint32_t receivedVector = 0;
volatile static nai_ser_status_t receivedChannelStatus = 0;
volatile static nai_ser_status_type_t receivedType = NAI_SER_STATUS_GEN5_ENUM_COUNT;
volatile static interrupt_status_type_t interruptStatus = INTERRUPT_WAITING;

/**************************************************************************************************************/
/** \defgroup SERInterrupts Serial Interrupts
The purpose of the Serial Interrupts sample application is to illustrate the methods to call in the naibrd
library to configure a given serial channel status to interrupt on. Interrupts in this example are routed
to the cPCI backplane.
*/
/**************************************************************************************************************/
#if defined (__VXWORKS__)
int32_t SER_Interrupt_Sample(void)
#else
int32_t main(void)
#endif
{
   bool_t stop = FALSE;
   int32_t cardIndex;
   int32_t moduleCnt;
   int32_t module;
   uint32_t moduleID = 0;
   int8_t inputBuffer[80];
   int32_t inputResponseCnt;

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

            /* Query the user for the module number */
            stop = naiapp_query_ModuleNumber(moduleCnt, 1, &module);
            if (stop != TRUE)
            {
               moduleID = naibrd_GetModuleID(cardIndex, module);
               if ((moduleID != 0))
               {
                  Run_SER_Interrupts(cardIndex, module, moduleID);
               }
            }
         }

         printf("\nType Q to quit or Enter key to restart application:\n");
         stop = naiapp_query_ForQuitResponse(sizeof(inputBuffer), NAI_QUIT_CHAR, inputBuffer, &inputResponseCnt);
      }
   }

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

   return 0;
}

/**************************************************************************************************************/
/** \ingroup SERInterrupts
Configures a serial module to interrupt on the Transmit Completed status. The user can choose, via the USE_ISR
preprocessor directive to use interrupts or poll instead.
\param cardIndex (Input) Logical Card Index assigned to connection with the NAI_BOARD (0 - NAI_MAX_CARDS-1).
\param modNum    (Input) Module Number of the module to access (1 - [max modules for board]).
\param modid     (Input) The ID of the module.
*/
/**************************************************************************************************************/
void Run_SER_Interrupts(int32_t cardIndex, int32_t modNum, uint32_t modid)
{
   int32_t channelCount;
   int32_t chanIndex;
   bool_t bContinue = TRUE;
#if defined (RUN_ISR)
   uint32_t channelStatus;
#endif

   channelCount = naibrd_SER_GetChannelCount(modid);

   for (chanIndex = FIRST_SER_CHANNEL_IDX; chanIndex < channelCount; chanIndex++)
   {
      /* Make sure there are no pending interrupts before they are enabled. */
      ClearInterrupt(cardIndex, modNum, type[chanIndex]);

      /* Setup Interrupts */
      Setup_SER_Interrupts(cardIndex, modNum, type[chanIndex], vector[chanIndex]);
   }

#if defined (RUN_ISR)
   /* Install the ISR */
   check_status(naibrd_InstallISR(cardIndex, NAIBRD_IRQ_ID_DONT_CARE, (nai_isr_t)MySERIsr, NULL));
#endif

   printf("\nInterrupts are fired from a NAI-75G5 to NAI-INT2.  Modify the parameters in");
   printf("\nthe function naibrd_InstallISR and naibrd_SER_SetInterruptSteering for other interrupt configuration.");
   printf("\nWaiting for Interrupts .....\n");

   do
   {
#if !defined (RUN_ISR)
      CheckForStatusChange(cardIndex, modNum, channelCount);
#if defined (__VXWORKS__)
      taskDelay(1);
#endif
#endif  /* RUN_ISR */

      if (isrLock == 0)
      {
         switch (interruptStatus)
         {
            case INTERRUPT_RECEIVED:
            {
               /* This indicates that we received the interrupt that was expected. */
#if defined (RUN_ISR)
         /* Read the latched channel status register to see what caused the interrupt. */
               check_status(naibrd_SER_GetChannelStatus(cardIndex, modNum, receivedType, &channelStatus));
               receivedChannelStatus = channelStatus;

#endif /* RUN_ISR */
               printf("Interrupt Received: Vector- 0x%X, ChannelStatus- 0x%X, count- %u\n",
                  receivedVector, receivedChannelStatus, irqSERCount);

               /* Subsequent interrupts will not occur until the previous ones have been cleared. */
               ClearInterrupt(cardIndex, modNum, receivedType);
               break;
            }
            case INTERRUPT_ERROR_UNEXPECTED_VECTOR:
            {
               /* This indicates that we received the interrupt that was not expected. */
               printf("Unexpected Interrupt Received: Vector- 0x%X, count- %u\n",
                  receivedVector, irqSERCount);
               break;
            }
            case INTERRUPT_WAITING:
            {
               /* Nothing to do but wait for an interrupt. */
               break;
            }
            default:
               break;
         }
      }
#if defined (__VXWORKS__)
      taskDelay(1);
#endif
   } while (bContinue);

}

/**************************************************************************************************************/
/** \ingroup SERInterrupts
Configures a serial module to interrupt on the Transmit Complete status.
\param cardIndex (Input) Logical Card Index assigned to connection with the NAI_BOARD (0 - NAI_MAX_CARDS-1).
\param modNum    (Input) Module Number of the module to access (1 - [max modules for board]).
\param type      (Input) Interrupt type (latched or realtime).
\param vector    (Input) Interrupt vector to identify which channel caused the interrupt.
*/
/**************************************************************************************************************/
void Setup_SER_Interrupts(int32_t cardIndex, int32_t modNum, nai_ser_status_type_t type, uint32_t vector)
{
   check_status(naibrd_SER_SetInterruptEdgeLevel(cardIndex, modNum, type, 0));
   check_status(naibrd_SER_SetInterruptVector(cardIndex, modNum, type, vector));
   check_status(naibrd_SER_SetInterruptSteering(cardIndex, modNum, type, NAIBRD_INT_STEERING_CPCI_APP));
   check_status(naibrd_SER_SetInterruptEnable(cardIndex, modNum, type, NAI_SER_GEN5_INT_TXCOMPLETE));
}

#if defined (RUN_ISR)
/*****************************/
/* Interrupt Service Routine */
/*****************************/
#if defined (__VXWORKS__)
void MySERIsr(uint32_t nVector)
#else
void MySERIsr(void* param, uint32_t vector)
#endif
{
   irqSERCount++;
   isrLock = 1;
#if defined (WIN32)
   UNREFERENCED_PARAMETER(param);
#endif

#if defined (__VXWORKS__)
   /* Get the vector that caused the interrupt */
   unsigned int vector = nai_Onboard_GetInterruptVector();
   /* Clear Interrupt */
   nai_Onboard_ClearInterrupt();
#endif

   /* Determine what interrupt was received */
   receivedVector = vector;
   switch (vector)
   {
      case SER_CHANNEL1_INTERRUPT_VECTOR:
         receivedType = type[0];
         interruptStatus = INTERRUPT_RECEIVED;
         break;
      case SER_CHANNEL2_INTERRUPT_VECTOR:
         interruptStatus = INTERRUPT_RECEIVED;
         receivedType = type[1];
         break;
      case SER_CHANNEL3_INTERRUPT_VECTOR:
         receivedType = type[2];
         interruptStatus = INTERRUPT_RECEIVED;
         break;
      case SER_CHANNEL4_INTERRUPT_VECTOR:
         receivedType = type[3];
         interruptStatus = INTERRUPT_RECEIVED;
         break;
      case SER_CHANNEL5_INTERRUPT_VECTOR:
         receivedType = type[4];
         interruptStatus = INTERRUPT_RECEIVED;
         break;
      case SER_CHANNEL6_INTERRUPT_VECTOR:
         interruptStatus = INTERRUPT_RECEIVED;
         receivedType = type[5];
         break;
      case SER_CHANNEL7_INTERRUPT_VECTOR:
         receivedType = type[6];
         interruptStatus = INTERRUPT_RECEIVED;
         break;
      case SER_CHANNEL8_INTERRUPT_VECTOR:
         receivedType = type[7];
         interruptStatus = INTERRUPT_RECEIVED;
         break;
      default:
         receivedType = NAI_SER_STATUS_GEN5_ENUM_COUNT;
         receivedChannelStatus = 0;
         interruptStatus = INTERRUPT_ERROR_UNEXPECTED_VECTOR;
         break;
   }
   isrLock = 0;
}
#else

/**************************************************************************************************************/
/** \ingroup SERInterrupts
Checks each channel (up to channelCount) for the Transmit Complete status. Set's interrupt received flag
if condition has been met. This is function is only called if the user undefined RUN_ISR.
\param cardIndex    (Input) Logical Card Index assigned to connection with the NAI_BOARD (0 - NAI_MAX_CARDS-1).
\param modNum       (Input) Module Number of the module to access (1 - [max modules for board]).
\param channelCount (Input) Channel Number of the channel to access (1 - [max channels for module]).
*/
/**************************************************************************************************************/
static void CheckForStatusChange(int32_t cardIndex, int32_t modNum, int32_t channelCount)
{
   uint32_t channelStatus;
   static int32_t chanIndex = 0;

   /* chanIndex is a static variable and allows processing multiple interrupts. In the event that multiple
      interrupts occur at once, the first interrupt is flagged and every subsequent call to this function will
      check the next channel and flag the interrupt. */
   do
   {
      check_status(naibrd_SER_GetChannelStatus(cardIndex, modNum, type[chanIndex], &channelStatus));
      if (0 != (channelStatus & NAI_SER_GEN5_INT_TXCOMPLETE))
      {
         irqSERCount++;
         receivedVector = vector[chanIndex];
         receivedType = type[chanIndex];
         receivedChannelStatus = channelStatus;
         interruptStatus = INTERRUPT_RECEIVED;
      }
      chanIndex++;
   } while ((chanIndex < channelCount) && (INTERRUPT_RECEIVED != interruptStatus));

   if (chanIndex >= channelCount)
   {
      chanIndex = 0;
   }
}
#endif  /* RUN_ISR */

/**************************************************************************************************************/
/** \ingroup SERInterrupts
Clears channel status and resets applicable application variables- to allow another interrupt to occur.
status has been met.
\param cardIndex (Input) Logical Card Index assigned to connection with the NAI_BOARD (0 - NAI_MAX_CARDS-1).
\param modNum    (Input) Module Number of the module to access (1 - [max modules for board]).
\param type      (Input) Interrupt type (latched or realtime).
*/
/**************************************************************************************************************/
static void ClearInterrupt(int32_t cardIndex, int32_t modNum, nai_ser_status_type_t type)
{
   check_status(naibrd_SER_ClearChannelStatus(cardIndex, modNum, type, NAI_SER_GEN5_INT_TXCOMPLETE));

   receivedVector = 0xFFFFFFFF;
   receivedType = NAI_SER_STATUS_GEN5_ENUM_COUNT;
   receivedChannelStatus = 0;
   irqSERCount = 0;
   interruptStatus = INTERRUPT_WAITING;
}

Help Bot

X