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 Async Loopback Timed RX

SER Async Loopback Timed RX Sample Application (SSK 2.x)

Overview

The SER Async Loopback Timed RX sample application demonstrates how to configure a serial channel for asynchronous timed transmission and timed reception using the NAI Software Support Kit (SSK 2.x). The application configures a channel for loopback mode with both timed TX and timed RX enabled, sends multiple messages separated by a configurable gap time, receives them back, and displays the received data with beginning-of-frame (BOF) indicators. It also reads and displays the contents of the Message Size FIFO, which reports the size of each received message.

This sample works with SER module types that support timed serial functionality. The message size, number of messages, baud rate, and gap time are configurable via preprocessor macros. It serves as a practical reference for the naibrd_SER_SetTimedRxConfig(), naibrd_SER_SetTimedSerialConfig(), and naibrd_SER_ReadTimedRxMsgSizeFifo() APIs.

Prerequisites

Before running this sample, make sure you have:

  • An NAI board with a SER module installed that supports timed serial functionality (e.g., SCA or newer SER variants).

  • SSK 2.x installed on your development host.

  • The sample applications built. Refer to the SSK 2.x Software Development Guide for platform-specific build instructions.

How to Run

Launch the ser_async_loopback_timed_rx executable from your build output directory. On startup the application looks for a configuration file (default_SerAsync_Loopback_TimedRx.txt). On the first run, this file will not exist — the application will present an interactive board menu where you configure a board connection, card index, and module slot. Once connected, the application queries for a channel, configures timed TX and RX, transmits data, and displays the received results.

Board Connection and Module Selection

Note
This startup sequence is common to all NAI sample applications. The board connection and module selection code shown here is not specific to SER.

The main() function follows a standard SSK 2.x startup flow:

  1. Call naiapp_RunBoardMenu() to load a saved configuration file or present the interactive board menu.

  2. Query the user for a card index with naiapp_query_CardIndex().

  3. Query for a module slot with naiapp_query_ModuleNumber().

  4. Retrieve the module ID with naibrd_GetModuleName().

  5. Call Run_SER_ASync_Loopback_TimedRx(cardIndex, module, moduleID).

#ifdef NAIBSP_CONFIG_SOFTWARE_OS_VXWORKS
int32_t SER_ASync_Loopback_TimedRx_Sample(void)
#else
int32_t main(void)
#endif
{
   bool_t stop = NAI_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) == NAI_TRUE)
   {
      while (stop != NAI_TRUE)
      {
         stop = naiapp_query_CardIndex(naiapp_GetBoardCnt(), 0, &cardIndex);
         if (stop != NAI_TRUE)
         {
            check_status(naibrd_GetModuleCount(cardIndex, &moduleCnt));
            stop = naiapp_query_ModuleNumber(moduleCnt, 1, &module);
            if (stop != NAI_TRUE)
            {
               check_status(naibrd_GetModuleName(cardIndex, module, &moduleID));
               if ((moduleID != 0))
               {
                  Run_SER_ASync_Loopback_TimedRx(cardIndex, module, moduleID);
               }
            }
         }

         naiif_printf("\r\nType Q to quit or Enter key to restart application:\r\n");
         stop = naiapp_query_ForQuitResponse(sizeof(inputBuffer), NAI_QUIT_CHAR, inputBuffer, &inputResponseCnt);
      }
   }

   naiif_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;
}

Note the SSK 2.x differences from SSK 1.x in this startup sequence:

  • The VxWorks preprocessor guard uses NAIBSP_CONFIG_SOFTWARE_OS_VXWORKS (SSK 1.x uses __VXWORKS__).

  • The module identifier is retrieved with naibrd_GetModuleName() (SSK 1.x uses naibrd_GetModuleID()).

  • Boolean constants are NAI_TRUE / NAI_FALSE (SSK 1.x uses TRUE / FALSE).

  • Console output uses naiif_printf() from the platform abstraction layer (SSK 1.x uses printf() directly).

Important

Common connection errors you may encounter at this stage:

  • No board found — verify that the board is powered on and physically connected.

  • Connection timeout — confirm network settings (for Ethernet connections) or bus configuration (for PCI/PCIe).

  • Invalid card or module index — indices are zero-based for cards and one-based for modules.

Program Structure

Entry Point

The entry point is main() on most platforms, or SER_ASync_Loopback_TimedRx_Sample() on VxWorks.

