AR Interrupt
Edit this on GitLab
AR Interrupt Sample Application (SSK 1.x)
Overview
The AR Interrupt sample application demonstrates how to configure and handle hardware interrupts on ARINC 429 (AR) modules using the NAI Software Support Kit (SSK 1.x). The sample covers two interrupt delivery mechanisms: standard (onboard/offboard ISR) and Ethernet IDR (Interrupt Driven Response, network-based). Both variants configure and enable the same underlying interrupt type — RX Data Available — and share the same module-level configuration code. The difference is only in how the interrupt notification reaches your application.
This sample supports the following ARINC module types: AR1, AR2, CM2, and CM5.
This is the "full" version of the ARINC interrupt sample. It supports multiple channels simultaneously, configurable edge/level triggering, onboard and offboard ISR delivery, Ethernet IDR delivery, optional timestamp capture, and user-controlled interrupt clearing. For a simpler starting point that covers single-channel onboard ISR delivery only, see the AR Interrupt Basic sample application guide.
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 ARINC 429 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 an ARINC module installed (AR1, AR2, or a combination module such as CM2, CM5).
-
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:
-
AR_Interrupt— standard interrupt delivery (onboard or offboard ISR). Supports multi-channel interrupt handling. -
AR_Interrupt_Ethernet— Ethernet-based interrupt delivery using IDR commands. Operates on a single channel.
Launch either executable from your build output directory. On startup the application looks for a configuration file (default_AR_Interrupt.txt for the standard variant, default_AR_Interrupt_Ethernet.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 AR. |
The main() function follows a standard SSK 1.x startup flow:
-
Initialize AR and interrupt configuration structures with defaults using
initializeARConfigurations()andinitializeInterruptConfigurations(). The Ethernet variant additionally callsinitializeIDRConfigurations()to set up the IDR response address, port, and protocol. -
Call
naiapp_RunBoardMenu()to load a saved configuration file (if one exists) or present the interactive board menu. The configuration file (default_AR_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. -
Query the user for card index and module number.
-
Retrieve the module ID with
naibrd_GetModuleID()to verify an ARINC module is installed at the selected slot.
#if defined (__VXWORKS__)
int32_t AR_Interrupt(void)
#else
int32_t main(void)
#endif
{
bool_t stop = FALSE;
int32_t cardIndex;
int32_t moduleCnt;
int32_t module;
int8_t inputBuffer[80];
int32_t inputResponseCnt;
initializeARConfigurations(0,0,0,0,0,0,MAX_FIFO_COUNT, DEF_AR_TIMESTAMP,FALSE);
initializeInterruptConfigurations(FALSE,FALSE,FALSE,0,0,0,0);
if (naiapp_RunBoardMenu(CONFIG_FILE) == TRUE)
{
while (stop != TRUE)
{
/* Query the user for the card index */
stop = naiapp_query_CardIndex(naiapp_GetBoardCnt(), 0, &cardIndex);
inputARConfig.cardIndex = cardIndex;
if (stop != TRUE)
{
check_status(naibrd_GetModuleCount(cardIndex, &moduleCnt));
/* Query the user for the module number */
stop = naiapp_query_ModuleNumber(moduleCnt, 1, &module);
inputARConfig.module = module;
if (stop != TRUE)
{
inputARConfig.modid = naibrd_GetModuleID(cardIndex, module);
if ((inputARConfig.modid != 0))
{
Run_AR_Interrupt();
}
}
}
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:
|
Program Structure
The AR Interrupt sample is split across four source files. Two variant-specific files provide the main() entry point and interrupt delivery logic, while two shared common files handle module configuration, interrupt handlers, and Ethernet IDR command construction:
-
AR_Interrupt.c— standard interrupt variant. Uses onboard or offboard ISR delivery vianaibrd_InstallISR(). Supports a range of channels simultaneously. -
AR_Interrupt_Ethernet.c— Ethernet IDR variant. Delivers interrupt notifications over the network using IDR commands. Operates on a single channel. -
nai_ar_int.c— shared interrupt configuration and handling logic used by both variants. ContainsconfigureARToInterruptOnRx(),configureARToInterruptOnRxMultiChan(),enableARInterrupts(),handleARInterrupt(), and the basic ISR callback. -
nai_ar_int_ether.c— Ethernet IDR-specific code. ContainssetupIDRConfiguration_AR(), IDR command construction functions, andHandleAREtherInterrupt().
Each variant has its own entry point:
-
Standard:
main()(orAR_Interrupt()on VxWorks). -
Ethernet IDR:
main()(orAR_Interrupt_Basic_Ethernet()on VxWorks).
After the board connection is established, both variants follow a similar user selection flow:
-
Select a card index and module slot.
-
For the standard variant: select a channel range (min/max). For the Ethernet variant: select a single channel.
-
Choose edge-triggered or level-triggered interrupt mode.
-
Choose whether to be prompted before clearing each interrupt, or clear automatically (standard variant).
-
Choose onboard or offboard interrupt delivery.
-
For the standard variant: choose the interrupt steering destination. For the Ethernet variant: configure the IDR IP address, port, and protocol.
-
Optionally enable timestamp capture on received ARINC messages.
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 key structures to track user selections and board state:
/* From nai_ar_cfg.h */
typedef struct _ArConfig
{
int32_t cardIndex;
int32_t module;
int32_t modid;
int32_t channel;
int32_t minChannel;
int32_t maxChannel;
int32_t maxFifoCount;
bool_t timeStampEnable;
bool_t labelEnable;
} ArConfig;
ArConfig captures the ARINC module identification and channel settings. For the standard variant, minChannel and maxChannel define the range of channels to monitor. For the Ethernet variant, channel specifies the single channel to monitor. The timeStampEnable flag controls whether receive timestamps are captured with each ARINC message.
/* From naiapp_interrupt.h */
typedef struct _InterruptConfig
{
bool_t bPromptForInterruptClear;
bool_t bProcessOnboardInterrupts;
bool_t displayData;
int32_t interrupt_Edge_Trigger;
int32_t steering;
int32_t irq;
int32_t cardIndex;
} InterruptConfig;
InterruptConfig captures the interrupt delivery preferences: trigger mode (edge vs. level), steering destination, IRQ assignment, and whether the user wants to be prompted before clearing each interrupt.
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
ARINC 429 modules expose two primary interrupt status types relevant to this sample. Each monitors a different hardware condition at the module level.
RX Data Available
AR_RX_DATA_AVAIL
The module’s receive FIFO for a channel contains at least one complete ARINC 429 message. When a valid message is received and placed into the FIFO, the module sets the RX Data Available status bit and, if enabled, raises an interrupt. This is the primary interrupt type used by this sample.
Enable RX Data Available interrupts when you need immediate notification that new ARINC data has arrived, rather than polling the FIFO buffer count on a timer. This is the standard approach for event-driven ARINC receive applications where latency matters — avionics data buses, real-time displays, or message-triggered processing pipelines.
When the interrupt fires, your handler should read the FIFO buffer count with naibrd_AR_GetRxBufferCnt() and then drain the available messages with naibrd_AR_ReadFifo(). The sample demonstrates this pattern in both the standard and Ethernet handlers.
BIT (Built-In Test)
The module’s internal self-test has detected an anomaly on a channel. The Built-In Test circuitry uses a loopback path to verify that the transmitter and receiver are functioning correctly. When BIT detects a discrepancy — for example, a transmitted test word that is not received back correctly — it latches the corresponding status bit.
While this sample focuses on RX Data Available interrupts, the BIT status is available for health monitoring. In safety-critical ARINC applications, you may want to enable BIT interrupts alongside RX Data Available to detect channel failures immediately rather than during periodic status checks.
Consult your module’s manual for the complete list of ARINC interrupt status types and the specific register layout for your module generation.
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 configureARToInterruptOnRxMultiChan() function in nai_ar_int.c (used by the standard variant for multi-channel setup) and configureARToInterruptOnRx() (used by the Ethernet variant for single-channel setup) perform the same four steps per channel: disable interrupts, clear status registers, set the interrupt vector, configure the trigger mode, and set interrupt steering.
Step 1: Disable and Clear Previous Configuration
Always disable interrupts and clear latched status before changing configuration. Stale latched status from a previous run will trigger an immediate interrupt if not cleared. The function begins by disabling the channel’s interrupt enable and clearing all status bits:
/* clear interruptConfigs of previous channels */
check_status( naibrd_AR_SetInterruptEnable( cardIndex, module, channel, 0 ) );
check_status( naibrd_AR_ClearStatus( cardIndex, module, channel, 0xFFFF ) );
naibrd_AR_SetInterruptEnable() with a value of 0 disables all interrupt sources for the channel. naibrd_AR_ClearStatus() with 0xFFFF clears all latched status bits. This combination ensures you start from a known-clean state.
Step 2: Set Interrupt Vector
The vector identifies which interrupt source generated the event. The sample assigns NAI_AR_INTERRUPT_VECTOR to all channels so that a single ISR can service every ARINC interrupt on the module:
check_status( naibrd_AR_SetInterruptVector( cardIndex, module, channel, vector ) );
If you need to distinguish channels inside your ISR without reading status registers, you can assign a different vector to each channel. In practice, most applications use a shared vector and read the per-channel status registers to determine which channel(s) fired.
Step 3: Set Trigger Mode
The trigger mode determines when the interrupt fires relative to the status change:
check_status( naibrd_AR_SetInterruptEdgeLevel( cardIndex, module, channel, interrupt_Edge_Trigger ) );
A value of 0 selects edge-triggered mode, where the interrupt fires once when the condition is first detected (the status bit transitions from 0 to 1). A value of 1 selects level-triggered mode, where the interrupt continues to assert as long as the condition remains active.
For ARINC receive interrupts, level-triggered (the default in this sample) is the typical choice. ARINC messages arrive asynchronously and you want the interrupt to remain active if multiple messages arrive in quick succession. With edge triggering, you risk missing messages if new data arrives between the time you read the status and clear it. For detailed theory on edge vs. level triggering and when to use each mode, see the Interrupts API Guide.
Step 4: Set Interrupt Steering
Interrupt steering determines how the interrupt signal is delivered from the module to your application:
check_status( naibrd_AR_SetInterruptSteering( cardIndex, module, channel, steering ) );
The steering options are:
-
Onboard (
NAIBRD_INT_STEERING_ON_BOARD_0) — handled locally on the board’s processor. The ISR runs directly on the board without traversing a bus. This is the standard choice for onboard applications. -
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 theAR_Interrupt_Ethernetvariant. -
cPCI offboard (
NAIBRD_INT_STEERING_CPCI_APP) — routes the interrupt to the CompactPCI backplane host. -
PCIe offboard (
NAIBRD_INT_STEERING_PCIE_APP) — routes the interrupt to the PCIe host.
For a full description of each steering mode and the hardware paths involved, refer to your module manual and the Interrupts API Guide.
Multi-Channel Configuration (Standard Variant)
The standard variant iterates over the user-selected channel range and applies the same configuration to each channel:
void configureARToInterruptOnRxMultiChan( InterruptConfig inputInterruptConfig, ArConfig inputARConfig )
{
int32_t idxChan;
int32_t cardIndex = inputARConfig.cardIndex;
int32_t module = inputARConfig.module;
int32_t minChan = inputARConfig.minChannel;
int32_t maxChan = inputARConfig.maxChannel;
int32_t vector = NAI_AR_INTERRUPT_VECTOR;
int32_t interrupt_Edge_Trigger = inputInterruptConfig.interrupt_Edge_Trigger;
int32_t steering = inputInterruptConfig.steering;
for ( idxChan = minChan; idxChan <= maxChan; idxChan++ )
{
check_status( naibrd_AR_SetInterruptEnable( cardIndex, module, idxChan, 0 ) );
check_status( naibrd_AR_ClearStatus( cardIndex, module, idxChan, 0xFFFF ) );
check_status( naibrd_AR_SetInterruptVector( cardIndex, module, idxChan, vector ) );
check_status( naibrd_AR_SetInterruptEdgeLevel( cardIndex, module, idxChan, interrupt_Edge_Trigger ) );
check_status( naibrd_AR_SetInterruptSteering( cardIndex, module, idxChan, steering ) );
}
}
This loop applies the four configuration steps to every channel in the range. The Ethernet variant calls configureARToInterruptOnRx(), which performs the identical steps for a single channel.
Enable Interrupts
After configuration, the enableARInterrupts() function enables interrupt generation for the configured channels:
void enableARInterrupts( ArConfig inputARConfig, bool_t enable )
{
int32_t channel = inputARConfig.channel;
int32_t idxChan;
if ( channel == 0 )
{
for ( idxChan = 1; idxChan <= inputARConfig.maxChannel; idxChan++ )
{
check_status( naibrd_AR_SetInterruptEnable( inputARConfig.cardIndex, inputARConfig.module, idxChan, enable ) );
}
}
else
{
check_status( naibrd_AR_SetInterruptEnable( inputARConfig.cardIndex, inputARConfig.module, inputARConfig.channel, enable ) );
}
}
When channel is 0 (the standard variant sets channel to 0 and uses the min/max range), the function iterates over all channels up to maxChannel. When channel is non-zero (the Ethernet variant), it enables only that specific channel. Pass AR_RX_DATA_AVAIL to enable or FALSE to disable.
|
Important
|
Common interrupt configuration errors:
|
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 reading the FIFO data from the interrupting channels. All code is from AR_Interrupt.c and nai_ar_int.c.
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:
inputInterruptConfig.cardIndex = inputARConfig.cardIndex;
check_status( naibrd_InstallISR( inputInterruptConfig.cardIndex, inputInterruptConfig.irq,
(nai_isr_t)IntOnboardIsr, NULL ) );
Offboard:
inputInterruptConfig.cardIndex = 0;
check_status( naibrd_AR_SetInterruptSteering( inputInterruptConfig.cardIndex, inputARConfig.module,
inputARConfig.channel, NAIBRD_INT_STEERING_ON_BOARD_0 ) );
check_status( naibrd_InstallISR( inputInterruptConfig.cardIndex, NAIBRD_IRQ_ID_ON_BOARD_0,
(nai_isr_t)IntOffboardIsr, (void*)&inputARConfig.cardIndex ) );
For onboard delivery, naibrd_InstallISR() registers IntOnboardIsr with the IRQ determined by the user’s steering selection. For offboard delivery, the ISR is installed on the master board (card index 0) with IntOffboardIsr, which receives the originating card index as its context parameter so it can identify which board generated the interrupt.
The IRQ ID you pass here must match the steering mode configured in the previous section. A mismatch will silently prevent interrupts from reaching your ISR.
Thread Setup and Execution Flow
The standard variant follows this sequence after ISR installation:
/**** 3. configure Module to perform interrupts ****/
configureARToInterruptOnRxMultiChan( inputInterruptConfig, inputARConfig );
/**** 4. Configure Module to cause Interrupts ****/
Cfg_Rx_AR( inputARConfig );
/**** Initialize Message Queue ****/
InitInterruptAppThread( ONBOARD_INT, 0 );
nai_msDelay( 10 );
UpdateThreadState( RUN );
/**** Enable Interrupts ****/
enableARInterrupts( inputARConfig, AR_RX_DATA_AVAIL );
/*** 5. Show Interrupt Handling (contains step 6) ***/
arIntProcessFunc = handleARInterrupt;
Cfg_Rx_AR() configures the ARINC receive parameters (baud rate and receive enable) for the selected channels, making the module ready to receive bus traffic. InitInterruptAppThread() creates the background thread that runs the interrupt state machine. The 10 ms delay ensures the thread’s state machine has completed its initialization cycle before any interrupts can arrive. UpdateThreadState(RUN) transitions the thread from its idle startup state into active processing.
The arIntProcessFunc function pointer is set to handleARInterrupt so the interrupt thread knows which callback to invoke when an interrupt message arrives. The application then displays a prompt and waits for interrupt events until the user quits.
Interrupt Handler
handleARInterrupt() is called by the interrupt thread each time the ISR posts a message. The handler iterates over all configured channels, reads the latched status and FIFO data from each channel that triggered, then clears the status to re-arm the interrupt.
void handleARInterrupt( uint32_t nVector )
{
static uint32_t status[NAI_GEN5_AR_MAX_CHANNEL_COUNT + 1];
static FIFO fifoArrayToPrint[NAI_GEN5_AR_MAX_CHANNEL_COUNT + 1];
int32_t idxChan;
int32_t minChan = inputARConfig.minChannel;
int32_t maxChan = inputARConfig.maxChannel;
uint32_t mask = AR_RX_DATA_AVAIL;
uint32_t statusMasked;
uint32_t statArr[NAI_AR_MAX_DATA_LEN];
uint32_t dataArr[NAI_AR_MAX_DATA_LEN];
uint32_t tstampArr[NAI_AR_MAX_DATA_LEN];
int32_t bufferCountsArray[NAI_GEN5_AR_MAX_CHANNEL_COUNT + 1];
naibrd_Wait( 1000000 );
for ( idxChan = minChan; idxChan <= maxChan; idxChan++ )
{
check_status( naibrd_AR_GetStatus( inputARConfig.cardIndex, inputARConfig.module, idxChan,
NAI_AR_STATUS_LATCHED, &status[idxChan] ) );
statusMasked = status[idxChan] & mask;
if ( statusMasked == mask )
{
int32_t outcount;
int32_t outnummsgs;
check_status( naibrd_AR_GetRxBufferCnt( inputARConfig.cardIndex, inputARConfig.module,
idxChan, &outcount ) );
check_status( naibrd_AR_ReadFifo( inputARConfig.cardIndex, inputARConfig.module, idxChan,
inputARConfig.timeStampEnable, outcount, statArr, dataArr, tstampArr, &outnummsgs ) );
/* Store FIFO data for display */
fifoArrayToPrint[idxChan].length = outcount;
bufferCountsArray[idxChan] = outcount;
}
}
printf( "\nInterrupt Occurred\n" );
if ( inputInterruptConfig.bPromptForInterruptClear == TRUE )
{
promptUserToClearInterrupt_AR();
}
for ( idxChan = minChan; idxChan <= maxChan; idxChan++ )
{
check_status( naibrd_AR_ClearStatus( inputARConfig.cardIndex, inputARConfig.module, idxChan, 0xFFFF ) );
}
printInterruptInformation_AR( nVector, status, fifoDataFile, bufferCountsArray, fifoArrayToPrint );
}
The handler works as follows:
-
Wait for module —
naibrd_Wait(1000000)gives the module time to complete any in-progress FIFO write before reading. This prevents reading a partial message. -
Read status per channel —
naibrd_AR_GetStatus()reads the latched status register for each channel in the configured range. The result is masked againstAR_RX_DATA_AVAILto check whether new data triggered the interrupt. -
Drain the FIFO — for each channel with the RX Data Available bit set,
naibrd_AR_GetRxBufferCnt()returns the number of messages waiting andnaibrd_AR_ReadFifo()reads them all. Each message includes a status word, the 32-bit ARINC data word, and an optional timestamp. -
Clear status to re-arm —
naibrd_AR_ClearStatus()with0xFFFFclears all latched status bits for each channel. This is essential: if you omit this step with edge-triggered interrupts, no new edge will occur and the interrupt will never fire again. -
Display results —
printInterruptInformation_AR()formats the vector, per-channel status, and FIFO contents to the output stream (stdout or a file, depending on user preference).
Auto-Clear vs. Prompt-Clear
The sample provides two interrupt clearing modes controlled by the bPromptForInterruptClear flag:
if ( inputInterruptConfig.bPromptForInterruptClear == TRUE )
{
promptUserToClearInterrupt_AR();
}
for ( idxChan = minChan; idxChan <= maxChan; idxChan++ )
{
check_status( naibrd_AR_ClearStatus( inputARConfig.cardIndex, inputARConfig.module, idxChan, 0xFFFF ) );
}
When prompt-clear is active, the handler pauses and prints Press "C" to clear interrupts…. It polls GetUserRequestClearInt() in a 10 ms loop until the user responds. This mode is useful for learning and debugging because it lets you observe the latched status and FIFO contents before clearing.
When auto-clear is active, the prompt is skipped and the handler proceeds directly to naibrd_AR_ClearStatus(). This is the recommended mode for production use — it minimizes interrupt latency and avoids the risk of missed interrupts while waiting for user input.
Cleanup
When the user quits, the application disables interrupts, clears status, disables receive, and uninstalls the ISR:
/***** 7. Clear Module Configurations *****/
enableARInterrupts( inputARConfig, FALSE );
for ( chan = inputARConfig.minChannel; chan <= inputARConfig.maxChannel; chan++ )
{
check_status( naibrd_AR_SetRxEnable( inputARConfig.cardIndex, inputARConfig.module, chan, FALSE ) );
check_status( naibrd_AR_ClearStatus( inputARConfig.cardIndex, inputARConfig.module, chan, 0xFFFF ) );
}
/***** 8. Clear Board Configurations *****/
check_status( naibrd_UninstallISR( inputInterruptConfig.cardIndex ) );
Always disable interrupts and uninstall the ISR before exiting. Leaving an ISR installed after your application exits can cause system instability if a stale interrupt fires.
|
Important
|
Common standard interrupt handling errors:
|
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 the board to automatically read status registers and package the results into a single UDP message.
Prerequisites
Ethernet IDR requires a Generation 4 or later board with Ethernet support. The application verifies this at startup before proceeding with IDR configuration:
bGen4ArIDRCommands = SupportsGen4Ether( inputARConfig.cardIndex );
if ( !bGen4ArIDRCommands )
{
printf( "AR Ethernet Interrupt Support Prior to Generation 4 Ethernet commands currently not supported\n" );
bQuit = TRUE;
}
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 setupIDRConfiguration_AR() 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.
void setupIDRConfiguration_AR( ArConfig inputARConfig, IDRConfig* inputIDRConfig, bool_t bGen4ArIDRCommands )
{
int32_t cardIndex = inputIDRConfig->cardIndex;
uint16_t protocol = inputIDRConfig->protocol;
uint16_t port = inputIDRConfig->port;
uint8_t* ipAddress = inputIDRConfig->ipAddress;
uint8_t ipLength = inputIDRConfig->ipLength;
int32_t vector = NAI_AR_INTERRUPT_VECTOR;
uint8_t *commands = inputIDRConfig->commands;
uint16_t *cmdcount = &inputIDRConfig->cmdcount;
uint16_t *cmdlength = &inputIDRConfig->cmdlength;
check_status( naibrd_Ether_ClearIDRConfig( cardIndex, (uint16_t)DEF_ETHERNET_AR_IDR_ID ) );
InitARRxIDRCommands( inputARConfig, inputIDRConfig, bGen4ArIDRCommands );
check_status( naibrd_Ether_SetIDRConfig( cardIndex, (uint16_t)DEF_ETHERNET_AR_IDR_ID, protocol,
ipLength, ipAddress, port, vector, *cmdcount, *cmdlength, commands ) );
}
The configuration flow proceeds in three steps:
-
Clear any previous IDR configuration —
naibrd_Ether_ClearIDRConfig()removes any existing IDR registered underDEF_ETHERNET_AR_IDR_IDso the new configuration starts clean. -
Build the read command —
InitARRxIDRCommands()callsMakeARRxReadRegsCommand()to construct an Ethernet read command targeting the channel’s latched interrupt status register. This command is embedded in the IDR definition so that when the interrupt fires, the board automatically reads the status register and includes the result in the UDP response message. -
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.
The IDR read command is constructed using the board address and module offset to target the correct register:
void MakeARRxReadRegsCommand( ArConfig inputARConfig, IDRConfig* inputIDRConfig,
uint32_t boardAddress, int32_t moduleOffset,
bool_t bGen4Ether, uint16_t startIndex )
{
uint32_t AR_GEN5_LatchedIntStatusAddr[] = NAI_AR_GEN5_REG_CH_LATCHED_INT_STATUS_ADD;
uint16_t seqno = 0;
uint32_t regaddr = boardAddress + moduleOffset + AR_GEN5_LatchedIntStatusAddr[inputARConfig.channel-1];
uint32_t count = 1;
uint32_t stride = 4;
msgIndex = (uint16_t)nai_ether_MakeReadMessage( &inputIDRConfig->commands[startIndex],
seqno, NAI_ETHER_GEN4, (nai_intf_t)inputIDRConfig->boardInterface,
regaddr, stride, count, NAI_REG32 );
inputIDRConfig->cmdlength = inputIDRConfig->cmdlength + msgIndex;
command_index_interrupt_status = inputIDRConfig->cmdcount;
inputIDRConfig->cmdcount++;
}
The register address is calculated by adding the board base address, the module offset within the board, and the per-channel latched status register offset from NAI_AR_GEN5_REG_CH_LATCHED_INT_STATUS_ADD. The resulting read command requests a single 32-bit register.
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:
check_status( naibrd_Ether_StartIDR( inputIDRConfig.cardIndex, (uint16_t)DEF_ETHERNET_AR_IDR_ID ) );
The Ethernet variant then starts the IDR server with runIDRServer(), which listens for incoming UDP messages and dispatches them to the registered handler.
When the application exits, stop the IDR and clean up:
/***** 8. Clear Board Configurations *****/
check_status( naibrd_Ether_StopIDR( inputIDRConfig.cardIndex, (uint16_t)DEF_ETHERNET_AR_IDR_ID ) );
check_status( naibrd_Ether_ClearIDRConfig( inputIDRConfig.cardIndex, DEF_ETHERNET_AR_IDR_ID ) );
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
HandleAREtherInterrupt() 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 HandleAREtherInterrupt( uint16_t msglen, uint8_t msg[], uint16_t tdr_idr_id )
{
static uint32_t status;
static FIFO fifoToPrint;
uint16_t seq;
nai_ether_typecode_t typeCode;
nai_ether_gen_t gen = NAI_ETHER_GEN4;
int32_t size;
int32_t commandIndex;
nai_ether_DecodeMessageHeader(msg, msglen, &seq, &typeCode, gen, &size);
commandIndex = ( seq & ( 0x0F << 6 ) ) >> 6;
naibrd_Wait( 1000000 );
switch (typeCode)
{
case NAI_ETHER_TYPECODE_RSP_COMMAND_COMPLETE_READ_4:
if ( inputIDRConfig.cmdcount-1 == commandIndex )
{
status = msg[11];
status = ( status | ( msg[10] << 8 ) );
if ( status & 0x1 )
{
int32_t outcount, outnummsgs;
check_status( naibrd_AR_GetRxBufferCnt( inputARConfig.cardIndex,
inputARConfig.module, inputARConfig.channel, &outcount ) );
if ( outcount > 0 )
{
uint32_t stat[NAI_AR_MAX_DATA_LEN];
uint32_t data[NAI_AR_MAX_DATA_LEN];
uint32_t tstamp[NAI_AR_MAX_DATA_LEN];
check_status( naibrd_AR_ReadFifo( inputARConfig.cardIndex, inputARConfig.module,
inputARConfig.channel, inputARConfig.timeStampEnable,
outcount, stat, data, tstamp, &outnummsgs ) );
/* Store FIFO data for display */
fifoToPrint.length = outcount;
}
}
}
break;
}
if ( commandIndex == inputIDRConfig.cmdcount - 1 )
{
printf( "\nInterrupt Occurred\n" );
printEthernetInterruptInformation( tdr_idr_id, status, fifoDataFile,
fifoToPrint.length, fifoToPrint );
}
/* Clear Interrupt Latch */
check_status( naibrd_AR_ClearStatus( inputARConfig.cardIndex, inputARConfig.module,
inputARConfig.channel, 0xFFFF ) );
}
The handler works as follows:
-
Parse the message header —
nai_ether_DecodeMessageHeader()extracts the sequence number, typecode, and payload offset from the raw UDP message. -
Extract the command index — the command index is encoded in the sequence number field. The handler uses this to verify which IDR command response it is processing.
-
Verify the typecode — the handler checks for
NAI_ETHER_TYPECODE_RSP_COMMAND_COMPLETE_READ_4, which indicates a successful 32-bit register read response. -
Extract the status value — the latched status is assembled from two bytes in the response payload. Bit 0 (RX Data Available) is checked to determine whether FIFO data needs to be read.
-
Drain the FIFO — if the status indicates data is available, the handler reads the FIFO buffer count and drains all messages, just like the standard handler.
-
Display and clear — the status and FIFO data are formatted for display, and
naibrd_AR_ClearStatus()clears the latched status to re-arm the interrupt.
Efficiency Advantage
The key advantage of the Ethernet IDR approach is that the board reads the status register automatically and includes the result in the UDP notification message. The standard handler must issue separate naibrd_AR_GetStatus() 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 a network round-trip per interrupt event for the status read, reducing both latency and network traffic.
Note that FIFO data is still read separately via naibrd_AR_ReadFifo() in the current implementation. The IDR provides the status to determine whether data needs to be read, but the actual FIFO drain is performed as a follow-up API call.
|
Important
|
Common Ethernet IDR errors:
|
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:
-
Check whether the status registers are changing. Call
naibrd_AR_GetStatus()withNAI_AR_STATUS_LATCHEDto read the latched status for the channel you expect. If the status bits are changing when ARINC messages are being sent to the channel, the module is detecting the event correctly — the issue is in your interrupt delivery path (steering, ISR installation, or thread setup). -
If the status registers are NOT changing, the issue is at the hardware or channel configuration level. Verify that the correct channel is configured, that
naibrd_AR_SetRxEnable()has been called to enable the receiver, that the baud rate matches the bus you are connected to, and that a valid ARINC signal is present on the bus. 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 AR |
No ARINC module installed at the selected slot, incorrect module number, or a non-AR module is present |
Verify hardware configuration. |
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: |
Handler never called (standard) |
Thread not started, ISR not installed for correct IRQ, or steering mismatch |
Verify |
Interrupts stop after first (edge-triggered) |
Status not cleared in handler — edge interrupts require clearing to re-arm |
Ensure |
Interrupts fire continuously (level-triggered) |
The underlying condition persists (data in FIFO) — this is expected for level-triggered interrupts |
Drain the FIFO completely and clear the status in your handler, or switch to edge triggering if continuous firing is not desired. |
FIFO data missing or incomplete |
Reading FIFO too quickly after interrupt fires, module still finalizing write |
Ensure |
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 |
Ethernet status always zero |
Incorrect register address in IDR read command, module offset or board address retrieval failed |
Verify |
Timestamp data missing |
Timestamp not enabled before receiving messages |
Call |
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 four source files: the standard interrupt application, the Ethernet IDR variant, shared interrupt configuration code, and shared Ethernet IDR code.
Full Source — AR_Interrupt.c (SSK 1.x)
/**************************************************************************************************************/
/**
<summary>
The AR_Interrupt program demonstrates how to perform an interrupt when a single channel receives
an ar message. The purpose of this program is to demonstrate the method calls in the naibrd library for performing
the interrupt. More information on this process can be found in the naibrd SSK Quick Guide (Interrupts) file.
This application differs from AR_Interrupt_Basic in that it could handle multiple interrupts at once.
It also queries the user for the edge trigger value and whether the user should be prompted to clear an interrupt.
The application also has support for offboard interrupts.
</summary>
*/
/**************************************************************************************************************/
/************************/
/* Include Declarations */
/************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
/* Common Module Specific Sample Program include files */
#include "nai_ar_int.h"
#include "nai_ar_cfg.h"
#include "nai_ar_utils.h"
/* Common Sample Program include files */
#include "include/naiapp_interrupt.h"
#include "include/naiapp_interrupt_ether.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_ar.h"
InterruptConfig inputInterruptConfig;
IntProcessFuncDef arIntProcessFunc;
/* Extern Functions or Variables*/
extern ArConfig inputARConfig;
extern FILE* fifoDataFile;
/*********************************************/
/* Application Name and Revision Declaration */
/*********************************************/
static const int8_t *CONFIG_FILE = (int8_t *)"default_AR_Interrupt.txt";
/********************************/
/* Internal Function Prototypes */
/********************************/
static bool_t Run_AR_Interrupt();
/**************************************************************************************************************/
/***** Main Routine *****/
/**************************************************************************************************************/
/**************************************************************************************************************/
/**
<summary>
The main routine assists in gaining access to the board.
The following routines from the nai_sys_cfg.c file are
called to assist with accessing and configuring the board.
- ConfigDevice
- DisplayDeviceCfg
- GetBoardSNModCfg
- CheckModule
</summary>
*/
/*****************************************************************************/
#if defined (__VXWORKS__)
int32_t AR_Interrupt(void)
#else
int32_t main(void)
#endif
{
bool_t stop = FALSE;
int32_t cardIndex;
int32_t moduleCnt;
int32_t module;
int8_t inputBuffer[80];
int32_t inputResponseCnt;
initializeARConfigurations(0,0,0,0,0,0,MAX_FIFO_COUNT, DEF_AR_TIMESTAMP,FALSE);
initializeInterruptConfigurations(FALSE,FALSE,FALSE,0,0,0,0);
if (naiapp_RunBoardMenu(CONFIG_FILE) == TRUE)
{
while (stop != TRUE)
{
/* Query the user for the card index */
stop = naiapp_query_CardIndex(naiapp_GetBoardCnt(), 0, &cardIndex);
inputARConfig.cardIndex = cardIndex;
if (stop != TRUE)
{
check_status(naibrd_GetModuleCount(cardIndex, &moduleCnt));
/* Query the user for the module number */
stop = naiapp_query_ModuleNumber(moduleCnt, 1, &module);
inputARConfig.module = module;
if (stop != TRUE)
{
inputARConfig.modid = naibrd_GetModuleID(cardIndex, module);
if ((inputARConfig.modid != 0))
{
Run_AR_Interrupt();
}
}
}
printf("\nType Q to quit or Enter key to restart application:\n");
stop = naiapp_query_ForQuitResponse(sizeof(inputBuffer), NAI_QUIT_CHAR, inputBuffer, &inputResponseCnt);
}
}
printf("\nType the Enter key to exit the program: ");
naiapp_query_ForQuitResponse(sizeof(inputBuffer), NAI_QUIT_CHAR, inputBuffer, &inputResponseCnt);
naiapp_access_CloseAllOpenCards();
return 0;
}
/**************************************************************************************************************/
/**
<summary>
This function is broken into the following major steps. These steps correspond with the steps provided
in the naibrd SSK Quick Guide (Interrupts) file.
2. Bus Interrupt Handling - Install ISR
API CALLS - naibrd_InstallISR
3. Enable Module Interrupts- Configures module to interrupt when channel receives AR message.
API CALLS - naibrd_AR_SetInterruptEdgeLevel, naibrd_AR_SetIntVector, naibrd_AR_SetInterruptSteering, naibrd_AR_SetIntEnable
4. Configure Module to Cause Rx Interrupt - sets the BAUD Rate to 1mbit/s (AR AB) or 500k bits/s (AR J1939) as definted in nai_ar_utils.h
It also enables the particular channel on the module to receive ar messages
API CALLS - naibrd_AR_SetBitTiming , naibrd_AR_SetRxEnable
5. Show Interrupt Handling - Check the mailbox to see if any interrupts occurred.
6. Re-arming Interrupts - Clear the status register to allow interrupts to occur again. This is done by writing to the status register.
In this program, we use an API call to do this.
API CALLS - naibrd_AR_ClearStatus
7. Clear Module Configurations
API CALLS - naibrd_AR_SetRxEnable
8. Clear Board Configurations
API CALLS - naibrd_UninstallISR
</summary>
*/
/**************************************************************************************************************/
static bool_t Run_AR_Interrupt()
{
bool_t bQuit = FALSE;
int32_t minChannel;
int32_t maxChannel;
minChannel = 1;
maxChannel = naibrd_AR_GetChannelCount( inputARConfig.modid );
/* Query for Channels to Operate on */
bQuit = naiapp_query_ForChannelRange( &inputARConfig.minChannel, &inputARConfig.maxChannel, minChannel, maxChannel );
/* Query for Trigger Status of interrupts */
if (!bQuit)
{
bQuit = GetARLatchStatusTriggerMode( &inputInterruptConfig.interrupt_Edge_Trigger );
}
/* Query user if they'd like to be prompted for clearing interrupts */
if (!bQuit)
{
bQuit = QueryUserForClearingInterruptPrompts( &inputInterruptConfig.bPromptForInterruptClear );
}
if (!bQuit)
{
bQuit = QueryUserForOnboardOffboardInterrupts( &inputInterruptConfig.bProcessOnboardInterrupts );
}
/* Query user if they'd like to display fifo data after interrupt */
if (!bQuit)
{
bQuit = QueryUserForDisplayingData( &inputInterruptConfig.displayData );
}
/* Query user for location interrupt will be sent out to */
if (!bQuit)
{
bQuit = GetIntSteeringTypeFromUser( &inputInterruptConfig.steering );
}
if (!bQuit)
{
bQuit = QueryUserForTimeStampEnable(&inputARConfig.timeStampEnable );
}
if (!bQuit)
{
int32_t chan;
if ( inputInterruptConfig.displayData )
fifoDataFile = stdout;
else
fifoDataFile = fopen( "fifoData.txt", "w+" );
/**** 2. Implement Bus Interrupt Handling ****/
setIRQ( inputInterruptConfig.steering, &inputInterruptConfig.irq );
if ( inputInterruptConfig.bProcessOnboardInterrupts == TRUE )
{
inputInterruptConfig.cardIndex = inputARConfig.cardIndex;
check_status( naibrd_InstallISR( inputInterruptConfig.cardIndex, inputInterruptConfig.irq, (nai_isr_t)IntOnboardIsr, NULL ) );
}
else
{
inputInterruptConfig.cardIndex = 0;
check_status( naibrd_AR_SetInterruptSteering( inputInterruptConfig.cardIndex, inputARConfig.module, inputARConfig.channel, NAIBRD_INT_STEERING_ON_BOARD_0 ) );
check_status( naibrd_InstallISR( inputInterruptConfig.cardIndex, NAIBRD_IRQ_ID_ON_BOARD_0, (nai_isr_t)IntOffboardIsr, (void*)&inputARConfig.cardIndex ) );
}
/**** 3. configure Module to perform interrupts ****/
configureARToInterruptOnRxMultiChan( inputInterruptConfig, inputARConfig );
/**** 4. Configure Module to cause Interrupts ****/
Cfg_Rx_AR( inputARConfig );
/**** Initialize Message Queue ****/
InitInterruptAppThread( ONBOARD_INT, 0 );
nai_msDelay( 10 );
UpdateThreadState( RUN );
/**** Enable Interrupts ****/
enableARInterrupts( inputARConfig, AR_RX_DATA_AVAIL );
/*** 5. Show Interrupt Handling (contains step 6) ***/
arIntProcessFunc = handleARInterrupt;
/*** Request user triggers interrupt ***/
DisplayMessage_ARInterrupt( MSG_BANNER_AR_INT );
DisplayMessage_ARInterrupt( MSG_USER_TRIGGER_AR_INT );
/**** Wait on program threads ****/
while ( !isThreadStateTerminated() )
{
}
bQuit = TRUE;
if ( !inputInterruptConfig.displayData )
fclose( fifoDataFile );
/***** 7. Clear Module Configurations *****/
enableARInterrupts( inputARConfig, FALSE );
for ( chan = inputARConfig.minChannel; chan <= inputARConfig.maxChannel; chan++ )
{
check_status( naibrd_AR_SetRxEnable( inputARConfig.cardIndex, inputARConfig.module, chan, FALSE ) );
check_status( naibrd_AR_ClearStatus( inputARConfig.cardIndex, inputARConfig.module, chan, 0xFFFF ) );
}
/***** 8. Clear Board Configurations *****/
check_status( naibrd_UninstallISR( inputInterruptConfig.cardIndex ) );
}
return bQuit;
}
Full Source — AR_Interrupt_Ethernet.c (SSK 1.x)
/**************************************************************************************************************/
/**
<summary>
The AR_Interrupt_Ethernet program demonstrates how to perform an interrupt when a single channel receives
an ar message. The purpose of this program is to demonstrate the method calls in the naibrd library for performing
the interrupt. More information on this process can be found in the naibrd SSK Quick Guide (Interrupts) file.
</summary>
*/
/**************************************************************************************************************/
/************************/
/* Include Declarations */
/************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
/* Common Module Specific Sample Program include files */
#include "nai_ar_int_ether.h"
#include "nai_ar_int.h"
#include "nai_ar_cfg.h"
/* Common Sample Program include files */
#include "include/naiapp_interrupt.h"
#include "include/naiapp_interrupt_ether.h"
#include "include/naiapp_boardaccess_menu.h"
#include "include/naiapp_boardaccess_query.h"
#include "include/naiapp_boardaccess_access.h"
#include "include/naiapp_boardaccess_display.h"
#include "include/naiapp_boardaccess_utils.h"
/* naibrd include files */
#include "nai.h"
#include "naibrd.h"
/* Module Specific NAI Board Library files */
#include "functions/naibrd_ar.h"
#include "maps/nai_map_ar.h"
static uint8_t DEF_RX_RESPONSE_IPv4_ADDR[] = {192,168,1,100};
static uint8_t COMMANDS[MAX_ETHER_IDR_CMD_CNT*MAX_ETHER_BLOCK_REG_CNT];
InterruptConfig inputInterruptConfig;
IDRConfig inputIDRConfig;
ClearInterrupt AR_ClearInterrupt;
etherIntFuncDef arEtherIntFunc;
bool_t bDisplayEtherUPR;
/* Extern Functions or Variables*/
extern ArConfig inputARConfig;
extern FILE* fifoDataFile;
/*********************************************/
/* Application Name and Revision Declaration */
/*********************************************/
static const int8_t *CONFIG_FILE = (int8_t *)"default_AR_Interrupt_Ethernet.txt";
/********************************/
/* Internal Function Prototypes */
/********************************/
static bool_t Run_AR_Interrupt_Basic_Ethernet();
/**************************************************************************************************************/
/***** Main Routine *****/
/**************************************************************************************************************/
/**************************************************************************************************************/
/**
<summary>
The main routine assists in gaining access to the board.
The following routines from the nai_sys_cfg.c file are
called to assist with accessing and configuring the board.
- ConfigDevice
- DisplayDeviceCfg
- GetBoardSNModCfg
- CheckModule
</summary>
*/
/*****************************************************************************/
#if defined (__VXWORKS__)
int32_t AR_Interrupt_Basic_Ethernet(void)
#else
int32_t main(void)
#endif
{
bool_t stop = FALSE;
int32_t cardIndex;
int32_t moduleCnt;
int32_t module;
int8_t inputBuffer[80];
int32_t inputResponseCnt;
initializeARConfigurations( 0, 0, 0, 0, 0, 0, MAX_FIFO_COUNT, DEF_AR_TIMESTAMP, FALSE);
initializeInterruptConfigurations(FALSE,FALSE,FALSE,0,0,0,0);
initializeIDRConfigurations(0,0,DEF_RX_RESPONSE_PROTOCOL,DEF_RX_RESPONSE_PORT,
DEF_RX_RESPONSE_IPv4_ADDR, DEF_RX_RESPONSE_IPv4_LENGTH,
COMMANDS,0,ETHERNET_OVERHEAD_FIFO_COMMAND,DEF_ETHERNET_AR_IDR_ID);
if (naiapp_RunBoardMenu(CONFIG_FILE) == TRUE)
{
while (stop != TRUE)
{
/* Query the user for the card index */
stop = naiapp_query_CardIndex(naiapp_GetBoardCnt(), 0, &cardIndex);
inputARConfig.cardIndex = cardIndex;
if (stop != TRUE)
{
check_status(naibrd_GetModuleCount(cardIndex, &moduleCnt));
/* Query the user for the module number */
stop = naiapp_query_ModuleNumber(moduleCnt, 1, &module);
inputARConfig.module = module;
if (stop != TRUE)
{
inputARConfig.modid = naibrd_GetModuleID(cardIndex, module);
if ((inputARConfig.modid != 0))
{
Run_AR_Interrupt_Basic_Ethernet();
}
}
}
printf("\nType Q to quit or Enter key to restart application:\n");
stop = naiapp_query_ForQuitResponse(sizeof(inputBuffer), NAI_QUIT_CHAR, inputBuffer, &inputResponseCnt);
}
}
printf("\nType the Enter key to exit the program: ");
naiapp_query_ForQuitResponse(sizeof(inputBuffer), NAI_QUIT_CHAR, inputBuffer, &inputResponseCnt);
naiapp_access_CloseAllOpenCards();
return 0;
}
/**************************************************************************************************************/
/**
<summary>
This function is broken into the following major steps. These steps correspond with the steps provided
in the naibrd SSK Quick Guide (Interrupts) file.
2a. Ethernet Interrupt Handling - Setup IDR to handle interrupt
API CALLS - naibrd_Ether_SetIDRConfig, naibrd_Ether_StartIDR, naibrd_Ether_ClearIDRConfig
3. Enable Module Interrupts- Configures module to interrupt when channel receives AR message.
API CALLS - naibrd_AR_SetInterruptEdgeLevel, naibrd_AR_SetIntVector, naibrd_AR_SetInterruptSteering, naibrd_AR_SetIntEnable
4. Configure Module to Cause Rx Interrupt - sets the BAUD Rate to 1mbit/s (AR AB) or 500k bits/s (AR J1939) as defined in nai_ar_cfg.h
It also enables the particular channel on the module to receive ARINC messages
API CALLS - naibrd_AR_SetBitTiming , naibrd_AR_SetRxEnable
5. Show Interrupt Handling - The IDR server will listen on the boards ports for IDRs indicating an interrupt.
These results will be decoded and displayed to the user.
6. Re-arming Interrupts - Clear the status register to allow interrupts to occur again. This is done by writing to the status register.
In this program, the write command is included in the IDR.
API CALLS - nai_ether_BeginWriteMessage, nai_ether_WriteMessageData, nai_ether_FinishMessage
7. Clear Module Configurations
API CALLS - naibrd_AR_SetRxEnable, naibrd_AR_ClearStatus
8. Clear Board Configurations
API CALLS - naibrd_Ether_StopIDR, naibrd_Ether_ClearIDRConfig
</summary>
*/
/**************************************************************************************************************/
static bool_t Run_AR_Interrupt_Basic_Ethernet()
{
bool_t bQuit = FALSE;
bool_t bGen4ArIDRCommands;
inputARConfig.maxChannel = naibrd_AR_GetChannelCount( inputARConfig.modid );
inputARConfig.minChannel = 1;
/* check if AR module supports GEN 4 Ethernet */
bGen4ArIDRCommands = SupportsGen4Ether( inputARConfig.cardIndex );
if ( !bGen4ArIDRCommands )
{
printf( "AR Ethernet Interrupt Support Prior to Generation 4 Ethernet commands currently not supported\n" );
bQuit = TRUE;
}
if (!bQuit)
{
bQuit = naiapp_query_ChannelNumber( inputARConfig.maxChannel, inputARConfig.minChannel, &inputARConfig.channel );
}
/* Query user for Trigger Status of interrupts */
if (!bQuit)
{
bQuit = GetARLatchStatusTriggerMode( &inputInterruptConfig.interrupt_Edge_Trigger );
}
if (!bQuit)
{
bQuit = QueryIDRConfigInformation( &inputIDRConfig );
}
if (!bQuit)
{
bQuit = QueryUserForOnboardOffboardInterrupts( &inputInterruptConfig.bProcessOnboardInterrupts );
}
if (!bQuit)
{
bQuit = QueryUserForEtherIDRMsgDisplay( &bDisplayEtherUPR );
}
if (!bQuit)
{
bQuit = QueryUserForDisplayingData( &inputInterruptConfig.displayData );
}
if (!bQuit)
{
bQuit = QueryUserForTimeStampEnable( &inputARConfig.timeStampEnable );
}
if (!bQuit)
{
if ( inputInterruptConfig.displayData )
fifoDataFile = stdout;
else
fifoDataFile = fopen( "AR_Interrupt_FIFO_Data.txt", "w+" );
/**** 2. Setup IDR to Handle Interrupt (also contains step 6) ****/
if ( inputInterruptConfig.bProcessOnboardInterrupts == TRUE )
{
inputIDRConfig.cardIndex = inputARConfig.cardIndex;
inputIDRConfig.boardInterface = NAI_INTF_ONBOARD;
inputInterruptConfig.steering = NAIBRD_INT_STEERING_ON_BOARD_1;
}
else /* OffBoard Interrupt */
{
inputIDRConfig.cardIndex = 0;
inputIDRConfig.boardInterface = NAI_INTF_PCI;
inputInterruptConfig.steering = NAIBRD_INT_STEERING_CPCI_APP;
}
setupIDRConfiguration_AR( inputARConfig, &inputIDRConfig, bGen4ArIDRCommands );
check_status( naibrd_Ether_StartIDR( inputIDRConfig.cardIndex, (uint16_t)DEF_ETHERNET_AR_IDR_ID ) );
/**** 3. configure module To Interrupt ****/
configureARToInterruptOnRx( inputInterruptConfig, inputARConfig );
enableARInterrupts( inputARConfig, AR_RX_DATA_AVAIL );
/**** 4. Configure AR to cause Interrupts ****/
Cfg_Rx_AR( inputARConfig );
/**** 5. Show Interrupt Handling ****/
AR_ClearInterrupt = ClearInterrupt_AR;
arEtherIntFunc = HandleAREtherInterrupt;
bQuit = runIDRServer( inputIDRConfig );
/***** 7. Clear Module Configurations *****/
check_status( naibrd_AR_SetRxEnable( inputARConfig.cardIndex, inputARConfig.module, inputARConfig.channel, FALSE ) );
enableARInterrupts( inputARConfig, FALSE );
/***** 8. Clear Board Configurations *****/
check_status( naibrd_Ether_StopIDR( inputIDRConfig.cardIndex, (uint16_t)DEF_ETHERNET_AR_IDR_ID ) );
check_status( naibrd_Ether_ClearIDRConfig( inputIDRConfig.cardIndex, DEF_ETHERNET_AR_IDR_ID ) );
}
return bQuit;
}
Full Source — nai_ar_int.c (SSK 1.x)
/* Common Sample Program include files */
#include "include/naiapp_interrupt.h"
#include "include/naiapp_interrupt_ether.h"
#include "include/naiapp_boardaccess_query.h"
#include "include/naiapp_boardaccess_access.h"
#include "include/naiapp_boardaccess_display.h"
#include "include/naiapp_boardaccess_utils.h"
/* Common AR Sample Program include files */
#include "nai_ar_int.h"
#include "nai_ar_cfg.h"
/* naibrd include files */
#include "nai.h"
#include "naibrd.h"
#include "naibrd_ether.h"
#include "functions/naibrd_ar.h"
#include "maps/nai_map_ar.h"
#include <stdlib.h>
bool_t interruptOccured; /* used by checkForInterrupt to see if interrupt occurred */
int32_t frameCount; /* counter increment when frames are found */
uint32_t interruptVector; /* used by checkForInterrupt to get vector of the interrupt that occurred in myIsr */
FIFO fifo12Chans[NAI_GEN5_AR_MAX_CHANNEL_COUNT];
/* Extern Functions or Variables*/
extern InterruptConfig inputInterruptConfig;
extern ArConfig inputARConfig;
extern FILE* fifoDataFile;
/***********************/
/* Function Prototypes */
/***********************/
void promptUserToClearInterrupt_AR();
/**************************************************************************************************************/
/**
<summary>
Prompts user to check if an interrupt has occurred. MyIsr() should be installed if using this function.
</summary>
*/
/**************************************************************************************************************/
bool_t checkForARInterrupt( ArConfig inputARConfig )
{
bool_t bQuit;
int32_t cardIndex;
int32_t module;
int32_t channel;
nai_ar_status_t status;
int32_t count;
int32_t i;
uint32_t fifoLength;
int32_t maxFifoLength;
uint16_t msgStatus;
uint32_t msgData;
uint32_t msgTStamp;
uint32_t statArr[NAI_AR_MAX_DATA_LEN];
uint32_t dataArr[NAI_AR_MAX_DATA_LEN];
uint32_t tstampArr[NAI_AR_MAX_DATA_LEN];
int32_t outnummsgs;
int8_t inputBuffer[80];
int32_t inputResponseCnt;
cardIndex = inputARConfig.cardIndex;
module = inputARConfig.module;
channel = inputARConfig.channel;
status = 0;
bQuit = FALSE;
interruptOccured = FALSE;
while (!bQuit)
{
printf( "\nPress enter to check if interrupt Occurred (press Q to quit):" );
bQuit = naiapp_query_ForQuitResponse( sizeof(inputBuffer), NAI_QUIT_CHAR, inputBuffer, &inputResponseCnt );
if (!bQuit)
{
if (interruptOccured)
{
naibrd_Wait( 1000000 );
check_status( naibrd_AR_GetStatus( inputARConfig.cardIndex, inputARConfig.module, inputARConfig.channel, NAI_AR_STATUS_LATCHED, &status ) );
check_status( naibrd_AR_GetRxBufferCnt( cardIndex, module, channel, &count ) );
check_status( naibrd_AR_ReadFifo( cardIndex, module, channel, inputARConfig.timeStampEnable, count, statArr, dataArr, tstampArr, &outnummsgs ) );
printf( "\nVector = %#x \n", interruptVector );
printf( "Status = %#x \n\n", status );
maxFifoLength = NAI_AR_MAX_DATA_LEN;
fifoLength = count;
printf( "Max FIFO Word Count: %d\n", maxFifoLength );
printf( "Messages Received (FIFO Word Count): %d\n", fifoLength );
if ( count == 1 )
{
msgStatus = (uint16_t)statArr[0];
msgData = dataArr[0];
msgTStamp = tstampArr[0];
printf( "\n" );
printf( "Message Status: %#x", msgStatus );
printf( "\n" );
printf( "Message Data: %#x", msgData );
printf( "\n" );
printf( "Time Stamp: %#x", msgTStamp );
printf( "\n\n" );
}
else if ( count > 1 )
{
for ( i = 0; i < count; i++ )
{
printf( "\nMessage Number %d:", i + 1 );
msgStatus = (uint16_t)statArr[i];
msgData = dataArr[i];
msgTStamp = tstampArr[i];
printf( "\n" );
printf( "Message Status: %#x", msgStatus );
printf( "\n" );
printf( "Message Data: %#x", msgData );
printf( "\n" );
printf( "Time Stamp: %#x", msgTStamp );
printf( "\n\n" );
}
}
else if ( count < 1 )
{
printf( "ERROR! naibrd_AR_GetRxBufferCnt returned an invalid value." );
}
interruptOccured = FALSE;
}
else
{
printf( "\nNo Interrupt Occurred" );
}
printf( "\n\nWould you like to clear the status register? (default:Y):" );
bQuit = naiapp_query_ForQuitResponse( sizeof(inputBuffer), NAI_QUIT_CHAR, inputBuffer, &inputResponseCnt );
if ( inputBuffer[0] == 'y' || inputBuffer[0] =='Y' || inputResponseCnt == 0 )
{
check_status( naibrd_AR_ClearStatus( inputARConfig.cardIndex, inputARConfig.module, inputARConfig.channel, 0xFFFF ) );
}
}
}
return bQuit;
}
/**************************************************************************************************************/
/**
<summary>
This function configures an interrupt to occur when a message is received on the AR channel specified by the
user.
</summary>
*/
/**************************************************************************************************************/
void configureARToInterruptOnRx( InterruptConfig inputInterruptConfig, ArConfig inputARConfig )
{
int32_t cardIndex = inputARConfig.cardIndex;
int32_t module = inputARConfig.module;
int32_t channel = inputARConfig.channel;
int32_t vector = NAI_AR_INTERRUPT_VECTOR;
int32_t interrupt_Edge_Trigger = inputInterruptConfig.interrupt_Edge_Trigger;
int32_t steering = inputInterruptConfig.steering;
/* clear interruptConfigs of previous channels */
check_status( naibrd_AR_SetInterruptEnable( cardIndex, module, channel, 0 ) );
check_status( naibrd_AR_ClearStatus( cardIndex, module, channel, 0xFFFF ) );
check_status( naibrd_AR_SetInterruptVector( cardIndex, module, channel, vector ) );
check_status( naibrd_AR_SetInterruptEdgeLevel( cardIndex, module, channel, interrupt_Edge_Trigger ) ); /* Edge triggered */
check_status( naibrd_AR_SetInterruptSteering( cardIndex, module, channel, steering ) );
}
/**************************************************************************************************************/
/**
<summary>
This function configures an interrupt to occur when a message is received on any of the AR channels specified.
</summary>
*/
/**************************************************************************************************************/
void configureARToInterruptOnRxMultiChan( InterruptConfig inputInterruptConfig, ArConfig inputARConfig )
{
int32_t idxChan;
int32_t cardIndex = inputARConfig.cardIndex;
int32_t module = inputARConfig.module;
int32_t minChan = inputARConfig.minChannel;
int32_t maxChan = inputARConfig.maxChannel;
int32_t vector = NAI_AR_INTERRUPT_VECTOR;
int32_t interrupt_Edge_Trigger = inputInterruptConfig.interrupt_Edge_Trigger;
int32_t steering = inputInterruptConfig.steering;
/* clear interruptConfigs of previous channels */
for ( idxChan = minChan; idxChan <= maxChan; idxChan++ )
{
check_status( naibrd_AR_SetInterruptEnable( cardIndex, module, idxChan, 0 ) );
check_status( naibrd_AR_ClearStatus( cardIndex, module, idxChan, 0xFFFF ) );
check_status( naibrd_AR_SetInterruptVector( cardIndex, module, idxChan, vector ) );
check_status( naibrd_AR_SetInterruptEdgeLevel( cardIndex, module, idxChan, interrupt_Edge_Trigger ) ); /* Edge triggered */
check_status( naibrd_AR_SetInterruptSteering( cardIndex, module, idxChan, steering ) );
}
}
/**************************************************************************************************************/
/**
<summary>
DisplayMessage_ARInterrupt handles displaying the messages associated with the msgId passed in.
</summary>
*/
/**************************************************************************************************************/
void DisplayMessage_ARInterrupt( int32_t msgId )
{
switch (msgId)
{
case (int32_t)MSG_BANNER_AR_INT:
{
printf( "\n********************************************************************************" );
printf( "\n****** AR INTERRUPT ******" );
printf( "\nAn interrupt will occur when the AR module receives a message " );
printf( "\n********************************************************************************" );
}
break;
case (int32_t)MSG_USER_TRIGGER_AR_INT:
{
printf( "\nPress \"Q\" to quit the application.\nPlease trigger AR interrupt (Recv Msg):" );
}
break;
case (int32_t)MSG_USER_CLEAR_AR_INT:
{
printf( "Press \"C\" to clear interrupts... " );
}
break;
}
}
/**************************************************************************************************************/
/**
<summary>
Enables the channels within the (minChannel, maxChannel) range to interrupt
if enable is true and disables them otherwise.
</summary>
*/
/**************************************************************************************************************/
void enableARInterrupts( ArConfig inputARConfig, bool_t enable )
{
int32_t channel = inputARConfig.channel;
int32_t idxChan;
if ( channel == 0 )
{
for ( idxChan = 1; idxChan <= inputARConfig.maxChannel; idxChan++ )
{
check_status( naibrd_AR_SetInterruptEnable( inputARConfig.cardIndex, inputARConfig.module, idxChan, enable ) );
}
}
else
{
check_status( naibrd_AR_SetInterruptEnable( inputARConfig.cardIndex, inputARConfig.module, inputARConfig.channel, enable ) );
}
}
/**************************************************************************************************************/
/**
<summary>
GetARLatchStatusTriggerMode handles prompting the user for the trigger mode for the latched status register
(Edge Triggered or Level Triggered).
</summary>
*/
/**************************************************************************************************************/
bool_t GetARLatchStatusTriggerMode( int32_t* interrupt_Edge_Trigger )
{
bool_t bQuit;
uint32_t temp;
int8_t inputBuffer[80];
int32_t inputResponseCnt;
printf( "\nEnter Latched Status Trigger Mode (Edge=0, Level=1) (Default=1): " );
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 )
{
*interrupt_Edge_Trigger = temp;
}
else
{
printf( "ERROR: Invalid Interrupt Trigger Mode.\n" );
}
}
else
*interrupt_Edge_Trigger = 1;
}
return( bQuit );
}
/**************************************************************************************************************/
/**
<summary>
The routine is called to handle a interrupt. This function alerts checkForInterrupt that an interrupt has occurred.
In vxWorks you must clear the Interrupt on the board within the ISR.
</summary>
*/
/**************************************************************************************************************/
#if defined (__VXWORKS__)
void basic_ISR_AR( uint32_t param )
#else
void basic_ISR_AR( void *param, uint32_t vector )
#endif
{
interruptOccured = TRUE;
#if defined (WIN32)
UNREFERENCED_PARAMETER( param );
#endif
#if defined (__VXWORKS__)
interruptVector = nai_Onboard_GetInterruptVector();
nai_Onboard_ClearInterrupt();
#else
interruptVector = vector;
#endif
}
/**************************************************************************************************************/
/**
<summary>
This routine takes in the vector of the AR RX interrupt that has just occurred. And gets the status, fifo status,
and fifo data of all channels that interrupted, and prints it.
</summary>
*/
/**************************************************************************************************************/
void handleARInterrupt( uint32_t nVector )
{
static uint32_t status[NAI_GEN5_AR_MAX_CHANNEL_COUNT + 1];
static FIFO fifoArrayToPrint[NAI_GEN5_AR_MAX_CHANNEL_COUNT + 1];
int32_t index;
int32_t idxChan;
int32_t minChan;
int32_t maxChan;
int32_t outnummsgs;
int32_t pathDeterminant;
int32_t bufferCountsArray[NAI_GEN5_AR_MAX_CHANNEL_COUNT + 1];
uint32_t mask = AR_RX_DATA_AVAIL;
uint32_t statusMasked;
uint32_t statArr[NAI_AR_MAX_DATA_LEN];
uint32_t dataArr[NAI_AR_MAX_DATA_LEN];
uint32_t tstampArr[NAI_AR_MAX_DATA_LEN];
minChan = inputARConfig.minChannel;
maxChan = inputARConfig.maxChannel;
pathDeterminant = maxChan - minChan;
naibrd_Wait( 1000000 );
if ( pathDeterminant >= 0 )
{
for ( idxChan = minChan; idxChan <= maxChan; idxChan++ )
{
check_status( naibrd_AR_GetStatus( inputARConfig.cardIndex, inputARConfig.module, idxChan, NAI_AR_STATUS_LATCHED, &status[idxChan] ) );
statusMasked = status[idxChan] & mask;
if ( statusMasked == mask )
{
int32_t outcount;
fifoArrayToPrint[idxChan].maxDataLength = NAI_AR_MAX_DATA_LEN;
check_status( naibrd_AR_GetRxBufferCnt( inputARConfig.cardIndex, inputARConfig.module, idxChan, &outcount ) );
check_status( naibrd_AR_ReadFifo( inputARConfig.cardIndex, inputARConfig.module, idxChan, inputARConfig.timeStampEnable, bufferCountsArray[idxChan], statArr, dataArr, tstampArr, &outnummsgs ) );
for ( index = 0; index < outcount; index++ )
{
fifoArrayToPrint[idxChan].data[index].fifoData = dataArr[index];
fifoArrayToPrint[idxChan].data[index].fifoStatus = (uint16_t)statArr[index];
fifoArrayToPrint[idxChan].data[index].fifoTimeStamp = tstampArr[index];
}
fifoArrayToPrint[idxChan].length = bufferCountsArray[idxChan] = outcount;
}
}
}
else if ( pathDeterminant < 0 )
{
printf( "ERROR! Min Channel is greater than Max Channel" );
}
printf( "\nInterrupt Occurred\n" );
if ( inputInterruptConfig.bPromptForInterruptClear == TRUE )
{
promptUserToClearInterrupt_AR();
}
for ( idxChan = minChan; idxChan <= maxChan; idxChan++ )
{
check_status( naibrd_AR_ClearStatus( inputARConfig.cardIndex, inputARConfig.module, idxChan, 0xFFFF ) );
}
printInterruptInformation_AR( nVector, status, fifoDataFile, bufferCountsArray, fifoArrayToPrint );
}
/**************************************************************************************************************/
/**
<summary>
Function will print the fifoData provided for each channel that has been set in the status register.
It will also print the status and idr id or vector.
</summary>
*/
/**************************************************************************************************************/
void printInterruptInformation_AR( int32_t interruptID, uint32_t* statuses, FILE* stream, int32_t* counts, FIFO* fifos )
{
uint8_t dataAvailStatus;
int32_t interruptChannels[NAI_GEN5_AR_MAX_CHANNEL_COUNT + 1];
uint16_t fifoElementStatus;
uint32_t fifoElementData;
uint32_t fifoElementTimeStamp;
uint32_t fifoLength;
int32_t maxFifoLength;
int32_t i;
int32_t j;
for ( i = 1; i <= NAI_GEN5_AR_MAX_CHANNEL_COUNT; i++ )
{
dataAvailStatus = statuses[i] & AR_RX_DATA_AVAIL;
if ( dataAvailStatus == 1 )
{
interruptChannels[i] = i;
}
else
{
interruptChannels[i] = 0;
}
}
for ( i = 1; i <= NAI_GEN5_AR_MAX_CHANNEL_COUNT; i++ )
{
if ( interruptChannels[i] > 0 )
{
fprintf( stream, "Interrupt Information\n" );
fprintf( stream, "-----------------------------------\n" );
fprintf( stream, "\nInterrupt Channel = %d \n", i );
fprintf( stream, "IDR ID = %#x \n", interruptID );
fprintf( stream, "Status = %#x \n", statuses[i] );
dataAvailStatus = statuses[i] & AR_RX_DATA_AVAIL;
if (dataAvailStatus)
{
if ( counts[i] == 1 )
{
fifoElementStatus = fifos[i].data[0].fifoStatus;
fifoElementData = fifos[i].data[0].fifoData;
fifoElementTimeStamp = fifos[i].data[0].fifoTimeStamp;
fprintf( stream, "\n" );
fprintf( stream, "Message Status: %#x", fifoElementStatus );
fprintf( stream, "\n" );
fprintf( stream, "Message Data: %#x", fifoElementData );
fprintf( stream, "\n" );
fprintf( stream, "Time Stamp: %#x", fifoElementTimeStamp );
fprintf( stream, "\n\n" );
}
else if ( counts[i] > 1 )
{
fifoLength = fifos[i].length;
maxFifoLength = fifos[i].maxDataLength;
fprintf( stream, "\nMax FIFO Word Count: %d\n", maxFifoLength );
fprintf( stream, "Messages Received (FIFO Word Count): %d\n", fifoLength );
for ( j = 0; j < counts[i]; j++ )
{
fprintf( stream, "\nMessage Number %d:", j+1 );
fifoElementStatus = fifos[i].data[j].fifoStatus;
fifoElementData = fifos[i].data[j].fifoData;
fifoElementTimeStamp = fifos[i].data[j].fifoTimeStamp;
fprintf( stream, "\n" );
fprintf( stream, "Message Status: %#x", fifoElementStatus );
fprintf( stream, "\n" );
fprintf( stream, "Message Data: %#x", fifoElementData );
fprintf( stream, "\n" );
fprintf( stream, "Time Stamp: %#x", fifoElementTimeStamp );
fprintf( stream, "\n\n" );
}
}
else if ( counts[i] < 1 )
{
fprintf( stream, "ERROR! naibrd_AR_GetRxBufferCnt returned an invalid value." );
}
}
fprintf( stream, "\n-----------------------------------\n" );
}
}
}
void promptUserToClearInterrupt_AR()
{
/* Prompt the user to clear the interrupt received */
SetUserRequestClearInt( FALSE );
printf( "\n" );
DisplayMessage_ARInterrupt( MSG_USER_CLEAR_AR_INT );
/* Wait for the user to respond */
while ( !GetUserRequestClearInt() )
{
nai_msDelay( 10 );
}
}
/**************************************************************************************************************/
/**
<summary>
QueryUserForTimeStampEnable handles querying the user to see if he wants time stamps to be enabled and
included in AR messages. If the user specifies 'N', time stamping will be disabled, else time stamping will
be enabled.
</summary>
*/
/**************************************************************************************************************/
bool_t QueryUserForTimeStampEnable( bool_t* tstampEnable )
{
bool_t bQuit = FALSE;
int8_t inputBuffer[80];
int32_t inputResponseCnt;
/* Query the user to determine if he wants time stamps to be included in AR messages */
printf( "\nWould you like to enable time stamping for messages received? (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' ) )
{
*tstampEnable = FALSE;
}
else
{
*tstampEnable = TRUE;
}
}
else
{
*tstampEnable = TRUE;
}
}
return bQuit;
}
void ClearInterrupt_AR()
{
uint32_t status;
if (inputInterruptConfig.bPromptForInterruptClear)
{
promptUserToClearInterrupt_AR();
}
naibrd_AR_GetStatus( inputARConfig.cardIndex, inputARConfig.module, inputARConfig.channel, NAI_AR_STATUS_LATCHED, &status );
naibrd_AR_ClearStatus( inputARConfig.cardIndex, inputARConfig.module, inputARConfig.channel, status );
}
Full Source — nai_ar_int_ether.c (SSK 1.x)
/* Common Sample Program include files */
#include "include/naiapp_interrupt.h"
#include "include/naiapp_interrupt_ether.h"
#include "include/naiapp_boardaccess_menu.h"
#include "include/naiapp_boardaccess_query.h"
#include "include/naiapp_boardaccess_access.h"
#include "include/naiapp_boardaccess_display.h"
#include "include/naiapp_boardaccess_utils.h"
/* Common AR Sample Program include files */
#include "nai_ar_int_ether.h"
#include "nai_ar_cfg.h"
/* naibrd include files */
#include "functions/naibrd_ar.h"
#include "maps/nai_map_ar.h"
#include "advanced/nai_ether_adv.h"
int32_t command_index_interrupt_status;
/* Extern Functions or Variables*/
extern IDRConfig inputIDRConfig;
extern ArConfig inputARConfig;
extern FILE* fifoDataFile;
/**************************************************************************************************************/
/**
<summary>
Constructs the ethernet commands that are part of the IDR. Configures the IDR on the board.
</summary>
*/
/**************************************************************************************************************/
void setupIDRConfiguration_AR( ArConfig inputARConfig, IDRConfig* inputIDRConfig, bool_t bGen4ArIDRCommands )
{
int32_t cardIndex = inputIDRConfig->cardIndex;
uint16_t protocol = inputIDRConfig->protocol;
uint16_t port = inputIDRConfig->port;
uint8_t* ipAddress = inputIDRConfig->ipAddress;
uint8_t ipLength = inputIDRConfig->ipLength;
int32_t vector = NAI_AR_INTERRUPT_VECTOR;
uint8_t *commands = inputIDRConfig->commands;
uint16_t *cmdcount = &inputIDRConfig->cmdcount;
uint16_t *cmdlength = &inputIDRConfig->cmdlength;
check_status( naibrd_Ether_ClearIDRConfig( cardIndex, (uint16_t)DEF_ETHERNET_AR_IDR_ID ) );
InitARRxIDRCommands( inputARConfig, inputIDRConfig, bGen4ArIDRCommands );
check_status( naibrd_Ether_SetIDRConfig( cardIndex, (uint16_t)DEF_ETHERNET_AR_IDR_ID, protocol, ipLength, ipAddress, port, vector, *cmdcount, *cmdlength, commands ) );
}
/**************************************************************************************************************/
/**
<summary>
This function configures the IDR (Interrupt Driven Response) commands when a AR Rx interrupt occurs.
There are four Ethernet commands that will be processed by the board when a AR Rx interrupt occurs.
</summary>
*/
/**************************************************************************************************************/
void InitARRxIDRCommands( ArConfig inputARConfig, IDRConfig* inputIDRConfig, bool_t bGen4ArIDRCommands )
{
nai_status_t status = NAI_SUCCESS;
uint16_t msgIndex = 0;
uint32_t boardAddress;
uint32_t moduleOffset;
boardAddress = 0;
status = check_status( naibrd_GetModuleOffset( inputARConfig.cardIndex, inputARConfig.module, &moduleOffset ) );
if ( status == NAI_SUCCESS )
status = check_status( naibrd_GetAddress( inputARConfig.cardIndex, &boardAddress ) );
if ( status == NAI_SUCCESS )
{
if ( bGen4ArIDRCommands )
{
msgIndex = inputIDRConfig->cmdlength;
MakeARRxReadRegsCommand( inputARConfig, inputIDRConfig, boardAddress, moduleOffset, bGen4ArIDRCommands, msgIndex );
}
}
}
/**************************************************************************************************************/
/**
<summary>
This function constructs an ethernet read reg command and stores it in the IDR Configuration. The read will be performed
on the modules latched status interrupt register.
</summary>
*/
/**************************************************************************************************************/
void MakeARRxReadRegsCommand( ArConfig inputARConfig, IDRConfig* inputIDRConfig, uint32_t boardAddress, int32_t moduleOffset, bool_t bGen4Ether, uint16_t startIndex )
{
uint32_t AR_GEN5_LatchedIntStatusAddr[] = NAI_AR_GEN5_REG_CH_LATCHED_INT_STATUS_ADD;
uint16_t msgIndex = startIndex;
uint16_t seqno;
uint32_t count, stride;
uint32_t regaddr;
if (bGen4Ether)
{
seqno = 0;
regaddr = boardAddress + moduleOffset + AR_GEN5_LatchedIntStatusAddr[inputARConfig.channel-1];
count = 1;
stride = 4;
msgIndex = (uint16_t)nai_ether_MakeReadMessage( &inputIDRConfig->commands[startIndex], seqno, NAI_ETHER_GEN4, (nai_intf_t)inputIDRConfig->boardInterface, regaddr, stride, count, NAI_REG32 );
inputIDRConfig->cmdlength = inputIDRConfig->cmdlength + msgIndex;
command_index_interrupt_status = inputIDRConfig->cmdcount;
inputIDRConfig->cmdcount++;
}
}
/**************************************************************************************************************/
/**
<summary>
This function constructs an ethernet write reg command and stores it in the IDR Configuration. The write will be performed
on the modules latched status interrupt register. The purpose of this write is to clear the interrupt status register and re-arm the interrupts
after one has occurred.
</summary>
*/
/**************************************************************************************************************/
void MakeARRxWriteRegsCommand( ArConfig inputARConfig, IDRConfig* inputIDRConfig, uint32_t boardAddress, int32_t moduleOffset, bool_t bGen4Ether, uint16_t startIndex )
{
uint32_t AR_GEN5_LatchedIntStatusAddr[] = NAI_AR_GEN5_REG_CH_LATCHED_INT_STATUS_ADD;
uint16_t msgIndex = startIndex;
uint16_t seqno;
uint32_t count, stride;
uint32_t regaddr;
uint32_t data = 0xFFFF; /* Clear Rx interrupt bits */
if (bGen4Ether)
{
seqno = 0;
regaddr = moduleOffset + boardAddress + AR_GEN5_LatchedIntStatusAddr[inputARConfig.channel-1];
count = 1;
stride = 4;
msgIndex = (uint16_t)nai_ether_BeginWriteMessage( &inputIDRConfig->commands[startIndex], seqno, NAI_ETHER_GEN4, (nai_intf_t)inputIDRConfig->boardInterface, regaddr, stride, count, NAI_REG32 );
if ( msgIndex >= 0 )
{
msgIndex = (uint16_t)nai_ether_WriteMessageData( &inputIDRConfig->commands[startIndex], msgIndex, NAI_REG32, &data, NAI_REG32, count );
if ( msgIndex >= 0 )
{
msgIndex = (uint16_t)nai_ether_FinishMessage( &inputIDRConfig->commands[startIndex], msgIndex, NAI_ETHER_GEN4 );
}
}
inputIDRConfig->cmdlength = inputIDRConfig->cmdlength + msgIndex;
inputIDRConfig->cmdcount++;
}
}
/**************************************************************************************************************/
/**
<summary>
Handles interpreting the idr response msgs received for ar data.
displays the IDR ID and status. Also displays the fifo data from the interrupting channel.
Expects to be parsing a message for a SINGLE channel interrupt only.
</summary>
*/
/**************************************************************************************************************/
void HandleAREtherInterrupt( uint16_t msglen, uint8_t msg[], uint16_t tdr_idr_id )
{
static uint32_t status;
static FIFO fifoToPrint;
int32_t index;
uint16_t seq;
nai_ether_typecode_t typeCode;
nai_ether_gen_t gen = NAI_ETHER_GEN4;
int32_t size;
int32_t commandIndex;
int32_t outnummsgs;
int32_t outcount;
uint32_t mask = 0x1;
uint32_t statusMasked;
uint32_t stat[NAI_AR_MAX_DATA_LEN];
uint32_t data[NAI_AR_MAX_DATA_LEN];
uint32_t tstamp[NAI_AR_MAX_DATA_LEN];
nai_ether_DecodeMessageHeader(msg, msglen, &seq, &typeCode, gen, &size);
commandIndex = ( seq & ( 0x0F << 6 ) ) >> 6;
naibrd_Wait( 1000000 );
switch (typeCode)
{
/* Write REG */
case NAI_ETHER_TYPECODE_RSP_COMMAND_COMPLETE_WRITE_4:
break;
/* READ REG */
case NAI_ETHER_TYPECODE_RSP_COMMAND_COMPLETE_READ_4:
if ( inputIDRConfig.cmdcount-1 == commandIndex )
{
status = msg[11];
status = ( status | ( msg[10] << 8 ) );
statusMasked = status & mask;
if ( statusMasked == mask )
{
check_status( naibrd_AR_GetRxBufferCnt( inputARConfig.cardIndex, inputARConfig.module, inputARConfig.channel, &outcount ) );
fifoToPrint.maxDataLength = NAI_AR_MAX_DATA_LEN;
if ( outcount > 0 )
{
check_status( naibrd_AR_ReadFifo( inputARConfig.cardIndex, inputARConfig.module, inputARConfig.channel, inputARConfig.timeStampEnable, outcount, stat, data, tstamp, &outnummsgs ) );
for ( index = 0; index < outcount; index++ )
{
fifoToPrint.data[index].fifoData = data[index];
fifoToPrint.data[index].fifoStatus = (uint16_t)stat[index];
fifoToPrint.data[index].fifoTimeStamp = tstamp[index];
}
fifoToPrint.length = outcount;
}
}
}
else if ( inputIDRConfig.cmdcount == commandIndex )
status = msg[11];
break;
}
if ( commandIndex == inputIDRConfig.cmdcount - 1 )
{
printf( "\nInterrupt Occurred\n" );
printEthernetInterruptInformation( tdr_idr_id, status, fifoDataFile, fifoToPrint.length, fifoToPrint );
}
/* Clear Interrupt Latch */
check_status( naibrd_AR_ClearStatus( inputARConfig.cardIndex, inputARConfig.module, inputARConfig.channel, 0xFFFF ) );
}
/**************************************************************************************************************/
/**
<summary>
Function will print the fifoData provided for each channel that has been set in the status register.
It will also print the status and idr id or vector. This function is used for Ethernet Interrupts only.
</summary>
*/
/**************************************************************************************************************/
void printEthernetInterruptInformation( int32_t interruptID, uint32_t status, FILE* stream, int32_t count, FIFO fifo )
{
uint8_t statusBitSet;
uint16_t fifoElementStatus;
uint32_t fifoElementData;
uint32_t fifoElementTimeStamp;
uint32_t fifoLength;
int32_t maxFifoLength;
int32_t i;
fprintf( stream, "Interrupt Information\n" );
fprintf( stream, "-----------------------------------\n" );
fprintf( stream, "\nIDR ID = %#x \n", interruptID );
fprintf( stream, "Status = %#x \n", status );
statusBitSet = status & AR_RX_DATA_AVAIL;
if ( statusBitSet )
{
if ( count > 0 )
{
fifoLength = fifo.length;
maxFifoLength = fifo.maxDataLength;
fprintf( stream, "\nMax FIFO Word Count: %d\n", maxFifoLength );
fprintf( stream, "Messages Received (FIFO Word Count): %d\n", fifoLength );
for ( i = 0; i < count; i++ )
{
fprintf( stream, "Message Number %d:", i + 1 );
fifoElementStatus = fifo.data[i].fifoStatus;
fifoElementData = fifo.data[i].fifoData;
fifoElementTimeStamp = fifo.data[i].fifoTimeStamp;
fprintf( stream, "\n" );
fprintf( stream, "Message Status: %#x", fifoElementStatus );
fprintf( stream, "\n" );
fprintf( stream, "Message Data: %#x", fifoElementData );
fprintf( stream, "\n" );
fprintf( stream, "Time Stamp: %#x", fifoElementTimeStamp );
fprintf( stream, "\n\n" );
}
}
else if ( count < 0 )
{
fprintf( stream, "ERROR! naibrd_AR_GetRxBufferCnt returned an invalid value." );
}
}
fprintf( stream, "\n-----------------------------------\n" );
}