DT Interrupt
Edit this on GitLab
DT Interrupt
Explanation
About the Sample Application Code: DT_Ethernet_IDR
Overview This sample application code demonstrates how to handle multiple channel interrupts for a discrete module using Ethernet IDR (Interrupt Driven Response) commands with North Atlantic Industries (NAI) hardware. Specifically, the code manages interrupts for Fault, Low-to-High Transition, High-to-Low Transition, and Overcurrent events.
Include Declarations The code includes several library files necessary for handling board operations, interrupt handling, and communication using Ethernet:
-
Standard libraries like
stdio.h
,stdlib.h
,string.h
, andstdint.h
are included to handle basic operations. -
Windows-specific libraries
winsock2.h
andws2tcpip.h
are included when compiled in a Windows environment. -
NAI specific libraries for board access (
nai.h
,naibrd.h
, etc.) and discrete module functionalities (naibrd_dt.h
,nai_map_dt.h
).
Constants and Static Variables
- CONFIG_FILE: Points to the configuration file for this application (default_DT_Interrupt.txt
).
- DT_INTERRUPT_RESPONSE_REG_COUNT: Specifies the number of registers to retrieve with each interrupt message (4 registers: Fault, Low-to-High Transition, High-to-Low Transition, and Overcurrent).
Internal Function Prototypes
The following functions are declared and defined internally to manage the interrupt routines:
- DT_QueryUserForClearingInterruptPrompts()
: Asks the user if prompts are needed to clear interrupts.
- QueryUserForOnboardOffbordInterrupts()
: Prompts the user to choose between processing onboard or offboard interrupts.
- HandleDTInterrupt(uint32_t nVector)
: Handles the received interrupt messages.
- ExitApp_DTInterrupt()
: Cleans up and exits the application.
Main Routine The main function initializes the application and sets up the necessary configurations for handling interrupts:
-
Initialization and Configuration:
-
Displays a banner using
DisplayMessage_DTInterrupt()
. -
Loads configuration from
CONFIG_FILE
. -
Acquires system and module configuration using
naiapp_access_SystemSNModCfg()
.
-
-
User Interaction:
-
The program prompts the user to provide input regarding:
-
Whether user prompts are needed before clearing interrupts.
-
Whether to process onboard or offboard interrupts.
-
-
Interrupt Handling Setup:
-
Based on the user’s input, the program configures the interrupt settings (
ConfigDTInterrupt
) and initializes the interrupt handling thread (InitInterruptAppThread
). -
Sets the global interrupt processing function pointer
dtIntProcessFunc
to handle discrete interrupts (HandleDTInterrupt
). -
Installs the appropriate interrupt service routine (ISR) using
naibrd_InstallISR()
.
-
-
Main Loop:
-
An infinite loop awaits interrupt events. When an interrupt occurs, the application processes the interrupt and handles it accordingly.
-
-
Exit Procedure:
-
The application exits cleanly by calling
ExitApp_DTInterrupt()
to close any open resources and terminate interrupt threads.
-
Detailed Function Implementations
1. DT_QueryUserForClearingInterruptPrompts:
- Prompts the user to decide if they should be asked before clearing an interrupt.
- Sets the bPromptForInterruptClear
flag accordingly.
-
QueryUserForOnboardOffbordInterrupts:
-
Prompts the user to choose between onboard and offboard interrupts.
-
Sets the
bProcessOnboardInterrupts
andisPCIE
flags based on the user’s choice.
-
-
HandleDTInterrupt:
-
This function is called when an interrupt occurs. It reads the interrupt status registers and prints out the interrupt event.
-
Clears the relevant status to re-arm interrupts if required, based on user prompts.
-
-
ExitApp_DTInterrupt:
-
Closes any open resources and exits the interrupt handling threads safely.
-
Enumerations and Types to Note
- bool_t: Custom boolean type, potentially defined in NAI’s libraries.
- nai_dt_status_type_t: Enum type to specify different status types (e.g., NAI_DT_STATUS_BIT_LATCHED
).
- nai_isr_t: Type definition for ISR functions.
Compilation and Execution To compile and run this application, ensure all necessary NAI libraries are correctly linked, and configuration files are in place. The code should be compatible with both Windows and certain Real-Time Operating Systems (RTOS) like VxWorks, as indicated by the conditional compilation directives.
This application serves as an example of how to manage interrupt-driven events in NAI’s hardware modules, providing an essential tool for developers working with NAI’s extensive hardware solutions.
/**************************************************************************************************************/
/**
<summary>
The DT_Ethernet_IDR program that handle multiple channel interrupts for the Discrete module using the
Ethernet IDR (Interrupt Driven Response) commands.
Interrupts for Fault, Low-to-High Transition, High-to-Low Transition and Overcurrent are enabled.
</summary>
*/
/**************************************************************************************************************/
/************************/
/* Include Declarations */
/************************/
#if defined (WIN32)
#include <winsock2.h>
#include <ws2tcpip.h>
#pragma comment (lib, "Ws2_32.lib")
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <stdint.h>
/* Common Sample Program include files */
#include "include/naiapp_interrupt.h"
#include "include/naiapp_interrupt_ether.h"
#include "include/naiapp_boardaccess_menu.h"
#include "include/naiapp_boardaccess_query.h"
#include "include/naiapp_boardaccess_access.h"
#include "include/naiapp_boardaccess_display.h"
#include "include/naiapp_boardaccess_utils.h"
/* Generic NAI Board Library include files */
#include "nai.h"
#include "naibrd.h"
#include "naibrd_ether.h"
#include "advanced/nai_ether_adv.h"
/* Module Specific NAI Board Library files */
#include "functions/naibrd_dt.h"
#include "maps/nai_map_dt.h"
/* Module Specific sample code include files */
#include "DT_Interrupt_Common.h"
/*********************************************/
/* Application Name and Revision Declaration */
/*********************************************/
/*
static const int8_t *App_Name = "DT Interrupt";
static const int8_t *App_Rev = "1.0";
*/
static const int8_t *CONFIG_FILE = (int8_t *)"default_DT_Interrupt.txt";
/* Number of Registers to retrieve with each interrupt message:
Fault, Low-to-High Transition, High-to-Low Transition and Overcurrent.
*/
#define DT_INTERRUPT_RESPONSE_REG_COUNT 4
static bool_t bPromptForInterruptClear = TRUE;
static bool_t bProcessOnboardInterrupts = TRUE;
static bool_t isPCIE = FALSE;
/********************************/
/* Internal Function Prototypes */
/********************************/
static bool_t DT_QueryUserForClearingInterruptPrompts(void);
static bool_t QueryUserForOnboardOffbordInterrupts(void);
void HandleDTInterrupt(uint32_t nVector);
void ExitApp_DTInterrupt(void);
/**************************************************************************************************************/
/***** Main Routine *****/
/**************************************************************************************************************/
/**************************************************************************************************************/
/**
<summary>
The purpose of the DT_Interrupt is to illustrate the methods to call in the naibrd library to configure the
discrete module to generate interrupts on any channel for the following events:
- Fault,
- Low-to-High Transition,
- High-to-Low Transition, or
- Overcurrent
The following routines from the DT_Interrupt_Common.c file are called to assist with displaying, handling prompting
the user for inputs and configurating the channels on the discrete modules:
- DisplayMessage_DTInterrupt
- PromptUserInput_DTInterrupt
- ConfigDTInterrupt
- EnableDTInterrupt
The following routines from the nai_sys_int.c file are called to assist with setup the threads used by this
application to handle the interrupt and user interface:
- InitInterruptAppThread
- UpdateThreadState
The following system configuration routines from the nai_sys_cfg.c file are called to assist with the configuration
setup for this program prior to calling the naibrd DT routines.
- ConfigDevice
- DisplayDeviceCfg
- GetBoardSNModCfg
</summary>
*/
/**************************************************************************************************************/
#if defined (__VXWORKS__)
void DT_Interrupt(void)
#else
int32_t main(void)
#endif
{
bool_t bQuit = FALSE;
bool_t bSuccess = FALSE;
DisplayMessage_DTInterrupt(MSG_BANNER_DT_INT);
bQuit = naiapp_RunBoardMenu(CONFIG_FILE);
while (!bQuit)
{
naiapp_access_SystemSNModCfg();
bQuit = PromptUserInput_DTInterrupt(&bSuccess);
if ((!bQuit) & bSuccess)
{
bQuit = DT_QueryUserForClearingInterruptPrompts();
if (!bQuit)
{
bQuit = QueryUserForOnboardOffbordInterrupts();
if (!bQuit)
{
if ( bProcessOnboardInterrupts == TRUE )
{
printf("\nOnboard Interrupts selected.\n");
ConfigDTInterrupt(ONBOARD_INT);
InitInterruptAppThread(ONBOARD_INT, 0);
/* Set the dtIntProcessFunc global function pointer to point to the routine that will handle
Interrupt messages associated with the Discrete Interrupt Vector (DEF_ETHERNET_DT_IDR_ID).
*/
dtIntProcessFunc = HandleDTInterrupt;
if ( naibrd_InstallISR(userInput_DTInt.cardIndex, NAIBRD_IRQ_ID_ON_BOARD_0, (nai_isr_t)IntOnboardIsr, (void*)&userInput_DTInt.cardIndex) == NAI_SUCCESS)
{
DisplayMessage_DTInterrupt(MSG_USER_TRIGGER_DT_INT);
EnableDTInterrupt(TRUE);
/* Add a small delay to make sure the Interrupt State Machine Task has completed initialization */
nai_msDelay(10);
UpdateThreadState(RUN);
}
else
{
printf("\n***** Error - naibrd_InstallISR (Onboard) FAILED - Interrupts will not work. *****\n");
bQuit = TRUE;
}
}
else
{
printf("\nOffboard Interrupts selected.\n");
if( isPCIE == TRUE )
{
ConfigDTInterrupt(MASTER_PCIE_BUS_OFFBOARD_INT);
InitInterruptAppThread(MASTER_PCIE_BUS_OFFBOARD_INT, 0);
}
else
{
ConfigDTInterrupt(MASTER_PCIBUS_OFFBOARD_INT);
InitInterruptAppThread(MASTER_PCIBUS_OFFBOARD_INT, 0);
}
/* Set the dtIntProcessFunc global function pointer to point to the routine that will handle
Interrupt messages associated with the Discrete Interrupt Vector (DEF_ETHERNET_DT_IDR_ID).
*/
dtIntProcessFunc = HandleDTInterrupt;
if ( naibrd_InstallISR(userInput_DTInt.cardIndex, NAIBRD_IRQ_ID_DONT_CARE, (nai_isr_t)IntOffboardIsr, (void*)&userInput_DTInt.cardIndex) == NAI_SUCCESS)
{
DisplayMessage_DTInterrupt(MSG_USER_TRIGGER_DT_INT);
EnableDTInterrupt(TRUE);
/* Add a small delay to make sure the Interrupt State Machine Task has completed initialization */
nai_msDelay(10);
UpdateThreadState(RUN);
}
else
{
printf("\n***** Error - naibrd_InstallISR (Offboard) FAILED - Interrupts will not work. *****\n");
bQuit = TRUE;
}
}
}
else
{
UpdateThreadState(TERMINATED);
}
}
else
{
UpdateThreadState(TERMINATED);
}
bQuit = TRUE;
}
}
ExitApp_DTInterrupt();
#if !defined (__VXWORKS__)
return(0);
#endif
}
/**************************************************************************************************************/
/***** Internal Functions *****/
/**************************************************************************************************************/
/**************************************************************************************************************/
/**
<summary>
DT_QueryUserForClearingInterruptPrompts handles querying the user to see if he wants to be prompted to clear
the interrupts when an interrupt is received. If the user specifies 'N', the interrupts will automatically
be cleared when an interrupt is received. Otherwise, the program will prompt the user to enter a 'C' to
clear the interrupts.
</summary>
*/
/**************************************************************************************************************/
static bool_t DT_QueryUserForClearingInterruptPrompts(void)
{
bool_t bQuit = FALSE;
int8_t inputBuffer[80];
int32_t inputResponseCnt;
/* Query the user to determine if he wants to be prompted before clearing the interrupt */
printf("\nWould you like to be prompted to clear interrupts? (Y or N) (Default: Y): ");
bQuit = naiapp_query_ForQuitResponse(sizeof(inputBuffer), NAI_QUIT_CHAR, inputBuffer, &inputResponseCnt);
if (!bQuit)
{
if (inputResponseCnt != 0)
{
if ((inputBuffer[0] == 'N') || (inputBuffer[0] == 'n'))
{
bPromptForInterruptClear = FALSE;
}
else
{
bPromptForInterruptClear = TRUE;
}
}
else
{
bPromptForInterruptClear = TRUE;
}
}
return bQuit;
}
/**************************************************************************************************************/
/**
<summary>
QueryUserForOnboardOffbordInterrupts handles querying the user to see if he wants process Onboard or
Offboard interrupts. If the user specifies 'O', Onboard interrupts will be processed, else Offboard (External)
interrupt will be processed.
</summary>
*/
/**************************************************************************************************************/
static bool_t QueryUserForOnboardOffbordInterrupts(void)
{
bool_t bQuit = FALSE;
int8_t inputBuffer[80];
int32_t inputResponseCnt;
/* Query the user to determine if he wants Onboard or external Offbord Interrupts */
printf("\nWould you like to be process Onboard(O) or external Offbord_PCI(P) Offbord_PCIE(E) Interrupts? (Default: O): ");
bQuit = naiapp_query_ForQuitResponse(sizeof(inputBuffer), NAI_QUIT_CHAR, inputBuffer, &inputResponseCnt);
if (!bQuit)
{
if (inputResponseCnt != 0)
{
if ( (inputBuffer[0] == 'E') || (inputBuffer[0] == 'e') || (inputBuffer[0] == 'P') || (inputBuffer[0] == 'p') )
{
if( (inputBuffer[0] == 'E') || (inputBuffer[0] == 'e') )
isPCIE = TRUE;
bProcessOnboardInterrupts = FALSE;
}
else
{
bProcessOnboardInterrupts = TRUE;
}
}
else
{
bProcessOnboardInterrupts = TRUE;
}
}
return bQuit;
}
/**************************************************************************************************************/
/**
<summary>
HandleDTInterrupt is called by the HandleDTInterrupt() routine in nai_sys_int.c when an
a message is received from the interrupt service routine.
</summary>
*/
/**************************************************************************************************************/
void HandleDTInterrupt(uint32_t nVector)
{
int32_t i;
uint32_t dtstatus_int[DT_INTERRUPT_RESPONSE_REG_COUNT];
nai_dt_status_type_t dt_status_type = NAI_DT_STATUS_BIT_LATCHED;
/* Check all 4 status elements (BIT, Lo-Hi, Hi-Lo, Overcurrent) */
printf("\n\n");
for (i = 0; i < DT_INTERRUPT_RESPONSE_REG_COUNT; i++)
{
switch (i)
{
case 0:
dt_status_type = NAI_DT_STATUS_BIT_LATCHED;
break;
case 1:
dt_status_type = NAI_DT_STATUS_LO_HI_TRANS_LATCHED;
break;
case 2:
dt_status_type = NAI_DT_STATUS_HI_LO_TRANS_LATCHED;
break;
case 3:
dt_status_type = NAI_DT_STATUS_OVERCURRENT_LATCHED;
break;
}
check_status(naibrd_DT_GetGroupStatusRaw(userInput_DTInt.cardIndex, userInput_DTInt.moduleNumber, 1, dt_status_type, &dtstatus_int[i]));
if (dtstatus_int[i] != 0)
{
switch (i)
{
case 0:
printf("Received DT Bit Interrupt: (Interrupt_status) 0x%08X\n", dtstatus_int[i]);
break;
case 1:
printf("Received DT Lo-Hi Interrupt: (Interrupt_status) 0x%08X\n", dtstatus_int[i]);
break;
case 2:
printf("Received DT Hi-Lo Interrupt: (Interrupt_status) 0x%08X\n", dtstatus_int[i]);
break;
case 3:
printf("Received DT Overcurrent Interrupt: (Interrupt_status) 0x%08X\n", dtstatus_int[i]);
break;
}
if (bPromptForInterruptClear)
{
/* Prompt the user t to clear the interrupt received */
SetUserRequestClearInt(FALSE);
DisplayMessage_DTInterrupt(MSG_USER_CLEAR_DT_INT);
/* Wait for the user to respond */
while (!GetUserRequestClearInt())
{
nai_msDelay(10);
}
}
/* Clear the status state to re-arm the interrupts */
check_status(naibrd_DT_ClearGroupStatusRaw(userInput_DTInt.cardIndex, userInput_DTInt.moduleNumber, 1, dt_status_type, dtstatus_int[i]));
switch (i)
{
case 0:
printf("Cleared DT Bit Interrupt: 0x%08X\n", dtstatus_int[i]);
break;
case 1:
printf("Cleared DT Lo-Hi Interrupt: 0x%08X\n", dtstatus_int[i]);
break;
case 2:
printf("Cleared DT Hi-Lo Interrupt: 0x%08X\n", dtstatus_int[i]);
break;
case 3:
printf("Cleared DT Overcurrent Interrupt: 0x%08X\n", dtstatus_int[i]);
break;
}
}
}
}
void ExitApp_DTInterrupt(void)
{
ExitInterruptThreads();
if (userInput_DTInt.cardIndex >= 0)
{
naibrd_Close(userInput_DTInt.cardIndex);
}
}