Integrator Resources

The official home for NAI Support

Not sure where to start? Try Quick Start Guide or ask a question below!

Toggle Components with Visual Button
JavaScript Form Processing

CAN Transmit

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

  1. Initialization:

    • initializeCANConfigurations: Configures CAN settings like payload size and baud rate.

  2. User Interaction Loop:

    • Repeatedly prompts the user to select a card index and module, checks the module type, and initiates transmission if appropriate.

  3. 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

  1. User Query for Channel:

    • Asks the user to select a CAN channel for transmission.

  2. Protocol Setting:

    • Configures the communication protocol based on the module type (e.g., J1939 or AB).

  3. Timing and Source Query:

    • Prompts the user for CAN timing settings and the source of transmission data (generate or read from a file).

  4. Payload Reading:

    • Depending on the source, it either generates data or reads from a file.

  5. Data Transmission:

    • Configures the channel and transmits the CAN data using the Cfg_Tx_CAN and transmitAllFIFOData_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;
   }
}

Help Bot

X