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

SER Recv Summary

SER Recv Summary

Explanation

About the Code

This provided sample code is a C program designed to interact with embedded function modules via the North Atlantic Industries (NAI) System Software Kit (SSK). Specifically, this example focuses on configuring and using serial communication channels to receive data in a summarized manner. Here’s a detailed breakdown and explanation of the components and flow of the application.

Header Files and Definitions

Included Headers - Standard Headers: - <stdio.h>: for standard input/output. - <stdlib.h>: for utility functions, memory allocation, etc. - <string.h>: for string manipulation functions. - <time.h>: for time-related functions. - <ctype.h>: for character classification and conversion functions. - Platform-specific Headers: - vxBusLib.h and logLib.h: specific to VxWorks OS, for bus and logging support respectively.

  • NAI Common Sample Program Include Files:

  • "naiapp_boardaccess_menu.h"

  • "naiapp_boardaccess_query.h"

  • "naiapp_boardaccess_access.h"

  • "naiapp_boardaccess_display.h"

  • "naiapp_boardaccess_utils.h"

  • NAI Specific Include Files:

  • "nai.h"

  • "naibrd.h"

  • "functions/naibrd_ser.h"

Constants and Global Variables

  • Default Configuration File: CONFIG_FILE = "default_SERRecv_Summary.txt"

  • Default Channel Selection: c #define DEF_SER_CARD_INDEX 0 #define DEF_SER_MODULE 1 #define SER_MAX_RECV 1024 #define SER_MAX_CHANNELS 8

  • Default Configurations: c #define DEF_USE_INTERRUPTS FALSE #define INTERRUPT_VECTOR 0xA0 #define MAX_TIMEOUT 10 #define CLEAR_FIFO_TIMEOUT 1000

  • Global Variable:

  • irqFlag: a global flag used to handle interrupts.

Function Declarations

static bool_t SER_Receive_Summary_Run(int32_t cardIndex, int32_t module, uint32_t moduleID);
static bool_t RxAndDisplayFIFOMsgs(int32_t cardIndex, int32_t module, uint32_t moduleID, bool_t useInterrupt);
static void FetchNewMessagesFromRxFIFO(int32_t cardIndex, int32_t module, int32_t channel);
static bool_t GetInterruptOrPoll(bool_t defUseInterrupt, bool_t* outuseInterrupt);
static void SampleCallBack(void* param, uint32_t vector);

Explanation of the Main Function

The main entry point of the program is defined according to the operating system. For VxWorks, it is named SER_Summary_Sample, otherwise, it is named main.

Main Function Flow

  1. Run Board Menu: c if (naiapp_RunBoardMenu(CONFIG_FILE) == (bool_t)TRUE)

  2. Loop to select card and module: c while (stop != TRUE)

  3. Select Card Index: c stop = naiapp_query_CardIndex(naiapp_GetBoardCnt(), DEF_SER_CARD_INDEX, &cardIndex);

  4. Get Module Count and Select Module: c check_status(naibrd_GetModuleCount(cardIndex, &moduleCnt)); stop = naiapp_query_ModuleNumber(moduleCnt, DEF_SER_MODULE, &module); if (stop != TRUE) moduleID = naibrd_GetModuleID(cardIndex, module);

  5. Run the SER Receive Summary Run Function: c if moduleID != 0 SER_Receive_Summary_Run(cardIndex, module, moduleID);

  6. Query to Quit: c naiapp_query_ForQuitResponse(sizeof(inputBuffer), NAI_QUIT_CHAR, inputBuffer, &inputResponseCnt);

  7. Close all open cards: c naiapp_access_CloseAllOpenCards();

Function Details

SER_Receive_Summary_Run

This function configures the serial channels for receiving messages and determines whether to use polling or interrupts.

  1. Channel Configuration:

    • Clear FIFOs.

    • Set transmission speed.

    • Enable receiver.

  2. Interrupt Configuration (if used):

    • Set interrupt parameters.

    • Install ISR callback.

  3. Polling/Interrupt Handling:

    • Call RxAndDisplayFIFOMsgs.

RxAndDisplayFIFOMsgs

This function handles receiving and displaying FIFO messages based on either polling or interrupts.

  • Polls the Summary Register within the specified duration.

  • If using interrupts, manage IRQ flag and clear summary latched status register.

  • Fetch new messages if any bits in the summary register indicate available data.

  • Print received data.

