CAN Transmit
Edit this on GitLab
CAN Transmit
Explanation
About the Sample Application Code
This C sample application illustrates how to interact with the Gen5 CAN module from North Atlantic Industries (NAI) utilizing their Single Board Computer Starter Kit (SSK). The code demonstrates how to select a CAN channel and transmit data either generated or read from a file. Below is an explanation and walkthrough of the provided code.
General Overview
Function Overview - Main Function: The code begins execution here, setting up the environment and facilitating board access. - Run_CAN_Transmit: This function handles the data transmission process over the CAN channel. - generateFIFOData: Generates random CAN frames for transmission. - generateFrame: Fills the CAN frame with random data. - QueryForTransmissionSource: Determines whether to generate data or read from a file. - readPayloadFromFile: Reads CAN frame payloads from a file.
Included Header Files
- Standard Libraries: These include standard C libraries like stdio.h
, stdlib.h
, string.h
, and time.h
.
- NAI Specific Libraries: These libraries enable access to board functionalities and CAN-specific configurations.
Detailed Walkthrough
Main Function Execution
#if defined (__VXWORKS__)
int32_t Run_CAN_Transmit_Main(void)
#else
int32_t main(void)
#endif
{
// Boilerplate code for run-time environment setup
}
Key Operations
-
Initialization:
-
initializeCANConfigurations: Configures CAN settings like payload size and baud rate.
-
-
User Interaction Loop:
-
Repeatedly prompts the user to select a card index and module, checks the module type, and initiates transmission if appropriate.
-
-
Transmission Invocation:
-
Calls
Run_CAN_Transmit
if the selected module and channel are valid for transmission.
-
Run_CAN_Transmit Function Execution
This function performs the main task of transmitting data over a selected CAN channel.
Key Operations
-
User Query for Channel:
-
Asks the user to select a CAN channel for transmission.
-
-
Protocol Setting:
-
Configures the communication protocol based on the module type (e.g., J1939 or AB).
-
-
Timing and Source Query:
-
Prompts the user for CAN timing settings and the source of transmission data (generate or read from a file).
-
-
Payload Reading:
-
Depending on the source, it either generates data or reads from a file.
-
-
Data Transmission:
-
Configures the channel and transmits the CAN data using the
Cfg_Tx_CAN
andtransmitAllFIFOData_PGN
functions.
-
Supporting Functions
generateFIFOData
Generates random data frames for each channel within specified payload limits.
static void generateFIFOData(FIFO* fifoData[NAI_GEN5_CAN_MAX_CHANNEL_COUNT], int32_t numOfFrames, int32_t minPayload, int32_t maxPayload, int32_t min, int32_t max)
{
// Random data frame generation logic
}
generateFrame
Fills the provided buffer with random data bytes.
static void generateFrame(uint32_t* buffer, int32_t length)
{
// Random byte generation for CAN frame
}
QueryForTransmissionSource
Queries the user on whether to generate input data or read it from a file.
static bool_t QueryForTransmissionSource(bool_t* generateInput)
{
// User query logic
}
readPayloadFromFile
Reads CAN frame data from a file and prepares it for transmission.
static void readPayloadFromFile(FILE* inputFile, int32_t channel, FIFO* fifoData[NAI_GEN5_CAN_MAX_CHANNEL_COUNT])
{
// File reading and frame preparation logic
}
Summary
This sample application demonstrates the process of selecting a CAN channel and transmitting data using NAI embedded function modules. It sets the groundwork for real-world applications where a user needs to interact with CAN modules programmatically. The provided functions and their orchestrations ensure seamless user interaction, protocol configuration, and data transmission over the CAN network.
/**************************************************************************************************************/
/**
<summary>
This sample application lets you select a channel from a Gen5 CAN module and transmit on it.
</summary>
*/
/**************************************************************************************************************/
#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 CAN Sample Program include files */
#include "nai_can_cfg.h"
/* naibrd include files */
#include "nai.h"
#include "naibrd.h"
#include "functions/naibrd_can.h"
#include "naibrd_ether.h"
#include "advanced/nai_ether_adv.h"
/********************/
/* Application Name */
/********************/
static const int8_t *CONFIG_FILE = (int8_t *)"default_CANTx.txt";
/********************************/
/* Internal Function Prototypes */
/********************************/
static bool_t Run_CAN_Transmit(void);
int32_t Run_CAN_Transmit_Main(void);
static void generateFrame(uint32_t* buffer,int32_t length);
static void generateFIFOData(FIFO* fifoData[NAI_GEN5_CAN_MAX_CHANNEL_COUNT],int32_t numOfFrames,int32_t minPayload,int32_t maxPayload,int32_t min, int32_t max);
static bool_t QueryForTransmissionSource(bool_t* generateInput);
static void readPayloadFromFile(FILE* inputFile,int32_t channel,FIFO* fifoData[NAI_GEN5_CAN_MAX_CHANNEL_COUNT]);
/**************************************************************************************************************/
/**
<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 Run_CAN_Transmit_Main(void)
#else
int32_t main(void)
#endif
{
bool_t stop = FALSE;
int32_t moduleCnt;
int32_t channelCount;
int8_t inputBuffer[80];
int32_t inputResponseCnt;
initializeCANConfigurations(0, 0, 0, 0, 0, 0, MAX_CAN_PAYLOAD_AB, 8, NAI_CAN_500K_BAUD);
if (naiapp_RunBoardMenu(CONFIG_FILE) == (bool_t)TRUE)
{
while (stop != TRUE)
{
/* Select Card Index */
stop = naiapp_query_CardIndex(naiapp_GetBoardCnt(), 0, &inputCANConfig.cardIndex);
if (stop != TRUE)
{
check_status(naibrd_GetModuleCount(inputCANConfig.cardIndex, &moduleCnt));
/* Select Module */
stop = naiapp_query_ModuleNumber(moduleCnt, 1, &inputCANConfig.module);
if (stop != TRUE)
{
inputCANConfig.modid = naibrd_GetModuleID(inputCANConfig.cardIndex, inputCANConfig.module);
channelCount = naibrd_CAN_GetChannelCount(inputCANConfig.modid);
if ((channelCount != 0))
{
Run_CAN_Transmit();
}
else
{
printf(" *** Module selection not recognized as valid module type for this application. ***\n\n");
}
}
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>
CAN_Transmit lets you generate or read data from a file and transmit it on a particular can channel.
</summary>
*/
/**************************************************************************************************************/
static bool_t Run_CAN_Transmit(void)
{
int32_t numOfFramesToTransmit;
FIFO* fifoData[NAI_GEN5_CAN_MAX_CHANNEL_COUNT];
FILE* fifoInputFile = NULL;
bool_t generateInput = FALSE;
bool_t bContinue;
int32_t maxChannel;
int32_t payload = 0;
uint32_t PGN = 0;
int32_t channel;
bool_t isJ1939 = TRUE;
bool_t bQuit = FALSE;
int8_t inputBuffer[80];
int32_t inputResponseCnt;
maxChannel = naibrd_CAN_GetChannelCount(inputCANConfig.modid);
inputCANConfig.minChannel = 1;
inputCANConfig.maxChannel = maxChannel;
printf("\nWhich channel would you like to Transmit on? \n");
bQuit = naiapp_query_ChannelNumber(inputCANConfig.maxChannel, inputCANConfig.minChannel, &channel);
if(!bQuit)
{
if( inputCANConfig.modid == NAI_MODULE_ID_CB3 || inputCANConfig.modid == NAI_MODULE_ID_CB6 )
{
bQuit = QueryForChannelProtocol(&isJ1939);
if(isJ1939 && !bQuit)
{
check_status(naibrd_CAN_SetProtocol(inputCANConfig.cardIndex, inputCANConfig.module, channel, NAI_CAN_PROTOCOL_J1939));
}
else if(!bQuit)
{
check_status(naibrd_CAN_SetProtocol(inputCANConfig.cardIndex, inputCANConfig.module, channel, NAI_CAN_PROTOCOL_AB));
}
}
else if(inputCANConfig.modid == NAI_MODULE_ID_CB2)
isJ1939 = TRUE;
else if(inputCANConfig.modid == NAI_MODULE_ID_CB1)
isJ1939 = FALSE;
}
numOfFramesToTransmit = 1;
if(!bQuit)
{
bQuit = QueryUserForCANTiming(&inputCANConfig.baudRate,isJ1939);
}
if(!bQuit)
{
bQuit = QueryForTransmissionSource(&generateInput);
}
if(IsCAN_AB(inputCANConfig.cardIndex, inputCANConfig.module,channel))
{
inputCANConfig.maxPayload = MAX_CAN_PAYLOAD_AB;
inputCANConfig.minPayload = 1;
}
else if(IsCAN_J1939(inputCANConfig.cardIndex, inputCANConfig.module,channel))
{
/* prompt user for pgn */
if(!bQuit)
bQuit = QueryForPGN(&PGN);
if(PGN >= 0xFF00 && PGN <= 0xFFFF) /*proprietary B message can have less than 8 bytes*/
{
inputCANConfig.minPayload = 0;
}
else
{
inputCANConfig.minPayload = 8;
}
inputCANConfig.maxPayload = NAI_J1939_MAX_DATA_LEN;
}
printf("\n");
if( !bQuit && generateInput )
{
bQuit = QueryForPayload(&payload,inputCANConfig.minPayload,inputCANConfig.maxPayload);
}
else if(!bQuit)
{
fifoInputFile = fopen("transmitInputFile.txt","r");
if(fifoInputFile == NULL)
{
printf("No input file found. Please provide the inputFile transmitInputFile.txt in the working directory. \n\n");
bQuit = TRUE;
}
else if(!bQuit)
{
printf("Reading Input from file \n");
}
}
if (!bQuit)
{
bContinue = TRUE;
/* Configure channel to transmit */
inputCANConfig.minChannel = channel;
inputCANConfig.maxChannel = channel;
Cfg_Tx_CAN(inputCANConfig);
if(IsCAN_J1939(inputCANConfig.cardIndex, inputCANConfig.module,channel))
{
nai_msDelay(250);
printf("\n");
claimAddresses(inputCANConfig.cardIndex,inputCANConfig.module, channel, channel);
}
/* Configure channel to Rx (Needed by other devices wishing to claim addresses) */
setRxEnable(inputCANConfig.cardIndex,inputCANConfig.module,channel , channel ,TRUE);
/* allocate fifo */
fifoData[channel - 1] = allocateSpaceForFIFO(numOfFramesToTransmit,inputCANConfig.maxPayload);
while (bContinue)
{
printf("\nPress Enter to Begin Transmission...Or Press Q to quit:\n");
bQuit = naiapp_query_ForQuitResponse(sizeof(inputBuffer), NAI_QUIT_CHAR, inputBuffer, &inputResponseCnt);
if (!bQuit)
{
if(generateInput)
{
generateFIFOData(fifoData, numOfFramesToTransmit,payload,payload,channel,channel);
}
else
{
readPayloadFromFile(fifoInputFile,channel,fifoData);
}
transmitAllFIFOData_PGN(inputCANConfig.cardIndex,inputCANConfig.module, PGN,fifoData,inputCANConfig.minChannel,inputCANConfig.maxChannel);
printf("fifo DATA Transmitted\n");
printf("-----------------------");
printf("\n");
printAllFIFOData(fifoData,stdout,inputCANConfig.minChannel,inputCANConfig.maxChannel);
printf("\n");
printf("\n");
}
else
{
bContinue = FALSE;
}
}
deallocSpaceForFIFO(fifoData[channel -1]);
}
if(!generateInput && fifoInputFile != NULL)
fclose(fifoInputFile);
return bQuit;
}
static void generateFIFOData(FIFO* fifoData[NAI_GEN5_CAN_MAX_CHANNEL_COUNT],int32_t numOfFrames,int32_t minPayload,int32_t maxPayload,int32_t min, int32_t max)
{
int32_t frames;
int32_t channel;
int32_t length;
srand((unsigned int)time(NULL));
for(channel = min; channel <= max; channel++)
{
fifoData[channel-1]->numOfFramesOnFifo = 0;
if(fifoData[channel-1] != NULL)
{
for(frames = 0; frames < numOfFrames && frames < fifoData[channel-1]->maxFramesOnFifo; frames++)
{
length = -1;
while(length < minPayload)
{
length = rand() % (maxPayload+1);
}
generateFrame(fifoData[channel-1]->buffer[frames].data,length);
fifoData[channel-1]->buffer[frames].length = length;
fifoData[channel-1]->numOfFramesOnFifo++;
}
}
}
}
static void generateFrame(uint32_t* buffer,int32_t length)
{
int32_t i;
uint8_t byte;
for(i = 0; i < length; i++)
{
byte = rand() % 16;
buffer[i] = byte;
}
}
/**************************************************************************************************************/
/**
<summary>
query user to get transmission data from file or from generating.
</summary>
*/
/**************************************************************************************************************/
static bool_t QueryForTransmissionSource(bool_t* generateInput)
{
bool_t bQuit = FALSE;
int8_t inputBuffer[80];
int32_t inputResponseCnt;
printf("\nWould you like to generate input? No(N) or Yes(Y) (Default: Y): ");
bQuit = naiapp_query_ForQuitResponse(sizeof(inputBuffer), NAI_QUIT_CHAR, inputBuffer, &inputResponseCnt);
if (!bQuit)
{
if ((inputBuffer[0] == 'N') || (inputBuffer[0] == 'n'))
{
*generateInput = FALSE;
}
else
{
*generateInput = TRUE;
}
}
return bQuit;
}
/**************************************************************************************************************/
/**
<summary>
Takes file open for reading and reads line by line and extracts CAN payload.
</summary>
*/
/**************************************************************************************************************/
static void readPayloadFromFile(FILE* inputFile,int32_t channel,FIFO* fifoData[NAI_GEN5_CAN_MAX_CHANNEL_COUNT])
{
char line[1000];
uint32_t lineIndex;
int32_t byteNum = 0;
char byte[2];
char* ptr;
CanDataFrame* frame = fifoData[channel-1]->buffer;
/* byteArray */
rewind(inputFile);
if(frame != NULL)
{
while( fgets(line,1000,inputFile) != NULL )
{
for(lineIndex = 0; lineIndex < strlen(line) && byteNum < frame->maxLength ;lineIndex++)
{
if(line[lineIndex] != '#' ) /* Line is not comment in txt file */
{
if(line[lineIndex] == ',')
{
byte[0] = line[lineIndex + 1];
byte[1] = line[lineIndex + 2];
frame->data[byteNum] = (uint8_t)strtol(byte,&ptr,16);
byteNum++;
}
else if(lineIndex == 0)
{
byte[0] = line[lineIndex];
byte[1] = line[lineIndex + 1];
frame->data[byteNum] = (uint8_t)strtol(byte,&ptr,16);
byteNum++;
}
}
else
{
lineIndex = (uint32_t)strlen(line);
}
}
}
frame->length = byteNum;
fifoData[channel-1]->numOfFramesOnFifo = 1;
}
}