Application Flow

  1. Load configuration and connect to the board.

  2. Query for channel number and reset the channel.

  3. Configure the channel for async loopback.

  4. Configure timed RX and timed TX.

  5. Verify the configuration was applied correctly.

  6. Transmit data and read back the loopback results.

  7. Display received data with BOF indicators and Message Size FIFO contents.

Channel Configuration

After resetting the channel and clearing both FIFOs, the application sets up standard async loopback parameters:

check_status(naibrd_SER_SetCommProtocol(cardIndex, module, chanNum, NAIBRD_SER_PROTOCOL_ASYNC));
check_status(naibrd_SER_SetInterface(cardIndex, module, chanNum, NAIBRD_SER_INTF_LOOPBACK));
check_status(naibrd_SER_SetParityType(cardIndex, module, chanNum, NAIBRD_SER_PARITY_NONE));
check_status(naibrd_SER_SetNumDataBits(cardIndex, module, chanNum, NAIBRD_SER_DATA_BITS_8));
check_status(naibrd_SER_SetNumStopBits(cardIndex, module, chanNum, NAIBRD_SER_STOP_BITS_1));
check_status(naibrd_SER_SetBaudrate(cardIndex, module, chanNum, BAUD_RATE));
check_status(naibrd_SER_SetReceiverEnable(cardIndex, module, chanNum, NAI_TRUE));

Timed RX and TX Configuration

The application then configures both the timed RX and timed TX features:

check_status(naibrd_SER_SetTimedRxConfig(cardIndex, module, chanNum, NAI_TRUE, GAP_TIME_BITS));
check_status(naibrd_SER_SetTimedSerialConfig(cardIndex, module, chanNum, NAI_TRUE, GAP_TIME_BYTES,
                                MSG_SIZE, NUM_MSGS));
  • naibrd_SER_SetTimedRxConfig() enables timed RX mode and sets the gap time in bit-times (GAP_TIME_BITS = 960). The receiver uses this gap time to detect message boundaries.

  • naibrd_SER_SetTimedSerialConfig() enables timed TX mode, sets the gap time in bytes (GAP_TIME_BYTES), the message size (MSG_SIZE = 8), and the number of messages (NUM_MSGS = 2).

The application inserts a 500 ms delay after configuration to allow the hardware to settle (must be longer than the gap time).

Configuration Verification

After the delay, the application reads back both the timed RX and TX configurations and verifies that all parameters match:

check_status(naibrd_SER_GetTimedRxConfig(cardIndex, module, chanNum, &enabledRxRead, &gapTimeRxRead));
check_status(naibrd_SER_GetTimedSerialConfig(cardIndex, module, chanNum, &enabledTxRead, &gapTimeTxRead,
                                &msgSizeRead, &msgCountRead));

If any parameter does not match the expected value, the application prints an error and returns without transmitting.

Data Transmission and Reception

The application populates a send buffer with DATA_SIZE (16) bytes of incremental values, loads the FIFO, and initiates transmission:

check_status(naibrd_SER_LoadBufferWithTimeOut32(cardIndex, module, chanNum, sendBuff, DATA_SIZE, DATA_SIZE,
   NAIBRD_FIFO_TIMEOUT_NONE, (int32_t*)&numBytesSent));
check_status(naibrd_SER_TransmitInitiate(cardIndex, module, chanNum));

After the user presses Enter, the application reads back the received data and displays each byte with its BOF (beginning of frame) indicator:

for (idx = 0; idx < numBytesReceived; idx++)
{
   naiif_printf("0x%02X %s\r\n",
                  recvBuff[idx] & 0x00FF,
                  (recvBuff[idx] & NAIBRD_SER_GEN5_TIMED_RX_BOF_MASK) ? "BOF" : "");
}

The NAIBRD_SER_GEN5_TIMED_RX_BOF_MASK flag in the received word indicates the first byte of each timed message. In this example with MSG_SIZE = 8 and NUM_MSGS = 2, you should see the BOF indicator on bytes 0 and 8.

Message Size FIFO

After displaying the received data, the application reads the Message Size FIFO:

check_status(naibrd_SER_ReadTimedRxMsgSizeFifo(cardIndex, module, chanNum, msgSizes, FIFO_SIZE));
for (idx = 0; idx < FIFO_SIZE; idx++)
{
   if (msgSizes[idx] == 0)
      break;
   naiif_printf("%u\r\n", msgSizes[idx]);
}