FetchNewMessagesFromRxFIFO

This function reads the receive FIFO buffer of a specified channel and prints the collected messages.

GetInterruptOrPoll

Asks the user to choose between using interrupts or polling for the summary register status.

SampleCallBack

Handles the interrupt callback. Sets the global irqFlag if the interrupt vector matches the expected value.

Summary

This program effectively demonstrates how to set up and manage serial communication using NAI’s System Software Kit for reading received messages from serial channels. It provides options for both polling and interrupt-driven mechanisms and showcases how to configure each channel, handle received data, and manage interrupts properly. This example serves as a reference to understand the usage of NAI’s embedded function modules and APIs for serial communication.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <ctype.h>

#if defined (__VXWORKS__)
#include "vxBusLib.h"
#endif

/* 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"

/* naibrd include files */
#include "nai.h"
#include "naibrd.h"
#include "functions/naibrd_ser.h"

#if defined (__VXWORKS__)
#include "logLib.h"
#endif

static const int8_t *CONFIG_FILE = (const int8_t *)"default_SERRecv_Summary.txt";

static bool_t SER_Receive_Summary_Run(int32_t cardIndex, int32_t module, uint32_t moduleID);
static bool_t RxAndDisplayFIFOMsgs(int32_t cardIndex, int32_t module, uint32_t moduleID, bool_t useInterrupt);
static void FetchNewMessagesFromRxFIFO(int32_t cardIndex, int32_t module, int32_t channel);
static bool_t GetInterruptOrPoll(bool_t defUseInterrupt, bool_t* outuseInterrupt);
static void SampleCallBack(void* param, uint32_t vector);

/* Default channel selection */
#define DEF_SER_CARD_INDEX          0
#define DEF_SER_MODULE              1
#define SER_MAX_RECV                1024
#define SER_MAX_CHANNELS            8

/* Default channel configuration settings */
#define DEF_USE_INTERRUPTS                FALSE
#define INTERRUPT_VECTOR                  0xA0

#define MAX_TIMEOUT  10          /* 10ms timeout */
#define CLEAR_FIFO_TIMEOUT 1000  /* 1 second */

/* Global Variables */
static bool_t irqFlag = FALSE;

/**************************************************************************************************************/
/** \defgroup SERRxSummary Serial Receive Summary
The purpose of the Serial Receive Summary Sample Application is to illustrate the methods to call in the naibrd
library to configure all serial channels for message receive operation and poll the Rx summary register (or
utilize interrupts) to ascertain which channels contain new data in their respective Rx FIFO buffer. This
application does not transmit any data, the user will have to write their own code to do this or use one of
the other sample applications (SER_Async_LOOPBACK). The summary register is bit-mapped by channel (bit index
zero is channel 1) and mirrors the "Rx Data Available" bit in the Channel Status registers. If unread messages
are present in the FIFO of a particular channel, the corresponding bit will be set to '1' in the Rx summary register.
*/
/**************************************************************************************************************/
#if defined (__VXWORKS__)
int32_t SER_Summary_Sample(void)
#else
int32_t main(void)
#endif
{
   int32_t cardIndex;
   int32_t moduleCnt;
   int32_t module;
   bool_t stop = FALSE;
   uint32_t moduleID;
   int8_t inputBuffer[80];
   int32_t inputResponseCnt;

   if (naiapp_RunBoardMenu(CONFIG_FILE) == (bool_t)TRUE)
   {
      while (stop != TRUE)
      {
         /* Select Card Index */
         stop = naiapp_query_CardIndex(naiapp_GetBoardCnt(), DEF_SER_CARD_INDEX, &cardIndex);
         if (stop != TRUE)
         {
            check_status(naibrd_GetModuleCount(cardIndex, &moduleCnt));

            /* Select Module */
            stop = naiapp_query_ModuleNumber(moduleCnt, DEF_SER_MODULE, &module);
            if (stop != TRUE)
            {
               moduleID = naibrd_GetModuleID(cardIndex, module);
               if ((moduleID != 0))
               {
                  SER_Receive_Summary_Run(cardIndex, module, moduleID);
                  printf("\r\nType Q to quit or Enter to continue:\r\n");
                  stop = naiapp_query_ForQuitResponse(sizeof(inputBuffer), NAI_QUIT_CHAR, inputBuffer, &inputResponseCnt);
               }
            }
         }
      }
   }

   printf("\r\nType the Enter key to exit the program: ");
   naiapp_query_ForQuitResponse(sizeof(inputBuffer), NAI_QUIT_CHAR, inputBuffer, &inputResponseCnt);
   naiapp_access_CloseAllOpenCards();
   return 0;
}
/**************************************************************************************************************/
/**
\ingroup SERRxSummary
Configures all serial channels on a given module for asynchronous internal loopback transmission. The user is
queried if they would like to poll for a summary status change or setup an interrupt to alert them of the condition.
Another application (SER_Async_LOOPBACK) is needed to transmit data and trigger the condition.
\param cardIndex (Input) Logical Card Index assigned to connection with the NAI_BOARD (0 - NAI_MAX_CARDS-1).
\param module    (Input) Module Number of the module to access (1 - [max modules for board]).
\param moduleID  (Input) The ID of the module.
 */
