AR Interrupt Basic
Edit this on GitLab
AR Interrupt Basic Sample Application (SSK 1.x)
Overview
The AR Interrupt Basic sample application demonstrates how to configure ARINC 429 module interrupts to detect BIT (Built-In Test) failures and new message availability using the NAI Software Support Kit (SSK 1.x). ARINC 429 is an avionics data bus standard used for point-to-point communication between aircraft systems. Unlike discrete module interrupts — which monitor voltage levels on individual I/O pins — ARINC 429 interrupts operate at the communication protocol level. They notify your application when the receive FIFO has captured a new ARINC word from the bus or when the hardware’s continuous self-test detects a data path fault.
This distinction is important: a DT interrupt fires because a voltage crossed a threshold or an edge was detected on a wire. An AR interrupt fires because a complete ARINC message arrived in the receive buffer, or because the internal loopback verification detected a mismatch between transmitted and received data. The interrupt sources are fundamentally different — protocol events vs. electrical events — and this affects how you configure, handle, and troubleshoot them.
This sample supports the following AR module types: AR1 (up to 12 channels) and AR2 (2 channels). It also works with combination modules that include ARINC 429 functionality: CM2 (8 AR channels) and CM5 (8 AR channels).
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. Consult your AR module’s manual (AR-01 or equivalent) for BIT timing specifications and FIFO depth details.
Prerequisites
Before running this sample, make sure you have:
-
An NAI board with an ARINC 429 module installed (AR1, AR2, or a combination module such as CM2 or 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 testing RX Available interrupts: an ARINC 429 transmitter connected to the receive channel’s bus (either an external device or another channel on the same module configured for Tx).
How to Run
Launch the AR_Interrupt_Basic executable from your build output directory. On startup the application looks for a configuration file (default_AR_Interrupt_Basic.txt). On the first run, this file will not exist — the application will present an interactive board menu where you configure a board connection, card index, and module slot. You can save this configuration so that subsequent runs skip the menu and connect automatically. Once connected, the application prompts you for a receive channel, trigger mode, steering, and timestamp preferences, then waits 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 ARINC 429. For details on board connection configuration, see the First Time Setup Guide. |
The main() function (or AR_Interrupt_Basic() on VxWorks) follows a standard SSK 1.x startup flow:
-
Initialize default AR and interrupt configuration structures with
initializeARConfigurations()andinitializeInterruptConfigurations(). -
Call
naiapp_RunBoardMenu()to load a saved configuration file or present the interactive board menu. The configuration file (default_AR_Interrupt_Basic.txt) is not included with the SSK — it is created when you save your 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()and, if valid, proceed to interrupt configuration.
#if defined (__VXWORKS__)
int32_t AR_Interrupt_Basic(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)
{
stop = naiapp_query_CardIndex(naiapp_GetBoardCnt(), 0, &cardIndex);
inputARConfig.cardIndex = cardIndex;
if (stop != TRUE)
{
check_status(naibrd_GetModuleCount(cardIndex, &moduleCnt));
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();
}
}
}
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 Basic sample is split across two source files:
-
AR_Interrupt_Basic.c— entry point. Handles board connection, user queries, and orchestrates the interrupt lifecycle (install ISR, configure, wait, clean up). -
nai_ar_int.c— shared ARINC interrupt utilities. Contains the ISR (basic_ISR_AR()), the interrupt configuration function (configureARToInterruptOnRx()), the interrupt enable function (enableARInterrupts()), the polling/check function (checkForARInterrupt()), and user query helpers.
Entry Point
Run_AR_Interrupt_Basic() is the core function called after board connection succeeds. It collects four pieces of information from the user, then executes the interrupt lifecycle:
-
Receive channel — which ARINC channel to monitor for incoming messages.
-
Latch trigger mode — edge-triggered (0) or level-triggered (1, default). This determines whether the interrupt fires once on detection (edge) or continuously while the condition persists (level). For ARINC receive interrupts, level triggering is the default because new messages may accumulate in the FIFO — level mode ensures the interrupt re-fires as long as unread data remains.
-
Interrupt steering — where the interrupt signal is delivered (onboard, offboard PCI/PCIe, etc.).
-
Timestamp enable — whether to include hardware timestamps with received ARINC messages (default: Yes).
After collecting these values, the function follows a linear flow: install ISR, configure interrupt registers, enable Rx on the channel, wait for interrupts, then clean up.
/* Query user for RX channel */
printf( "\nWhich channel would you like to Receive on? \n" );
bQuit = naiapp_query_ChannelNumber( inputARConfig.maxChannel, inputARConfig.minChannel, &inputARConfig.channel );
/* Query user for Trigger Status of interrupts */
bQuit = GetARLatchStatusTriggerMode( &inputInterruptConfig.interrupt_Edge_Trigger );
/* Query user for location interrupt will be sent out to */
bQuit = GetIntSteeringTypeFromUser( &inputInterruptConfig.steering );
/* Query user for timestamp enable */
bQuit = QueryUserForTimeStampEnable( &inputARConfig.timeStampEnable );
The menu system is a sample convenience — in your own code, call these API functions directly with your desired values.
Interrupt Status Types
ARINC 429 interrupts are fundamentally different from discrete (DT) interrupts. A DT module monitors voltage levels on physical I/O pins and generates interrupts when those voltages cross configured thresholds (low-to-high transition, high-to-low transition) or when hardware faults are detected (overcurrent, BIT failure). An AR module monitors communication protocol events on the ARINC 429 bus and generates interrupts when protocol-level conditions occur — a new message has been received, or the internal data path verification has failed.
This means your interrupt handler logic is different. With DT interrupts, you typically read which channels triggered and take action based on the signal state. With AR interrupts, you read the FIFO to retrieve the actual ARINC message data, or you investigate a BIT failure to determine if the communication path is compromised.
The AR module exposes two primary interrupt status types that this sample demonstrates:
BIT (Built-In Test)
AR_BIT_ERROR (status bit 0x0200)
The module’s Built-In Test circuitry continuously verifies the ARINC data path using an internal loopback mechanism. The BIT system uses an "add-2, subtract-1" filtering scheme for Continuous BIT (CBIT): it transmits known test patterns through the internal loopback path and compares the received data against the expected values. Each successful comparison decrements an internal error counter; each failure increments it by two. This asymmetric weighting means a single transient glitch will not immediately trigger a BIT fault, but a persistent mismatch — where failures outnumber successes — will eventually cause the counter to exceed its threshold and latch the BIT error status.
When the BIT error bit latches, the corresponding interrupt fires (if enabled). A BIT fault indicates that the transmit-to-receive data path on the channel is not functioning correctly. This could be caused by a hardware failure, a configuration error that disrupts the internal loopback, or an FPGA issue.
Enable BIT interrupts for health monitoring, safety-critical applications, or continuous hardware validation. In systems where a compromised ARINC communication path must be flagged immediately rather than discovered during a periodic status poll, BIT interrupts provide the fastest notification.
Consult the AR-01 module manual for BIT timing specifications, error counter thresholds, and the relationship between CBIT test rate and fault detection latency.
Summary RX Available
AR_RX_DATA_AVAIL (status bit 0x0001)
A new ARINC 429 message has been received and is available in the channel’s receive FIFO buffer. This is the primary data-availability interrupt — it fires when the hardware has captured a complete ARINC word from the bus and placed it in the FIFO. Your application responds by reading the FIFO to retrieve the message data, status, and (if enabled) timestamp.
This interrupt is the ARINC equivalent of a "data ready" notification. Unlike a DT low-to-high transition interrupt — which tells you a voltage level changed — the RX Available interrupt tells you a complete 32-bit ARINC word has arrived through the protocol decoder, passed parity checking (if enabled), and been stored in the receive buffer.
Enable RX Available interrupts when your application needs to process incoming ARINC messages as they arrive rather than polling the FIFO. This is the most common AR interrupt type and the primary one demonstrated by this sample.
How AR Interrupts Differ from Discrete Interrupts
To summarize the key differences:
| Characteristic | DT (Discrete) Interrupts | AR (ARINC 429) Interrupts |
|---|---|---|
What is monitored |
Voltage levels on I/O pins |
ARINC 429 protocol events on the bus |
BIT meaning |
Channel hardware health (open input, stuck output) |
Data path integrity (Tx-to-Rx loopback verification) |
Data event |
Voltage transition (low-to-high, high-to-low) |
Message received (FIFO has new ARINC word) |
Handler action |
Read which channels triggered, check signal state |
Read FIFO to retrieve ARINC message data |
Prerequisite |
Physical signal present at input pin |
ARINC transmitter active on the bus, Rx enabled on channel |
Interrupt Configuration
The configureARToInterruptOnRx() function in nai_ar_int.c configures the module’s interrupt registers for a single channel. The configuration follows a specific sequence: disable existing interrupts, clear stale status, set the vector, configure the trigger mode, and set interrupt steering. After this, the main application enables interrupts and configures the channel for reception.
Step 1: Disable Interrupts and Clear Status
Always disable interrupts and clear stale status before reconfiguring. Stale latched status from a previous run will trigger an immediate interrupt if not cleared first.
/* clear interruptConfigs of previous channels */
check_status( naibrd_AR_SetInterruptEnable( cardIndex, module, channel, 0 ) );
check_status( naibrd_AR_ClearStatus( cardIndex, module, channel, 0xFFFF ) );
The 0xFFFF mask clears all status bits — BIT, RX Available, FIFO status, parity errors, and all other latched conditions. This ensures a clean starting state.
Step 2: Set Interrupt Vector
The vector identifies which interrupt source generated the event when your ISR is called. The sample assigns NAI_AR_INTERRUPT_VECTOR to the channel. If you need to distinguish multiple AR channels in a single ISR, you can assign a different vector to each channel.
check_status( naibrd_AR_SetInterruptVector( cardIndex, module, channel, vector ) );
Step 3: Set Trigger Mode (Edge/Level)
The trigger mode determines how the latched status register generates interrupts. Edge-triggered mode fires once when the status transitions from clear to set. Level-triggered mode fires continuously as long as the status remains set.
check_status( naibrd_AR_SetInterruptEdgeLevel( cardIndex, module, channel, interrupt_Edge_Trigger ) );
For ARINC receive interrupts, the default is level-triggered (1). This is appropriate because multiple ARINC messages may arrive in rapid succession — level mode ensures the interrupt continues to fire as long as unread messages remain in the FIFO. If you switch to edge-triggered mode, you must ensure your handler reads all available messages before clearing the status, or you may miss messages that arrived while you were processing.
Step 4: Set Interrupt Steering
Steering determines how the interrupt signal is delivered from the module to your application. The user’s selection is passed directly to the steering configuration call.
check_status( naibrd_AR_SetInterruptSteering( cardIndex, module, channel, steering ) );
The steering options are the same as for other module types: onboard (NAIBRD_INT_STEERING_ON_BOARD_0), cPCI offboard (NAIBRD_INT_STEERING_CPCI_APP), PCIe offboard (NAIBRD_INT_STEERING_PCIE_APP), and Ethernet (NAIBRD_INT_STEERING_ON_BOARD_1). Ensure the steering mode matches your physical bus configuration and the IRQ ID used in naibrd_InstallISR().
Step 5: Enable Interrupts on the Channel
After configuration, the enableARInterrupts() function enables interrupt generation on the selected channel:
check_status( naibrd_AR_SetInterruptEnable( inputARConfig.cardIndex, inputARConfig.module, inputARConfig.channel, enable ) );
Step 6: Enable Rx and Configure the Channel
This step is AR-specific and has no equivalent in discrete module interrupt setup. ARINC channels must be explicitly enabled for reception before any messages can arrive. Without this step, the channel’s receiver is inactive and no RX Available interrupt will ever fire, regardless of how correctly the interrupt registers are configured.
The Cfg_Rx_AR() function handles this:
Cfg_Rx_AR( inputARConfig );
This function sets the ARINC data rate (high speed at 100 kbps for ARINC 429, or the appropriate rate for the module variant), configures timestamp mode if the user requested it, and calls naibrd_AR_SetRxEnable() to activate the receiver on the selected channel. The Rx enable step is the most commonly missed step when ARINC interrupts fail to fire.
Full Configuration Sequence
The complete configuration flow in Run_AR_Interrupt_Basic() ties all steps together:
/**** 2. Implement Bus Interrupt Handling ****/
setIRQ( inputInterruptConfig.steering, &inputInterruptConfig.irq );
check_status( naibrd_InstallISR( inputARConfig.cardIndex, inputInterruptConfig.irq, basic_ISR_AR, NULL ) );
/**** 3. configure Module to perform interrupts ****/
configureARToInterruptOnRx( inputInterruptConfig, inputARConfig );
enableARInterrupts( inputARConfig, TRUE );
/**** 4. Configure Module to cause Interrupts ****/
Cfg_Rx_AR( inputARConfig );
|
Important
|
Common interrupt configuration errors:
|
Interrupt Handler
The sample uses a simple ISR (basic_ISR_AR()) that sets a flag and records the interrupt vector. The actual status reading and FIFO retrieval happen in the polling function checkForARInterrupt(), which runs in the main thread.
ISR: basic_ISR_AR()
The ISR is intentionally minimal. It sets the interruptOccured flag to TRUE and captures the interrupt vector. On VxWorks, it also reads and clears the onboard interrupt vector directly.
#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
}
In your own application, keep the ISR as short as possible. Set a flag or post a message, then do the heavy work (FIFO reads, data processing) outside the ISR context.
Polling and FIFO Read: checkForARInterrupt()
The checkForARInterrupt() function runs in a loop, prompting the user to check for interrupts. When interruptOccured is TRUE, it reads the channel’s latched status, retrieves the FIFO contents, and displays the received ARINC message data.
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 );
/* ... display message data, status, and timestamps ... */
interruptOccured = FALSE;
}
The key API sequence when an RX Available interrupt fires:
-
naibrd_AR_GetStatus()— read the latched status register to confirm which status bits are set. The status word containsAR_RX_DATA_AVAIL(bit 0),AR_BIT_ERROR(bit 9), and other condition flags. -
naibrd_AR_GetRxBufferCnt()— get the number of messages currently in the receive FIFO. -
naibrd_AR_ReadFifo()— read all available messages from the FIFO. Each message includes a status word, the 32-bit ARINC data word, and (if timestamps are enabled) a hardware timestamp.
After displaying the results, the function offers to clear the status register:
printf( "\n\nWould you like to clear the status register? (default:Y):" );
/* ... */
if ( inputBuffer[0] == 'y' || inputBuffer[0] =='Y' || inputResponseCnt == 0 )
{
check_status( naibrd_AR_ClearStatus( inputARConfig.cardIndex, inputARConfig.module, inputARConfig.channel, 0xFFFF ) );
}
Clearing the status register re-arms the interrupt for the next event. If you are using edge-triggered mode and do not clear the status, no new edge will be generated and the interrupt will never fire again. In level-triggered mode, the interrupt will continue to assert as long as unread data remains in the FIFO, but clearing the status after reading all messages is still good practice.
Cleanup
After the user quits the polling loop, the application disables Rx on the channel, clears all status, and uninstalls the ISR:
/***** 7. Clear Module Configurations *****/
check_status( naibrd_AR_SetRxEnable( inputARConfig.cardIndex, inputARConfig.module, inputARConfig.channel, FALSE ) );
check_status( naibrd_AR_ClearStatus( inputARConfig.cardIndex, inputARConfig.module, inputARConfig.channel, 0xFFFF ) );
/***** 8. Clear Board Configurations *****/
check_status( naibrd_UninstallISR( inputARConfig.cardIndex ) );
Always disable Rx and clear status before uninstalling the ISR. This prevents any final interrupt from firing after the handler has been removed.
|
Important
|
Common interrupt handling 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 ARINC Interrupts That Are Not Firing
For ARINC interrupts, the most common issue is RX Available never firing. This usually means the channel’s Rx is not enabled, or no ARINC transmitter is present on the bus. Use this 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 your channel. If theAR_RX_DATA_AVAILbit is setting when you know a transmitter is active, the module is detecting messages — the issue is in your interrupt delivery path (steering, ISR installation, or enable). -
If the status registers are NOT changing, verify that Rx is enabled on the channel (
naibrd_AR_SetRxEnable()was called withTRUE), that an ARINC transmitter is actually sending data on the bus, and that the data rate configuration matches between transmitter and receiver. You can also try reading the FIFO directly withnaibrd_AR_ReadFifo()to bypass the interrupt path entirely and confirm whether messages are arriving.
| 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 AR module installed at the selected slot, incorrect module number, or a non-AR module is present |
Verify hardware configuration. Check |
RX Available interrupt never fires |
Rx not enabled on the channel, no ARINC transmitter active on the bus, or data rate mismatch between transmitter and receiver |
Verify |
BIT failure interrupt fires unexpectedly |
Internal loopback path issue, channel configured in a mode that disrupts BIT, or hardware fault |
Read the BIT status register to identify which channel failed. If the failure is persistent, it indicates a real hardware issue — consult the AR-01 manual for BIT diagnostics. Transient BIT failures may self-clear due to the add-2/subtract-1 filtering scheme. |
FIFO overflow (data lost) |
Messages arriving faster than the application reads them, FIFO depth exceeded (255 words for AR1, 1024 for AR2) |
Increase your read rate, use level-triggered interrupts to ensure continuous notification while data remains in the FIFO, or reduce the incoming message rate. Check |
Timestamps show as zero |
Timestamp feature not enabled before first message arrived, or module does not support timestamps in the current mode |
Call |
Steering mismatch — ISR never called |
Steering mode does not match the IRQ ID used in |
Match steering to where your application executes. Onboard: |
Wrong trigger mode for ARINC receive |
Edge-triggered mode selected, but handler does not drain the full FIFO before clearing — subsequent messages missed |
Use level-triggered mode (default) for ARINC receive interrupts. Level mode re-fires as long as unread data remains in the FIFO. If you must use edge-triggered mode, read all FIFO messages before clearing the status. |
Interrupts stop after first event |
Status register not cleared after handling (edge-triggered mode) |
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 two source files: the main application and shared ARINC interrupt utilities.
Full Source — AR_Interrupt_Basic.c (SSK 1.x)
/**************************************************************************************************************/
/**
<summary>
The AR_Interrupt_Basic 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.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"
InterruptConfig inputInterruptConfig;
/* Extern Functions or Variables*/
extern ArConfig inputARConfig;
/*********************************************/
/* Application Name and Revision Declaration */
/*********************************************/
static const int8_t *CONFIG_FILE = (int8_t *)"default_AR_Interrupt_Basic.txt";
/********************************/
/* Internal Function Prototypes */
/********************************/
static bool_t Run_AR_Interrupt_Basic();
/**************************************************************************************************************/
/***** 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(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_Basic();
}
}
}
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_cfg.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 if any interrupt has occurred and report back the status and vector
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_ClearStatusRaw
7. Clear Module Configurations
API CALLS - naibrd_AR_SetRxEnable
8. Clear Board Configurations
API CALLS - naibrd_UninstallISR
</summary>
*/
/**************************************************************************************************************/
static bool_t Run_AR_Interrupt_Basic()
{
bool_t bQuit = FALSE;
inputARConfig.maxChannel = NAI_GEN5_AR_MAX_CHANNEL_COUNT;
inputARConfig.minChannel = 1;
/* Query user for RX channel */
if (!bQuit)
{
printf( "\nWhich channel would you like to Receive on? \n" );
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 );
}
/* Query user for location interrupt will be sent out to */
if (!bQuit)
{
bQuit = GetIntSteeringTypeFromUser( &inputInterruptConfig.steering );
}
if (!bQuit)
{
bQuit = QueryUserForTimeStampEnable( &inputARConfig.timeStampEnable );
}
if (!bQuit)
{
/**** 2. Implement Bus Interrupt Handling ****/
setIRQ( inputInterruptConfig.steering, &inputInterruptConfig.irq );
check_status( naibrd_InstallISR( inputARConfig.cardIndex, inputInterruptConfig.irq, basic_ISR_AR, NULL ) );
/**** 3. configure Module to perform interrupts ****/
configureARToInterruptOnRx( inputInterruptConfig, inputARConfig );
enableARInterrupts( inputARConfig, TRUE );
/**** 4. Configure Module to cause Interrupts ****/
Cfg_Rx_AR( inputARConfig );
/**** 5. Show Interrupt Handling (contains step 6) ****/
bQuit = checkForARInterrupt( inputARConfig );
/***** 7. Clear Module Configurations *****/
check_status( naibrd_AR_SetRxEnable( inputARConfig.cardIndex, inputARConfig.module, inputARConfig.channel, FALSE ) );
check_status( naibrd_AR_ClearStatus( inputARConfig.cardIndex, inputARConfig.module, inputARConfig.channel, 0xFFFF ) );
/***** 8. Clear Board Configurations *****/
check_status( naibrd_UninstallISR( inputARConfig.cardIndex ) );
}
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 );
}