The Message Size FIFO records the size of each received message. In this example, you should see two entries each showing a size of 8.

The application also displays Message Size FIFO status flags (Full, Empty, Overflow, Read Error) before and after reading the data, using naibrd_SER_GetEventMappedStatus() calls.

Troubleshooting Reference

Error / Symptom Possible Causes Suggested Resolution

No board found or connection timeout

Board not powered, incorrect configuration file, network issue

Verify hardware is powered and connected. Check default_SerAsync_Loopback_TimedRx.txt for correct settings.

Configuration not set properly (error message)

Timed RX or TX configuration did not apply correctly

Verify the module supports timed serial. Check the hardware and FPGA revision.

No BOF indicators in received data

Timed RX not enabled, gap time too short

Verify naibrd_SER_SetTimedRxConfig() was called with NAI_TRUE. Increase the gap time if messages are not being detected.

Message Size FIFO empty

No messages were detected by timed RX, receiver not enabled

Verify receiver is enabled and timed RX configuration is correct.

Received count does not match DATA_SIZE

Configuration delay too short, receiver not enabled

Increase the 500 ms post-configuration delay. Verify receiver is enabled.

Message Size FIFO overflow

Too many messages received before reading the FIFO

Read the FIFO more frequently or increase FIFO depth if supported.

Status byte indicates error

Parity or framing error on received data

In loopback mode this typically indicates a configuration issue. Try resetting the channel.

Full Source

The complete source for this sample is provided below for reference. The sections above explain each part in detail.

Full Source — ser_async_loopback_timed_rx.c (SSK 2.x)
/* nailib include files */
#include "nai_libs/nailib/include/naitypes.h"
#include "nai_libs/nailib/include/nailib.h"
#include "nai_libs/nailib/include/nailib_utils.h"

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

/* naiif include files */
#include "nai_libs/naiif/include/naiif_stdio.h"

/* Common Sample Program include files */
#include "nai_sample_apps/naiapp_common/include/naiapp_boardaccess_menu.h"
#include "nai_sample_apps/naiapp_common/include/naiapp_boardaccess_query.h"
#include "nai_sample_apps/naiapp_common/include/naiapp_boardaccess_access.h"
#include "nai_sample_apps/naiapp_common/include/naiapp_boardaccess_display.h"
#include "nai_sample_apps/naiapp_common/include/naiapp_boardaccess_utils.h"

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

#define MSG_SIZE          8
#define NUM_MSGS          2
#define BAUD_RATE         9600
#define GAP_TIME_BITS     960

#define DATA_SIZE         (MSG_SIZE * NUM_MSGS)
#define FIFO_SIZE         1024
#if GAP_TIME_BITS % 8
   #define GAP_TIME_BYTES    ((GAP_TIME_BITS / 8) + 1)
#else
   #define GAP_TIME_BYTES    (GAP_TIME_BITS / 8)
#endif

/* Function prototypes */
void Run_SER_ASync_Loopback_TimedRx(int32_t cardIndex, int32_t module, uint32_t moduleID);

/**************************************************************************************************************/
/** \defgroup SERAsyncLoopbackTimedRx
Illustrates the usage of timed Rx and Tx functionality (exclusive to SCA).

The specified channel is configured for loopback mode, and timed Tx and Rx are both enabled. The channel sends messages
separated by a gap time, and those messages are received back on the same channel. The received data is then displayed,
with the BOF (beginning of frame) bit indicated on the first byte of each message. The contents of the Message Size FIFO
are also displayed, indicating the size of each message received.

The message size, number of messages, baud rate, and gap time are configurable via preprocessor macros.
*/
/**************************************************************************************************************/
#ifdef NAIBSP_CONFIG_SOFTWARE_OS_VXWORKS
int32_t SER_ASync_Loopback_TimedRx_Sample(void)
#else
int32_t main(void)
#endif
{
   bool_t stop = NAI_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) == NAI_TRUE)
   {
      while (stop != NAI_TRUE)
      {
         /* Query the user for the card index */
         stop = naiapp_query_CardIndex(naiapp_GetBoardCnt(), 0, &cardIndex);
         if (stop != NAI_TRUE)
         {
            check_status(naibrd_GetModuleCount(cardIndex, &moduleCnt));

            /* Query the user for the module number */
            stop = naiapp_query_ModuleNumber(moduleCnt, 1, &module);
            if (stop != NAI_TRUE)
            {
               check_status(naibrd_GetModuleName(cardIndex, module, &moduleID));
               if ((moduleID != 0))
               {
                  Run_SER_ASync_Loopback_TimedRx(cardIndex, module, moduleID);
               }
            }
         }

         naiif_printf("\r\nType Q to quit or Enter key to restart application:\r\n");
         stop = naiapp_query_ForQuitResponse(sizeof(inputBuffer), NAI_QUIT_CHAR, inputBuffer, &inputResponseCnt);
      }
   }

   naiif_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;
}