/**************************************************************************************************************/
static bool_t SER_Receive_Summary_Run(int32_t cardIndex, int32_t module, uint32_t moduleID)
{
   bool_t bQuit = FALSE;
   int32_t i, ch;
   bool_t useInterrupts;
   int32_t nCntlValueLo;
   int32_t channelCnt = naibrd_SER_GetChannelCount(moduleID);
   int32_t serChannels[SER_MAX_CHANNELS];

   for (i = 0; i < channelCnt; i++)
   {
      serChannels[i] = i + 1;
   }

   /* Use Interrupts or Poll */
   bQuit = GetInterruptOrPoll(DEF_USE_INTERRUPTS, &useInterrupts);
   if (!bQuit)
   {
      for (ch = 0; ch < channelCnt; ch++)
      {
         naibrd_SER_ClearRxFifo(cardIndex, module, serChannels[ch]);
         naibrd_SER_ClearTxFifo(cardIndex, module, serChannels[ch]);
         nCntlValueLo = NAI_SER_CTRLLO_CLEAR_RX_FIFO | NAI_SER_CTRLLO_CLEAR_TX_FIFO;
         for (i = 0; i < CLEAR_FIFO_TIMEOUT && (nCntlValueLo & (NAI_SER_CTRLLO_CLEAR_RX_FIFO | NAI_SER_CTRLLO_CLEAR_TX_FIFO)); i++)
         {
            nai_ser_chanctrl chanCtrlRaw;
            naibrd_SER_GetChannelControlRaw(cardIndex, module, serChannels[ch], &chanCtrlRaw);
            nCntlValueLo = chanCtrlRaw & 0x0000FFFF;
            nai_msDelay(1);
         }

         /* Set the transmission speed */
         check_status(naibrd_SER_SetProtocol(cardIndex, module, serChannels[ch], NAI_SER_PROTOCOL_ASYNC));       /* Async mode */
         check_status(naibrd_SER_SetInterfaceLevel(cardIndex, module, serChannels[ch], NAI_SER_INTF_LOOPBACK));  /* LoopBack */
         check_status(naibrd_SER_SetBaudrate(cardIndex, module, serChannels[ch], 115200));                       /* 9600 baud */
         check_status(naibrd_SER_SetReceiverEnable(cardIndex, module, serChannels[ch], TRUE));

         /* If using interrupts, configure channel-specific settings */
         if (useInterrupts)
         {
            check_status(naibrd_SER_SetChannelMappedInterruptTriggerType(cardIndex, module, NAI_SER_STATUS_SUMMARY_RX_AVAIL_LATCHED, 0));   /* Level, on all channels */
            check_status(naibrd_SER_SetChannelMappedInterruptEnable(cardIndex, module, NAI_SER_STATUS_SUMMARY_RX_AVAIL_LATCHED, 0xF));
         }
      }

      /* If using interrupts, configure and enable interrupts on the summary status register */
      if (useInterrupts)
      {
         /* Specify callback function for interrupt type */
         check_status(naibrd_InstallISR(cardIndex, NAIBRD_IRQ_ID_ON_BOARD_0, (nai_isr_t)SampleCallBack, NULL));

         /* Set interrupt steering (VME, Onboard_ARM, PCIE or CPCI) */
         check_status(naibrd_SER_SetChannelMappedInterruptSteering(cardIndex, module, NAI_SER_STATUS_SUMMARY_RX_AVAIL_LATCHED, NAIBRD_INT_STEERING_ON_BOARD_0));

         /* Set the interrupt vector */
         check_status(naibrd_SER_SetChannelMappedInterruptVector(cardIndex, module, NAI_SER_STATUS_SUMMARY_RX_AVAIL_LATCHED, INTERRUPT_VECTOR));

         /* Clear summary latched status register to ensure that interrupts can be received */
         check_status(naibrd_SER_ClearChannelMappedStatus(cardIndex, module, NAI_SER_STATUS_SUMMARY_RX_AVAIL_LATCHED, 0xFFFFFFFFu));
      }

      /* Poll the Summary Register and Display Data Received in the Rx FIFO */
      bQuit = RxAndDisplayFIFOMsgs(cardIndex, module, moduleID, useInterrupts);
   }

   return bQuit;
}

