nai can int
Edit this on GitLab
nai can int
Explanation
About
The provided C sample code is designed for interacting with North Atlantic Industries' (NAI) embedded function modules, specifically focusing on Controller Area Network (CAN) functionalities using NAI’s System Software Kit (SSK). The code includes functions for setting up CAN interrupts, handling CAN events, and displaying CAN message information. Below is a detailed explanation of each function and its use within the code.
Includes
Standard Libraries:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
NAI Specific Libraries: These libraries provide necessary functions and macros for interacting with the NAI hardware.
#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"
#include "nai_can_int.h"
#include "nai_can_cfg.h"
#include "nai.h"
#include "naibrd.h"
#include "naibrd_ether.h"
#include "functions/naibrd_can.h"
#include "maps/nai_map_can.h"
Function Prototypes
void getFIFODataFromInterruptChannels(uint8_t status, FIFO* fifoData[NAI_GEN5_CAN_MAX_CHANNEL_COUNT], int32_t minChannel, int3232 maxChannel);
This function prototype is defined to get FIFO data from interrupt channels.
Main Functions
CAN_checkForInterrupt
bool_t CAN_checkForInterrupt(CanConfig inputCANConfig) {
// Function logic here...
}
This function prompts the user to check if a CAN interrupt has occurred and if so, it processes the interrupt status. It continually checks for user input to either check for interrupts or quit. If an interrupt has occurred, it retrieves and displays the status.
configureCANToInterruptOnRx
void configureCANToInterruptOnRx(InterruptConfig inputInterruptConfig, CanConfig inputCANConfig) {
// Function logic here...
}
This function configures the CAN module to generate interrupts when messages are received. It sets up the appropriate interrupt vectors, edge/level triggering, and interrupt steering.
DisplayMessage_CANInterrupt
void DisplayMessage_CANInterrupt(int32_t msgId) {
// Function logic here...
}
This function displays various messages to the user based on the message ID passed. It is used to inform the user about the status and actions required for CAN interrupts.
enableCANInterrupts
void enableCANInterrupts(CanConfig inputCANConfig, bool_t enable) {
// Function logic here...
}
This function enables or disables CAN interrupts for channels within a specified range. It sets the enable register values based on the input configuration.
GetCANLatchStatusTriggerMode
bool_t GetCANLatchStatusTriggerMode(int32_t* interrupt_Edge_Trigger) {
// Function logic here...
}
This function prompts the user to specify the trigger mode (edge-triggered or level-triggered) for the CAN status register.
basic_ISR_CAN
#if defined (__VXWORKS__)
void basic_ISR_CAN(uint32_t param)
#else
void basic_ISR_CAN(void *param, uint32_t vector)
#endif
{
// ISR logic here...
}
This interrupt service routine (ISR) handles CAN interrupts. It alerts the CAN_checkForInterrupt
function that an interrupt has occurred, captures the interrupt vector, and clears the interrupt as necessary.
handleCANInterrupt
void handleCANInterrupt(uint32_t nVector) {
// Function logic here...
}
This function processes the CAN interrupt, obtains the FIFO data for all channels that triggered the interrupt, prints the interrupt information, and deallocates memory used for FIFO data.
getFIFODataFromInterruptChannels
void getFIFODataFromInterruptChannels(uint8_t status, FIFO* fifoData[NAI_GEN5_CAN_MAX_CHANNEL_COUNT], int32_t minChannel, int32_t maxChannel) {
// Function logic here...
}
This function retrieves FIFO data for all channels that have their status bit set in the status register. It processes the FIFO data and updates the status and frame counters.
printInterruptInformation_CAN
void printInterruptInformation_CAN(CanConfig inputCANConfig, int32_t interruptID, uint8_t status, FIFO* fifoData[NAI_GEN5_CAN_MAX_CHANNEL_COUNT], bool_t isEther, FILE* stream) {
// Function logic here...
}
This function prints detailed information about the CAN interrupt, including FIFO data for each channel, the interrupt vector or ID, and the status register.
promptUserToClearInterrupt_CAN
void promptUserToClearInterrupt_CAN() {
// Function logic here...
}
This function prompts the user to clear the received CAN interrupt. It continually checks for user input to proceed with clearing the interrupt.
ClearInterrupt_CAN
void ClearInterrupt_CAN() {
// Function logic here...
}
This function clears the CAN interrupt by reading and clearing the status register.
Types and Enumerations
bool_t
This type is commonly used for boolean values, defined as TRUE or FALSE.
CanConfig
This structure holds configuration details for CAN communication, such as card index, module, and channel ranges.
InterruptConfig
This structure holds configuration details for interrupts, such as edge trigger and steering options.
FIFO
Holds FIFO data, including buffers and status information for each CAN channel.
nai_can_status_type_t
Represents various CAN status types, such as NAI_CAN_STATUS_RECV_MSG_LATCHED
.
Summary
This application provides a comprehensive toolkit for setting up and handling CAN interrupts using NAI’s embedded function modules. Each function covers specific aspects of the CAN communication and interrupt handling process, ensuring that the software can effectively manage and respond to CAN events.
#include <stdio.h>
#include <stdlib.h>
#include <string.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"
/* Common CAN Sample Program include files */
#include "nai_can_int.h"
#include "nai_can_cfg.h"
/* naibrd include files */
#include "nai.h"
#include "naibrd.h"
#include "naibrd_ether.h"
#include "functions/naibrd_can.h"
#include "maps/nai_map_can.h"
/***********************/
/* Function Prototypes */
/***********************/
void getFIFODataFromInterruptChannels(uint8_t status, FIFO* fifoData[NAI_GEN5_CAN_MAX_CHANNEL_COUNT], int32_t minChannel, int32_t maxChannel);
/**************************************************************************************************************/
/**
<summary>
Prompts user to check if an interrupt has occurred. MyIsr() should be installed if using this function.
</summary>
*/
/**************************************************************************************************************/
bool_t CAN_checkForInterrupt(CanConfig inputCANConfig) {
bool_t bQuit;
uint8_t status;
int8_t inputBuffer[80];
int32_t inputResponseCnt;
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_CAN_GetStatusRaw(inputCANConfig.cardIndex, inputCANConfig.module, NAI_CAN_STATUS_RECV_MSG_LATCHED, &status);
printf("\nVector = %#x \n", interruptVector);
printf("Status = %#x \n", status);
interruptOccured = FALSE;
}
else {
printf("\nNo Interrupt Occurred");
}
printf("\n\nWould you like to clear the status register? (default:N):");
bQuit = naiapp_query_ForQuitResponse(sizeof(inputBuffer), NAI_QUIT_CHAR, inputBuffer, &inputResponseCnt);
if (inputBuffer[0] == 'y' || inputBuffer[0] == 'Y')
{
naibrd_CAN_ClearStatusRaw(inputCANConfig.cardIndex, inputCANConfig.module, NAI_CAN_STATUS_RECV_MSG_LATCHED, status);
}
}
}
return bQuit;
}
/**************************************************************************************************************/
/**
<summary>
This function configures an interrupt to occur when a message is received on any of the can channels.
</summary>
*/
/**************************************************************************************************************/
void configureCANToInterruptOnRx(InterruptConfig inputInterruptConfig, CanConfig inputCANConfig) {
int32_t cardIndex = inputCANConfig.cardIndex;
int32_t module = inputCANConfig.module;
int32_t vector = NAI_CAN_INTERRUPT_VECTOR;
int32_t interrupt_Edge_Trigger = inputInterruptConfig.interrupt_Edge_Trigger;
int32_t steering = inputInterruptConfig.steering;
nai_can_status_type_t type = NAI_CAN_STATUS_RECV_MSG_LATCHED;
/* clear interruptConfigs of previous channels */
check_status(naibrd_CAN_SetIntEnableRaw(cardIndex, module, 0));
check_status(naibrd_CAN_ClearStatusRaw(cardIndex, module, type, 0xFFFF));
check_status(naibrd_CAN_SetIntVector(cardIndex, module, 1, type, vector));
check_status(naibrd_CAN_SetInterruptEdgeLevel(cardIndex, module, type, interrupt_Edge_Trigger)); /* Edge triggered */
check_status(naibrd_CAN_SetInterruptSteering(cardIndex, module, type, steering));
}
/**************************************************************************************************************/
/**
<summary>
DisplayMessage_CANInterrupt handles displaying the messages associated with the msgId passed in.
</summary>
*/
/**************************************************************************************************************/
void DisplayMessage_CANInterrupt(int32_t msgId)
{
switch (msgId)
{
case (int32_t)MSG_BANNER_CAN_INT:
{
printf("\n********************************************************************************");
printf("\n****** CAN INTERRUPT ******");
printf("\nAn interrupt will occur when the CAN module receives a message ");
printf("\n********************************************************************************");
}
break;
case (int32_t)MSG_USER_TRIGGER_CAN_INT:
{
printf("\nPress \"Q\" to quit the application.\nPlease trigger CAN interrupt (Recv Msg):");
}
break;
case (int32_t)MSG_USER_CLEAR_CAN_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 enableCANInterrupts(CanConfig inputCANConfig, bool_t enable) {
int32_t channel;
int32_t enableRegVal = 0;
int32_t isEnabled = 0;
for (channel = inputCANConfig.minChannel; channel <= inputCANConfig.maxChannel; channel++)
{
isEnabled = 1 << (channel - 1);
if (enable)
enableRegVal = (1 << (channel - 1)) | enableRegVal;
else if (isEnabled & enableRegVal)
enableRegVal = (1 << (channel - 1)) ^ enableRegVal;
}
naibrd_CAN_SetIntEnableRaw(inputCANConfig.cardIndex, inputCANConfig.module, enableRegVal);
}
/**************************************************************************************************************/
/**
<summary>
GetCANLatchStatusTriggerMode handles prompting the user for the trigger mode for the latched status register
(Edge Triggered or Level Triggered).
</summary>
*/
/**************************************************************************************************************/
bool_t GetCANLatchStatusTriggerMode(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=0): ");
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 = 0;
}
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_CAN(uint32_t param)
#else
void basic_ISR_CAN(void *param, uint32_t vector)
#endif
{
interruptOccured = TRUE;
#if defined (__VXWORKS__)
interruptVector = nai_Onboard_GetInterruptVector();
nai_Onboard_ClearInterrupt();
#elif defined (WIN32)
UNREFERENCED_PARAMETER(param);
interruptVector = vector;
#else
interruptVector = vector;
#endif
}
/**************************************************************************************************************/
/**
<summary>
This routine takes in the vector of the CAN 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 handleCANInterrupt(uint32_t nVector) {
FIFO* fifo[NAI_GEN5_CAN_MAX_CHANNEL_COUNT];
uint8_t status;
int32_t maxChannel;
int32_t channel;
maxChannel = inputCANConfig.maxChannel;
printf("\n\nInterrupt Occurred \n\n");
if (inputInterruptConfig.bPromptForInterruptClear)
{
promptUserToClearInterrupt_CAN();
}
naibrd_CAN_GetStatusRaw(inputCANConfig.cardIndex, inputCANConfig.module, NAI_CAN_STATUS_RECV_MSG_LATCHED, &status);
naibrd_CAN_ClearStatusRaw(inputCANConfig.cardIndex, inputCANConfig.module, NAI_CAN_STATUS_RECV_MSG_LATCHED, status);
for (channel = inputCANConfig.minChannel; channel <= inputCANConfig.maxChannel; channel++)
{
fifo[channel - 1] = allocateSpaceForFIFO(MAX_FIFO_COUNT, inputCANConfig.maxPayload);
}
getFIFODataFromInterruptChannels(status, fifo, inputCANConfig.minChannel, maxChannel);
printInterruptInformation_CAN(inputCANConfig, nVector, status, fifo, FALSE, fifoDataFile);
for (channel = inputCANConfig.minChannel; channel < inputCANConfig.maxChannel; channel++)
{
deallocSpaceForFIFO(fifo[channel - 1]);
fifo[channel - 1] = NULL;
}
}
/**************************************************************************************************************/
/**
<summary>
Gets the fifo data of all channels whose status bit are set in status.
</summary>
*/
/**************************************************************************************************************/
void getFIFODataFromInterruptChannels(uint8_t status, FIFO* fifoData[NAI_GEN5_CAN_MAX_CHANNEL_COUNT], int32_t minChannel, int32_t maxChannel)
{
int32_t channel = 1;
uint8_t statusBitSet;
int32_t cardIndex = inputCANConfig.cardIndex;
int32_t module = inputCANConfig.module;
int32_t bufferLength;
CanDataFrame* buffer;
uint32_t* fifoStatus;
for (channel = minChannel; channel <= maxChannel; ++channel)
{
/* Check all status elements */
statusBitSet = status & (1 << (channel - 1));
if (statusBitSet && fifoData[channel - 1] != NULL)
{
buffer = fifoData[channel - 1]->buffer;
bufferLength = fifoData[channel - 1]->maxFramesOnFifo;
fifoStatus = &fifoData[channel - 1]->fifoStatus;
fifoData[channel - 1]->numOfFramesOnFifo = getFIFOChannelData(cardIndex, module, channel, buffer, bufferLength);
check_status(naibrd_CAN_GetFifoStatusRaw(cardIndex, module, channel, fifoStatus));
frameCount = frameCount + (fifoData[channel - 1]->numOfFramesOnFifo);
}
}
}
/**************************************************************************************************************/
/**
<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_CAN(CanConfig inputCANConfig, int32_t interruptID, uint8_t status, FIFO* fifoData[NAI_GEN5_CAN_MAX_CHANNEL_COUNT], bool_t isEther, FILE* stream)
{
uint8_t statusBitSet;
int32_t channel;
uint32_t fifoStatus;
CanDataFrame* buffer;
int32_t bufferLength;
printf("\n");
fprintf(stream, "Interrupt Information\n");
fprintf(stream, "-----------------------------------\n");
if (isEther)
fprintf(stream, "\nIDR ID = %#x \n", interruptID);
else
fprintf(stream, "\nVector = %#x \n", interruptID);
fprintf(stream, "Status = %#x \n", status);
for (channel = inputCANConfig.minChannel; channel <= inputCANConfig.maxChannel; ++channel)
{
statusBitSet = status & (1 << (channel - 1));
if (statusBitSet && fifoData[channel - 1] != NULL)
{
fifoStatus = fifoData[channel - 1]->fifoStatus;
buffer = fifoData[channel - 1]->buffer;
bufferLength = fifoData[channel - 1]->numOfFramesOnFifo;
fprintf(stream, "\n");
printFIFOStatusRx(fifoStatus, stream);
fprintf(stream, "\n");
printFIFOChannelData(channel, buffer, bufferLength, stream);
fprintf(stream, "\n\n");
}
}
fprintf(stream, "\nFrames Rx = %d", frameCount);
fprintf(stream, "\n-----------------------------------\n");
}
void promptUserToClearInterrupt_CAN()
{
/* Prompt the user to clear the interrupt received */
SetUserRequestClearInt(FALSE);
printf("\n");
DisplayMessage_CANInterrupt(MSG_USER_CLEAR_CAN_INT);
/* Wait for the user to respond */
while (!GetUserRequestClearInt())
{
nai_msDelay(10);
}
}
void ClearInterrupt_CAN()
{
nai_status_bit_t status;
if (inputInterruptConfig.bPromptForInterruptClear)
{
promptUserToClearInterrupt_CAN();
}
naibrd_CAN_GetStatusRaw(inputCANConfig.cardIndex, inputCANConfig.module, NAI_CAN_STATUS_RECV_MSG_LATCHED, &status);
naibrd_CAN_ClearStatusRaw(inputCANConfig.cardIndex, inputCANConfig.module, NAI_CAN_STATUS_RECV_MSG_LATCHED, status);
}