static void print_msgSize_fifo_statuses(int32_t cardIndex, int32_t module, int32_t channel);

/**************************************************************************************************************/
/** \ingroup SERAsyncLoopbackTimedRx
\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.
*/
/**************************************************************************************************************/
void Run_SER_ASync_Loopback_TimedRx(int32_t cardIndex, int32_t module, uint32_t moduleID)
{
   int32_t channelCount;
   int32_t chanNum;
   uint32_t sendBuff[DATA_SIZE] = {0};
   uint32_t recvBuff[DATA_SIZE] = {0};
   uint32_t msgSizes[FIFO_SIZE] = {0};
   int8_t inputBuffer[80];
   int32_t inputResponseCnt;
   uint32_t idx;
   uint32_t numBytesSent, numBytesReceived;
   uint32_t gapTimeRxRead, gapTimeTxRead;
   bool_t enabledRxRead;
   uint32_t enabledTxRead;
   uint32_t msgSizeRead, msgCountRead;

   /* Populate array with data to send */
   for (idx = 0; idx < DATA_SIZE; idx++)
   {
      sendBuff[idx] = (uint8_t)idx;
   }

   channelCount = naibrd_SER_GetChannelCount(moduleID);
   naiapp_query_ChannelNumber(channelCount, 1, &chanNum);

   naibrd_SER_ChannelReset(cardIndex, module, chanNum);
   naibrd_SER_ClearRxFifo(cardIndex, module, chanNum);
   naibrd_SER_ClearTxFifo(cardIndex, module, chanNum);

   naiif_printf("\r\nSerial Channel # %d\r\n", chanNum);

   /* Configure for ASync on the channel selected. */
   check_status(naibrd_SER_SetCommProtocol(cardIndex, module, chanNum, NAIBRD_SER_PROTOCOL_ASYNC));      /* Async mode  */
   check_status(naibrd_SER_SetInterface(cardIndex, module, chanNum, NAIBRD_SER_INTF_LOOPBACK));          /* LoopBack    */
   check_status(naibrd_SER_SetParityType(cardIndex, module, chanNum, NAIBRD_SER_PARITY_NONE));           /* No Parity   */
   check_status(naibrd_SER_SetNumDataBits(cardIndex, module, chanNum, NAIBRD_SER_DATA_BITS_8));          /* 8 Data Bits */
   check_status(naibrd_SER_SetNumStopBits(cardIndex, module, chanNum, NAIBRD_SER_STOP_BITS_1));          /* 1 Stop Bit  */
   check_status(naibrd_SER_SetBaudrate(cardIndex, module, chanNum, BAUD_RATE));
   check_status(naibrd_SER_SetReceiverEnable(cardIndex, module, chanNum, NAI_TRUE));                     /* Enable the Receiver */

   check_status(naibrd_SER_SetTimedRxConfig(cardIndex, module, chanNum, NAI_TRUE, GAP_TIME_BITS));
   check_status(naibrd_SER_SetTimedSerialConfig(cardIndex, module, chanNum, NAI_TRUE, GAP_TIME_BYTES,
                                   MSG_SIZE, NUM_MSGS));

   /* Wait for configuration to be ready, must be longer than gap time. */
   naibrd_msDelay(500);

   check_status(naibrd_SER_GetTimedRxConfig(cardIndex, module, chanNum, &enabledRxRead, &gapTimeRxRead));
   check_status(naibrd_SER_GetTimedSerialConfig(cardIndex, module, chanNum, &enabledTxRead, &gapTimeTxRead,
                                   &msgSizeRead, &msgCountRead));

   if (!(
      (enabledRxRead & enabledTxRead) &&   /* timed Tx and Rx enabled? */
      (gapTimeRxRead == GAP_TIME_BITS) &&  /* Rx gap time set properly? */
      (gapTimeTxRead == GAP_TIME_BYTES) && /* Tx gap time set properly? */
      (msgSizeRead == MSG_SIZE) &&         /* Tx frame size set properly? */
      (msgCountRead == NUM_MSGS)           /* Tx frame count set properly? */
      ))
   {
      naiif_printf("\r\nError: Configuration not set properly.\r\n");
      return;
   }

   naiif_printf("\r\nSending %u bytes"
                  "\r\nBaud rate: %u"
                  "\r\nGap time: %u bit-times\r\n",
                  DATA_SIZE,
                  BAUD_RATE,
                  GAP_TIME_BITS);

   check_status(naibrd_SER_LoadBufferWithTimeOut32(cardIndex, module, chanNum, sendBuff, DATA_SIZE, DATA_SIZE,
      NAIBRD_FIFO_TIMEOUT_NONE, (int32_t*)&numBytesSent));
   check_status(naibrd_SER_TransmitInitiate(cardIndex, module, chanNum));

   naiif_printf("\r\nPlease press Enter to read back data...\r\n");
   while (naiapp_query_ForQuitResponse(sizeof(inputBuffer), 0x0A, inputBuffer, &inputResponseCnt));

   print_msgSize_fifo_statuses(cardIndex, module, chanNum);

   check_status(naibrd_SER_GetRxBufferCnt(cardIndex, module, chanNum, &numBytesReceived));
   check_status(naibrd_SER_ReceiveBufferWithTimeOut32(cardIndex, module, chanNum, recvBuff, DATA_SIZE, numBytesReceived,
      NAIBRD_FIFO_TIMEOUT_NONE, (int32_t*)&numBytesReceived));

   naiif_printf("\r\n%d bytes received:\r\n", numBytesReceived);

   for (idx = 0; idx < numBytesReceived; idx++)
   {
      naiif_printf("0x%02X %s\r\n",
                     recvBuff[idx] & 0x00FF,
                     (recvBuff[idx] & NAIBRD_SER_GEN5_TIMED_RX_BOF_MASK) ? "BOF" : "");
   }

   naiif_printf("\r\nMessage Size FIFO contents: \r\n");
   check_status(naibrd_SER_ReadTimedRxMsgSizeFifo(cardIndex, module, chanNum, msgSizes, FIFO_SIZE));
   for (idx = 0; idx < FIFO_SIZE; idx++)
   {
      if (msgSizes[idx] == 0)
         break;
      naiif_printf("%u\r\n", msgSizes[idx]);
   }

   print_msgSize_fifo_statuses(cardIndex, module, chanNum);

   naiif_printf("\r\nPress ENTER to run again, or '%c' to exit program : ", NAI_QUIT_CHAR);
   naiapp_query_ForQuitResponse(sizeof(inputBuffer), NAI_QUIT_CHAR, inputBuffer, &inputResponseCnt);

   return;
}