/**************************************************************************************************************/
/**
\ingroup SERRxSummary
Queries the user for how long they would like to wait for receive messages then polls (or waits for an interrupt
to occur) to represent new data in the Serial Receive Buffer.
\param cardIndex    (Input) Logical Card Index assigned to connection with the NAI_BOARD (0 - NAI_MAX_CARDS-1).
\param module       (Input) Module Number of the module to access (1 - [max modules for board]).
\param moduleID     (Input) The ID of the module.
\param useInterrupt (Input) Whether or not the user wants to use interrupt on the status.
 */
/**************************************************************************************************************/
static bool_t RxAndDisplayFIFOMsgs(int32_t cardIndex, int32_t module, uint32_t moduleID, bool_t useInterrupt)
{
   bool_t bQuit = FALSE;
   bool_t bContinue = TRUE;
   int32_t chan;
   uint32_t regValue;
   int32_t duration;
   int32_t timeout;
   int32_t maxChannels;
   int8_t inputBuffer[80];
   int32_t inputResponseCnt;

   bContinue = TRUE;

   /* Get count of all channels on the module */
   maxChannels = naibrd_SER_GetChannelCount(moduleID);

   while (bContinue)
   {
      printf("\nType duration (in seconds) for serial receive messages test or %c to quit (default: 5) : ", NAI_QUIT_CHAR);
      bQuit = naiapp_query_ForQuitResponse(sizeof(inputBuffer), NAI_QUIT_CHAR, inputBuffer, &inputResponseCnt);
      printf("Waiting for data on any/all channels...\n");
      if (!bQuit)
      {
         duration = 0;
         timeout = 5;
         if (inputResponseCnt > 0)
            timeout = (int32_t)atol((const char*)inputBuffer);

         timeout *= 100;

         /* Read new messages */
         while (duration < timeout)
         {
            /****************************************/
            /*************** INTERRUPT **************/
            /****************************************/
            if (useInterrupt)
            {
               if (irqFlag)
               {
                  irqFlag = FALSE;

                  /* Read the Summary Latched Status Register */
                  check_status(naibrd_SER_GetChannelMappedStatus(cardIndex, module, NAI_SER_STATUS_SUMMARY_RX_AVAIL_LATCHED, &regValue));

                  /* If any bits in summary register are '1' indicating new data available, read out the received messages on the corresponding channels */
                  if (regValue > 0)
                  {
                     for (chan = 1; chan <= maxChannels; chan++)
                     {
                        if ((regValue & (1u << (chan - 1))) > 0u)
                        {
                           printf("\n***************************************\n");
                           printf("Summary latched register read: 0x%08X\n", regValue);
                           printf("Channel %d data detected\n", chan);
                           FetchNewMessagesFromRxFIFO(cardIndex, module, chan);
                           printf("***************************************\n");
                        }
                     }
                  }

                  /* Clear the Summary Latched Status Register once all new messages are read out */
                  check_status(naibrd_SER_ClearChannelMappedStatus(cardIndex, module, NAI_SER_STATUS_SUMMARY_RX_AVAIL_LATCHED, regValue));
               }
            }
            /****************************************/
            /**************** POLLING ***************/
            /****************************************/
            else
            {
               /* Read the Summary Real-Time Status Register */
               check_status(naibrd_SER_GetChannelMappedStatus(cardIndex, module, NAI_SER_STATUS_SUMMARY_RX_AVAIL_REALTIME, &regValue));

               /* If any bits in summary register are '1' indicating new data available, read out the received messages on the corresponding channels */
               if (regValue > 0)
               {
                  for (chan = 1; chan <= maxChannels; chan++)
                  {
                     if ((regValue & (1u << (chan - 1))) > 0u)
                     {
                        printf("\n***************************************\n");
                        printf("Summary real-time register read: 0x%08X\n", regValue);
                        printf("Channel %d data detected\n", chan);
                        FetchNewMessagesFromRxFIFO(cardIndex, module, chan);
                        printf("***************************************\n");
                     }
                  }
               }
            }
            duration++;
            nai_msDelay(10);

         }
      }
      else
         bContinue = FALSE;
   }

   return bQuit;
}

