M1553 RT Interrupt
Edit this on GitLab
M1553 RT Interrupt
Explanation
About the Sample Application Code for NAI SSK and 1553 Function Modules
This document provides an overview and explanation of the sample application code provided by North Atlantic Industries (NAI) for using their Systems Support Kits (SSK) to interact with embedded function modules, specifically the 1553 function module. This code is intended to illustrate how to configure a 1553 channel as a Remote Terminal, enable and handle interrupts, and process messages.
Key Components and Functionalities
Include Files The application starts by including necessary header files:
-
Standard Libraries:
stdio.h
,stdlib.h
,string.h
,time.h
-
NAI Specific Headers:
-
naiapp_boardaccess_menu.h
,naiapp_boardaccess_query.h
,naiapp_boardaccess_access.h
,naiapp_boardaccess_display.h
,naiapp_boardaccess_utils.h
-
nai_1553_utils.h
-
nai.h
,naibrd.h
,naibrd_1553.h
These header files contain function declarations and constants required for interacting with the NAI hardware and 1553 channels.
Constants and Global Variables
- Interrupt Vector and Types: Defined constants to configure and handle interrupts.
- File Constants: CONFIG_FILE
specifies the default configuration file.
- Function Prototypes: Declare static functions used within the code.
- Data Block and Default Settings: Constants for data block IDs and default settings.
Main Function
The entry point of the application is main
(or M1553_RT_Interrupt
for VxWorks):
1. Initialization and User Input: The application initializes and queries the user to select a card index and module number.
2. Module Configuration: If a valid module is selected, it invokes Run_M1553_RT_Interrupt
to configure it and handle interrupts.
3. Exit Handling: The user can opt to quit or restart the application.
Functionality of Run_M1553_RT_Interrupt
This function configures and enables interrupts for a 1553 channel as a remote terminal:
1. Device Setup:
- Configures the card, module, and logical device number.
- Opens the device using naibrd_1553_Open
and initializes it with naibrd_1553_Initialize
.
- Optionally sets the RT address in software.
2. Interrupt Setup:
- Configures and installs an interrupt service routine (ISR) using naibrd_1553_SetIrqConfig
, naibrd_InstallISR
, and other related functions.
- Prepares the device to handle end-of-message interrupts.
3. Buffer Setup:
- Sets up data blocks for receiving and transmitting messages using functions like naibrd_1553_RtDataBlockCreate
and naibrd_1553_RtDataBlockMapToSubaddress
.
4. Running the Device: Enters a loop to handle interrupts and process messages for a user-specified duration.
Interrupt Service Routine: myIsr
Handles the interrupt:
1. Clears the interrupt status and sets global flags.
2. Processes New Messages: Reads and decodes new 1553 messages, printing their details to the console.
Function Definitions
1. Get1553RTCfg, Get1553Address, Get1553LogicalDevNum, etc.: Utility functions to retrieve configuration details from the user.
2. naibrd_xxx: Functions provided by the naibrd
library to interact directly with the 1553 hardware.
Observations - Interrupt Management: The application includes robust interrupt management, allowing the user to monitor and respond to end-of-message interrupts. - Modular Design: Separation of concerns via different functions for setup, interrupt handling, and message processing. - Console Interaction: The application frequently interacts with the console for input and feedback, ensuring clarity for user operations.
Conclusion This sample application code provides a practical example of setting up and using a 1553 channel with NAI’s SSK and embedded function modules. It demonstrates key aspects of configuration, interrupt handling, and message processing, essential for developers working with NAI hardware. The included comments and structured design allow users to understand and potentially modify the code to fit specific needs.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
/* Common Sample Program include files */
#include "include/naiapp_boardaccess_menu.h"
#include "include/naiapp_boardaccess_query.h"
#include "include/naiapp_boardaccess_access.h"
#include "include/naiapp_boardaccess_display.h"
#include "include/naiapp_boardaccess_utils.h"
/* Common 1553 Sample Program include files */
#include "nai_1553_utils.h"
/* naibrd include files */
#include "nai.h"
#include "naibrd.h"
#include "functions/naibrd_1553.h"
#define INTERRUPT_VECTOR_ADDEND 0xA0
#define INTERRUPT_TYPE_MASK NAI_1553_INT_STS_REG1_MASK_END_OF_MESSAGE /* NAI_1553_INT_STS_REG1_MASK_TIME_TAG_ROLLOVER */ /* NAI_1553_INT_STS_REG1_MASK_END_OF_MESSAGE */
#define INT_FILTER_VALUE 0x30
static const int8_t *CONFIG_FILE = (int8_t *)"default_1553_RTInterrupt.txt";
/* Function prototypes */
static bool_t Run_M1553_RT_Interrupt(int32_t cardIndex, int32_t module, uint32_t modid);
static int32_t ProcessMessages(int32_t duration);
static void myIsr(void* param, uint32_t vector);
static const uint16_t DATA_BLOCK_ID_TX1 = 1;
static const uint16_t DATA_BLOCK_ID_TX2 = 2;
static const uint16_t DATA_BLOCK_ID_RX = 3;
static const int32_t DEF_RT_CHANNEL = 3;
static const int16_t DEF_RT_DEV_NUM = 3;
static const uint8_t DEF_RT_ADDRESS = 1;
static const uint8_t DEF_RT_SUBADDR = 2;
static const uint16_t DEF_RT_RX_BUF_TYPE = NAI_1553_RT_DATABLOCK_DOUBLE;
/* Global Variables */
static int32_t currDataBlock;
static int16_t deviceNumber;
static volatile int32_t irqFlag;
static int32_t irqCount;
static uint32_t receivedVector;
/**************************************************************************************************************/
/**
<summary>
The purpose of the M1553_RT_Interrupt is to illustrate the methods to call in the naibrd library to configure
the 1553 channel as a Remote Terminal, legalize the user specified subaddress for both Tx and Rx, and set it up
with interrupts enabled such that when an end of message interrupt is triggered, the received 1553 message is
displayed in the console. (NOTE: interrupt steering should be set in accordance with the onboard processor type,
where steering is set to NAIBRD_INT_STEERING_PCIE_APP for PPC1 and NAIBRD_INT_STEERING_ON_BOARD_0 for ARM1).
Ethernet communication will not work with this application.
The following routines are called to configure and enable interrupts on the 1553 and hook the interrupt service
routine (ISR).
- naibrd_1553_SetIrqConfig
- naibrd_1553_SetIrqManipulate
- naibrd_InstallISR
- naibrd_1553_SetInterruptSteering
- naibrd_1553_SetIntVector
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 1553 routines.
- ConfigDevice
- DisplayDeviceCfg
- GetBoardSNModCfg
- CheckModule
</summary>
*/
/**************************************************************************************************************/
#if defined (__VXWORKS__)
int32_t M1553_RT_Interrupt(void)
#else
int32_t main(void)
#endif
{
bool_t stop = FALSE;
int32_t cardIndex;
int32_t moduleCnt;
int32_t module;
uint32_t moduleID = 0;
int8_t inputBuffer[80];
int32_t inputResponseCnt;
if (naiapp_RunBoardMenu(CONFIG_FILE) == TRUE)
{
while (stop != TRUE)
{
/* Query the user for the card index */
stop = naiapp_query_CardIndex(naiapp_GetBoardCnt(), 0, &cardIndex);
if (stop != TRUE)
{
check_status(naibrd_GetModuleCount(cardIndex, &moduleCnt));
/* Query the user for the module number */
stop = naiapp_query_ModuleNumber(moduleCnt, 1, &module);
if (stop != TRUE)
{
moduleID = naibrd_GetModuleID(cardIndex, module);
if ((moduleID != 0))
{
Run_M1553_RT_Interrupt(cardIndex, module, moduleID);
}
}
}
printf("\nType Q to quit or Enter key to restart application:\n");
stop = naiapp_query_ForQuitResponse(sizeof(inputBuffer), NAI_QUIT_CHAR, inputBuffer, &inputResponseCnt);
}
}
printf("\nType the Enter key to exit the program: ");
naiapp_query_ForQuitResponse(sizeof(inputBuffer), NAI_QUIT_CHAR, inputBuffer, &inputResponseCnt);
naiapp_access_CloseAllOpenCards();
return 0;
}
static bool_t Run_M1553_RT_Interrupt(int32_t cardIndex, int32_t module, uint32_t modid)
{
/* Variables */
bool_t bQuit = FALSE;
int32_t rtchan;
uint8_t rtaddr;
uint8_t sa = DEF_RT_SUBADDR;
int16_t DevNum = 0;
int32_t swResult;
uint16_t nDataBlockType = 0;
bool_t bContinue = TRUE;
int32_t duration;
uint16_t status1, status2;
bool_t bSoftwareRTAddr;
int8_t inputBuffer[80];
int32_t inputResponseCnt;
/*************************/
/*** 1553 DEVICE SETUP ***/
/*************************/
/* Get Card, Module, Channel Numbers and Open a Handle */
bQuit = Get1553RTCfg(modid, DEF_RT_CHANNEL, DEF_RT_ADDRESS, &rtchan, &rtaddr);
if (bQuit)
{
return bQuit;
}
printf("Enter Subaddress\n");
bQuit = Get1553Address(31, DEF_RT_SUBADDR, &sa);
/* Get Logical Device # */
bQuit = Get1553LogicalDevNum(DEF_RT_DEV_NUM, &DevNum);
if (bQuit)
{
return bQuit;
}
deviceNumber = DevNum;
irqFlag = 0;
/* Associate Card, Module and Channel Numbers with the Logical Device # */
swResult = naibrd_1553_Open(cardIndex, module, rtchan, DevNum);
if(swResult)
{
bQuit = TRUE;
printf("Error: naibrd_1553_Open %d", swResult);
return bQuit;
}
/* Initialize Device */
swResult = naibrd_1553_Initialize(DevNum,NAI_1553_ACCESS_CARD,NAI_1553_MODE_RT,0,0,0);
if(swResult != 0)
{
bQuit = TRUE;
printf("Error: naibrd_1553_Initialize %d", swResult);
return bQuit;
}
if (modid == NAI_MODULE_ID_FT8)
{
/* Simplex Enable */
naibrd_1553_WriteAuxReg(DevNum, 0x3, 0x4000);
}
/* Get RT Address Source from user */
bQuit = Get1553RTAddressSource(TRUE, &bSoftwareRTAddr);
if (bQuit)
{
return bQuit;
}
if (bSoftwareRTAddr)
{
/* Set RTAD_SW_EN and RT_ADR_LAT in software */
swResult = naibrd_1553_WriteAuxReg(DevNum, 0x2, 0x0018);
/* Set RT address */
swResult = naibrd_1553_RtSetAddress(DevNum, rtaddr);
if(swResult != 0)
{
bQuit = TRUE;
printf("Error: naibrd_1553_RtSetAddress %d", swResult);
return bQuit;
}
}
else
{
/* Unset RTAD_SW_EN and set RT_ADR_LAT in software */
swResult = naibrd_1553_WriteAuxReg(DevNum, 0x2, 0x0008);
}
/***********************/
/*** INTERRUPT SETUP ***/
/***********************/
/* Reset Interrupt counter */
irqCount = 0;
/* Setup Interrupts in Core with Level Detection and Auto Clear (read clears interrupt statuses) */
swResult = naibrd_1553_SetIrqConfig(DevNum, NAI_1553_IRQ_MODE_LEVEL, NAI_1553_IRQ_AUTO_CLEAR);
if(swResult != 0)
{
bQuit = TRUE;
printf("Error: naibrd_1553_SetIrqConfig %d", swResult);
return bQuit;
}
/* Hook the interrupt service routine */
swResult = naibrd_InstallISR(cardIndex, NAIBRD_IRQ_ID_DONT_CARE, (nai_isr_t)myIsr, NULL); /* NAIBRD_IRQ_ID_ON_BOARD_0 for Onboard, NAIBRD_IRQ_ID_DONT_CARE for everything else */
if(swResult != 0)
{
bQuit = TRUE;
printf("Error: naibrd_InstallISR %d", swResult);
return bQuit;
}
/* Set the Interrupt Steering to Onboard */
swResult = naibrd_1553_SetInterruptSteering( DevNum, NAIBRD_INT_STEERING_CPCI_APP ); /* NAIBRD_INT_STEERING_CPCI_APP, NAIBRD_INT_STEERING_PCIE_APP for PCIe, NAIBRD_INT_STEERING_ON_BOARD_0 for Onboard */
if(swResult != 0)
{
bQuit = TRUE;
printf("Error: naibrd_1553_SetInterruptSteering %d", swResult);
return bQuit;
}
/* Set the Interrupt Vector (The vector is set as channel number plus 0xA0) */
swResult = naibrd_1553_SetIntVector( DevNum, INTERRUPT_VECTOR_ADDEND + rtchan );
if(swResult != 0)
{
bQuit = TRUE;
printf("Error: naibrd_1553_SetIntVector %d", swResult);
return bQuit;
}
/* Read core status registers to clear statuses */
swResult = naibrd_1553_GetIntStatus(DevNum, &status1, &status2);
if(swResult != 0)
{
bQuit = TRUE;
printf("Error: naibrd_1553_GetIntStatus %d", swResult);
return bQuit;
}
/* Clear Interrupt Latch Bit */
swResult = naibrd_1553_ClearIntLatch(DevNum);
if(swResult != 0)
{
bQuit = TRUE;
printf("Error: naibrd_1553_ClearIntLatch %d", swResult);
return bQuit;
}
/*************************/
/*** 1553 BUFFER SETUP ***/
/*************************/
/* Select Single Buffer, Double Buffer or Circular Buffer for Rx Messages */
bQuit = Get1553RxBufferType(DEF_RT_RX_BUF_TYPE, &nDataBlockType);
if (bQuit)
{
return bQuit;
}
/* Create a Rx Buffer data block and map to the desired subaddress */
swResult = naibrd_1553_RtDataBlockCreate(DevNum, DATA_BLOCK_ID_RX, nDataBlockType, NULL, 0);
if(swResult != 0)
{
bQuit = TRUE;
printf("Error: naibrd_1553_RtDataBlockCreate %d", swResult);
return bQuit;
}
swResult = naibrd_1553_RtDataBlockMapToSubaddress(DevNum, DATA_BLOCK_ID_RX, sa, NAI_1553_RT_MESSAGE_TYPE_RX, NAI_1553_RT_DATABLOCK_IRQ_END_OF_MESSAGE, 1);
if(swResult != 0)
{
bQuit = TRUE;
printf("Error: naibrd_1553_RtDataBlockMapToSubaddress %d", swResult);
return bQuit;
}
/* Create two Tx Buffer data blocks and map the first to the desired subaddress */
swResult = naibrd_1553_RtDataBlockCreate(DevNum, DATA_BLOCK_ID_TX1, NAI_1553_RT_DATABLOCK_SINGLE_32, NULL, 0);
if(swResult != 0)
{
bQuit = TRUE;
printf("Error: naibrd_1553_RtDataBlockCreate %d", swResult);
return bQuit;
}
swResult = naibrd_1553_RtDataBlockCreate(DevNum, DATA_BLOCK_ID_TX2, NAI_1553_RT_DATABLOCK_SINGLE_32, NULL, 0);
if(swResult != 0)
{
bQuit = TRUE;
printf("Error: naibrd_1553_RtDataBlockCreate %d", swResult);
return bQuit;
}
swResult = naibrd_1553_RtDataBlockMapToSubaddress(DevNum, DATA_BLOCK_ID_TX1, sa, NAI_1553_RT_MESSAGE_TYPE_TX, 0, 1);
if(swResult < 0)
{
bQuit = TRUE;
printf("Error: naibrd_1553_RtDataBlockMapToSubaddress %d", swResult);
return bQuit;
}
currDataBlock = DATA_BLOCK_ID_TX1;
/*******************/
/*** RUN 1553 RT ***/
/*******************/
while (bContinue)
{
printf("\nType duration (in seconds) to run RT or %c to quit (default: 5) : ", NAI_QUIT_CHAR);
bQuit = naiapp_query_ForQuitResponse(sizeof(inputBuffer), NAI_QUIT_CHAR, inputBuffer, &inputResponseCnt);
if (!bQuit)
{
duration = 5;
if (inputResponseCnt > 0)
{
duration = (int)atol((const char*)inputBuffer);
}
/* Enable Subadddress EOM Interrupts (myIsr is only used here for compatibility with DDC, it is not used in the function) */
swResult = naibrd_1553_SetIrqManipulate(DevNum, 0x1, INTERRUPT_TYPE_MASK, myIsr);
if(swResult != 0)
{
bQuit = TRUE;
printf("Error: naibrd_1553_SetIrqManipulate %d", swResult);
return bQuit;
}
/* Start RT */
swResult = naibrd_1553_RtStart(DevNum);
if(swResult != 0)
{
bQuit = TRUE;
printf("Error: naibrd_1553_RtStart %d", swResult);
return bQuit;
}
/* Process New Messages */
ProcessMessages(duration);
/* Stop RT */
swResult = naibrd_1553_RtStop(DevNum);
if(swResult != 0)
{
bQuit = TRUE;
printf("Error: naibrd_1553_RtStop %d", swResult);
return bQuit;
}
/* Disable Interrupts */
swResult = naibrd_1553_SetIrqManipulate(DevNum, 0x0, 0xFFFFFFFF, myIsr);
if(swResult != 0)
{
bQuit = TRUE;
printf("Error: naibrd_1553_SetIrqManipulate %d", swResult);
return bQuit;
}
}
else
bContinue = FALSE;
}
/* Uninstall ISR */
swResult = naibrd_UninstallISR(cardIndex);
/* Free 1553 Device */
swResult = naibrd_1553_Free(DevNum);
if(swResult != 0)
{
bQuit = TRUE;
printf("Error: naibrd_1553_Free %d", swResult);
return bQuit;
}
return bQuit;
}
static void myIsr(void* param, uint32_t vector)
{
#if defined (WIN32)
UNREFERENCED_PARAMETER(param);
UNREFERENCED_PARAMETER(vector);
#endif
#if defined (__VXWORKS__)
/* Get the vector that caused the interrupt */
vector = nai_Onboard_GetInterruptVector();
logMsg("\nvector = %d deviceNumber = %d\n", vector, deviceNumber, 2, 3, 4, 5);
/* Clear Interrupt */
nai_Onboard_ClearInterrupt();
#endif
receivedVector = vector;
/* Set the global interrupt flag */
irqFlag = 1;
irqCount++;
}
static int ProcessMessages(int32_t duration)
{
time_t end;
uint32_t swResult;
int32_t i;
naiDecodedMessageStructure DecodedMsgStruct;
uint16_t wsBuffer[72] = { 0x0000 };
int32_t count = 0;
uint16_t status1, status2;
end = time(NULL) + duration;
/* While looping for the user specified duration of time, poll on the global irqFlag and if it is set (interrupt received), */
/* reset the flag, clear the interrupt status registers, clear interrupt latch bit and process new 1553 message, if any. */
while (time(NULL) < end)
{
if (irqFlag)
{
irqFlag = 0;
/* Display the Interrupt Vector */
printf("\nReceived Vector: 0x%08X", receivedVector);
/* Read to clear status registers */
swResult = naibrd_1553_GetIntStatus(deviceNumber, &status1, &status2);
if (swResult != NAI_SUCCESS)
{
printf("\nERROR: naibrd_1553_GetIntStatus - %d\n", swResult);
}
if (status1 & NAI_1553_INT_STS_REG1_MASK_END_OF_MESSAGE)
{
printf("\nEnd Of Message interrupt triggered. IrqCount = %d\n", irqCount);
}
else if (status1 & NAI_1553_INT_STS_REG1_MASK_TIME_TAG_ROLLOVER)
{
printf("\nTime Tag Rollover interrupt triggered. IrqCount = %d\n", irqCount);
}
else
{
printf("\nOther interrupt triggered. status1=0x%04X status2=0x%04X IrqCount=%d\n", status1, status2, irqCount);
}
/* Clear Latch Bit */
swResult = naibrd_1553_ClearIntLatch(deviceNumber);
if (swResult != NAI_SUCCESS)
{
printf("\nERROR: naibrd_1553_ClearIntLatch - %d\n", swResult);
}
/* Get Data */
/* If the stack pointer has updated (new message arrived), read one message at a time */
swResult = naibrd_1553_RtMessageGetFromStackRaw(deviceNumber, wsBuffer, NAI_1553_MAX_MESSAGE_SIZE_RT);
if (swResult < 0)
{
printf("ERROR: naibrd_1553_RtMessageGetFromStackRaw %d\n\n", swResult);
}
else if (swResult > 0)
{
/* Decode Raw Message */
swResult = naibrd_1553_RtMessageDecodeRaw(deviceNumber, wsBuffer, &DecodedMsgStruct);
if (swResult < 0)
{
printf("ERROR: naibrd_1553_RtMessageDecodeRaw %d\n\n", swResult);
}
if ((DecodedMsgStruct.wCommandWord1 & 0x0400) != 0x0400) /* If this is a Rx message */
{
printf("Rx Msg Received\n");
printf("\n\nDecoded Message:\n\n");
printf("Block Status - 0x%04X\n", DecodedMsgStruct.wBlockStatus);
printf("Time Tag - 0x%04X\n", DecodedMsgStruct.wTimeTag);
printf("Command Word - 0x%04X\n", DecodedMsgStruct.wCommandWord1);
printf("Data Word Count - 0x%04X\n", DecodedMsgStruct.wDataWordCount);
printf("Data:");
for (i = 0; i < DecodedMsgStruct.wDataWordCount; i++)
{
if (i % 8 == 0)
{
printf("\n");
}
printf("0x%04X ", DecodedMsgStruct.waData[i]);
}
printf("count: %d\n", count++);
printf("\n\n");
}
else
{
printf("Tx Msg Received\n");
}
}
}
#if defined (__VXWORKS__)
taskDelay(1);
#endif
}
return 1;
}