void print_msgSize_fifo_statuses(int32_t cardIndex, int32_t module, int32_t channel)
{
   nai_status_bit_t fifoStatusFull, fifoStatusEmpty, fifoStatusOverflow, fifoStatusErr;

   check_status(naibrd_SER_GetEventMappedStatus(cardIndex, module, channel,
      NAIBRD_SER_EVENT_MAP_STATUS_FIFO_MSGSIZE_FULL_REALTIME, &fifoStatusFull));
   check_status(naibrd_SER_GetEventMappedStatus(cardIndex, module, channel,
      NAIBRD_SER_EVENT_MAP_STATUS_FIFO_MSGSIZE_EMPTY_REALTIME, &fifoStatusEmpty));
   check_status(naibrd_SER_GetEventMappedStatus(cardIndex, module, channel,
      NAIBRD_SER_EVENT_MAP_STATUS_FIFO_MSGSIZE_OVERFLOW_REALTIME, &fifoStatusOverflow));
   check_status(naibrd_SER_GetEventMappedStatus(cardIndex, module, channel,
      NAIBRD_SER_EVENT_MAP_STATUS_FIFO_MSGSIZE_READ_ERR_REALTIME, &fifoStatusErr));

   naiif_printf("\r\nMessage Size FIFO statuses: Full (%u), Empty (%u), Overflow (%u), Read Error (%u)\r\n",
                fifoStatusFull, fifoStatusEmpty, fifoStatusOverflow, fifoStatusErr);
}

Help Bot

X