/**************************************************************************************************************/
/**
\ingroup SERRxSummary
Queries the module for how many elements are in the Receive Buffer, then reads those elements off the
receive buffer and prints them out to the console.
\param cardIndex (Input) Logical Card Index assigned to connection with the NAI_BOARD (0 - NAI_MAX_CARDS-1).
\param module    (Input) Module Number of the module to access (1 - [max modules for board]).
\param channel   (Input) Channel Number of the channel to access (1 - [max channels for module]).
 */
/**************************************************************************************************************/
static void FetchNewMessagesFromRxFIFO(int32_t cardIndex, int32_t module, int32_t channel)
{
   uint32_t nNumWordsRecv;
   uint32_t RecvData[SER_MAX_RECV];
   uint32_t i;

   /* Get receive buffer count. */
   check_status(naibrd_SER_GetRxBufferCnt(cardIndex, module, channel, &nNumWordsRecv));

   /* If Rx count is greater than 0, read out as many messages from the Rx FIFO */
   if (nNumWordsRecv > 0)
   {
      printf("Reading back %d words on channel %d ...\n", nNumWordsRecv, channel);
      check_status(naibrd_SER_ReceiveBuffer32(cardIndex, module, channel, RecvData, SER_MAX_RECV, &nNumWordsRecv));
      for (i = 0; i < nNumWordsRecv; i++)
      {
         printf("Data: 0x%08X\n", RecvData[i]);
      }
   }
}

/**************************************************************************************************************/
/** \ingroup SERRxSummary
Queries the user if they would like to setup this application to poll or to interrupt on the summary status.
\param defUseInterrupt (Input) Default value, in the case the user hits 'enter'.
\param outuseInterrupt (Output) Whether or not the user wants to use interrupt on the status.
*/
/**************************************************************************************************************/
static bool_t GetInterruptOrPoll(bool_t defUseInterrupt, bool_t* outuseInterrupt)
{
   bool_t bQuit = FALSE;
   bool_t bContinue = TRUE;
   int8_t inputBuffer[80];
   int32_t inputResponseCnt;

   *outuseInterrupt = defUseInterrupt;
   while (bContinue)
   {
      bContinue = FALSE;
      printf("\nUse Interrupt(1) or Poll Summary Register(0) or type %c to quit? [default=%d]: ", NAI_QUIT_CHAR, defUseInterrupt);
      bQuit = naiapp_query_ForQuitResponse(sizeof(inputBuffer), NAI_QUIT_CHAR, inputBuffer, &inputResponseCnt);
      if (!bQuit)
      {
         if (inputResponseCnt > 0)
         {
            if ((inputBuffer[0] != '0') && (inputBuffer[0] != '1'))
               printf("ERROR: Invalid selection.\n\n");
            else
            {
               *outuseInterrupt = (bool_t)atol((const char*)inputBuffer);
               bContinue = FALSE;
            }
         }
         else
            bContinue = FALSE;
      }
      else
      {
         bContinue = FALSE;
      }
   }
   return bQuit;
}

static void SampleCallBack(void* param, uint32_t vector)
{
#if defined (WIN32)
   UNREFERENCED_PARAMETER(param);
#endif

#if defined (__VXWORKS__)
   logMsg("Interrupt Received!!! Vector:0x%x\n Clear Status to receive new interrupt!!!\r\n", vector, 0, 0, 0, 0, 0);
   if ((vector & 0xFF) == INTERRUPT_VECTOR)
   {
      irqFlag = TRUE;
   }
   else
   {
      logMsg("Unknown Vector Received!!!r\n", 0, 0, 0, 0, 0, 0);
   }
#else
   printf("Interrupt Received!!! Vector:0x%x\n Clear Status to receive new interrupt!!!\r\n", vector);
   if ((vector & 0xFF) == INTERRUPT_VECTOR)
   {
      irqFlag = TRUE;
   }
#endif
}

Help Bot

X