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

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

Overview

The SER Async Loopback Timed sample application demonstrates how to configure a serial channel for asynchronous timed transmission using the NAI Software Support Kit (SSK 2.x). The application is exclusive to the SCA module and allows the user to enable or disable timed transmission mode, configure timed-mode parameters (frame count, sub-bytes, and gap time), adjust the baud rate, and transmit data through an internal loopback path. A menu-driven interface lets you experiment with different timing configurations before initiating a transmission.

This sample supports only the SCA module type. It serves as a practical reference for the naibrd_SER_SetTimedSerialEnable(), naibrd_SER_SetTimedSerialConfig(), and naibrd_SER_GetTimedSerialConfig() APIs, which control the timed serial transmission feature unique to the SCA.

Prerequisites

Before running this sample, make sure you have:

  • An NAI board with an SCA module installed.

  • 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 executable from your build output directory. On startup the application looks for a configuration file (default_SerAsync_TIMED.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. You can save this configuration so that subsequent runs skip the menu and connect automatically. Once connected, the application verifies that the selected module is an SCA, queries for a channel, and displays a five-option menu for configuring and testing timed serial mode.

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 (if one exists) or present the interactive board menu. The configuration file (default_SerAsync_TIMED.txt) is not included with the SSK — it is created when the user saves their connection settings from the board menu. On the first run, the menu will always appear.

  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() and verify it is NAIBRD_MODULE_ID_SCA. If it is not, the application prints an error message and returns.

  5. Call Run_SER_ASYNC_TIMED(cardIndex, module, moduleID) to present the timed-mode menu.

#if defined (__VXWORKS__)
int32_t SER_ASYNC_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 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 == NAIBRD_MODULE_ID_SCA)
               {
                  Run_SER_ASYNC_TIMED(cardIndex, module, moduleID);
               }
               else
               {
                  naiif_printf("This application can only be run on an SCA\r\n");
               }
            }
         }

         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 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. Check that the configuration file lists the correct interface and address.

  • Connection timeout — confirm network settings (for Ethernet connections) or bus configuration (for PCI/PCIe). Firewalls and IP mismatches are frequent causes.

  • Module not SCA — this application only supports the SCA module. If a different module is installed, the application will display an error and return to the board menu.

Program Structure

Entry Point

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

Application Flow

After establishing a board connection and verifying the module is an SCA, the application:

  1. Queries the user for a channel number.

  2. Clears the receive and transmit FIFOs and polls until the clear completes (with a 1-second timeout).

  3. Configures the channel for async loopback (9600 baud, 8N1, no parity, loopback interface, receiver enabled).

  4. Displays a five-option menu.

FIFO Clearing with Timeout

Before configuring the channel, the application clears both FIFOs and polls the channel control register to confirm the clear operation has completed:

naibrd_SER_ClearRxFifo(cardIndex, module, chanNum);
naibrd_SER_ClearTxFifo(cardIndex, module, chanNum);
nCntlValueLo = NAIBRD_SER_CTRL_CLEAR_RX_FIFO | NAIBRD_SER_CTRL_CLEAR_TX_FIFO;
for (i = 0; i < CLEAR_FIFO_TIMEOUT && (nCntlValueLo & (NAIBRD_SER_CTRL_CLEAR_RX_FIFO | NAIBRD_SER_CTRL_CLEAR_TX_FIFO)); i++)
{
   naibrd_ser_chanctrl chanCtrlRaw;
   naibrd_SER_GetChannelControlRaw(cardIndex, module, chanNum, &chanCtrlRaw);
   nCntlValueLo = chanCtrlRaw & 0x0000FFFF;
   naibrd_msDelay(1);
}
  • CLEAR_FIFO_TIMEOUT is set to 1000 (1 second). The loop polls every 1 ms.

  • naibrd_SER_GetChannelControlRaw() reads the raw channel control register. The clear bits remain set until the hardware completes the operation.

  • If the timeout expires, the application prints an error and returns without proceeding.

Channel Configuration

The application configures the channel with standard async 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, 9600));
check_status(naibrd_SER_SetReceiverEnable(cardIndex, module, chanNum, 1));

These settings match the standard async loopback configuration. The interface is set to loopback so transmitted data is received back on the same channel.

Timed Mode Menu

The application presents a five-option menu:

  1. Enable/Disable Timed Mode — calls naibrd_SER_SetTimedSerialEnable() to toggle timed serial mode on or off.

  2. Change Timed Mode Configuration — calls naibrd_SER_SetTimedSerialConfig() with user-supplied values for enable, frame count, sub-bytes, and gap time.

  3. View Timed Mode Configuration — calls naibrd_SER_GetTimedSerialConfig() and displays the current timed-mode settings.

  4. Change Baud Rate — calls naibrd_SER_SetBaudrate() with a user-supplied baud rate.

  5. Initiate Transmit — builds a test payload, loads it into the FIFO, transmits, and reads back the loopback data.

Timed Mode Configuration

When configuring timed mode (option 2), the user provides three parameters in hexadecimal:

  • Frame count (n) — the number of frames to transmit per timed cycle.

  • Sub bytes (m) — the number of bytes per sub-frame.

  • Gap time (k) — the inter-frame gap time in byte-times.

check_status(naibrd_SER_SetTimedSerialConfig(cardIndex, module, chanNum, (uint32_t)option, outgapTime, outSubBytes, outFrameCnt));

Viewing Configuration

Option 3 reads back the current timed-mode settings and displays them:

check_status(naibrd_SER_GetTimedSerialConfig(cardIndex, module, chanNum, &outEnable, &outgapTime, &outSubBytes, &outFrameCnt));

Data Transmission and Reception

When the user selects option 5, the application builds a payload of 8 words with incremental values starting at 0x00, loads the FIFO, initiates transmission, and reads back the loopback data:

for (i = 0; i < NUM_DATA_TX; i++)
{
   SendData[i] = (uint8_t)i;
}

nNumWordsSend = i;
check_status(naibrd_SER_LoadBufferWithTimeOut32(cardIndex, module, chanNum, SendData, nNumWordsSend, NUM_DATA_TX, NAIBRD_FIFO_TIMEOUT_NONE, &nNumWordsSend));

check_status(naibrd_SER_TransmitInitiate(cardIndex, module, chanNum));

After transmission, the application prompts the user to press Enter, then reads back the data using naibrd_SER_GetRxBufferCnt() and naibrd_SER_ReceiveBufferWithTimeOut32(), displaying both the sent and received data side by side with per-word status bytes.

Troubleshooting Reference

Error / Symptom Possible Causes Suggested Resolution

Module not SCA

A non-SCA module is installed at the selected slot

This application only supports the SCA module. Verify your hardware configuration.

Unable to clear FIFOs (timeout)

Hardware is not responding to FIFO clear commands

Check that the module is powered and the board connection is valid. Try a board reset.

No board found or connection timeout

Board not powered, incorrect configuration file, network issue

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

No data received after transmit

Receiver not enabled, timed mode misconfigured, transmit not initiated

Verify receiver is enabled. Check timed-mode configuration with option 3 before transmitting.

Received count does not match sent count

Timed mode gap time or frame configuration incorrect

Review timed-mode settings. Ensure gap time and frame count match the expected transmission pattern.

Status byte indicates error

Parity or framing error detected during reception

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

Invalid baud rate

Module does not support the requested baud rate

Consult the SC3 Manual for supported baud rates.

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.c (SSK 2.x)
/* 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"

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

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

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

#define NUM_DATA_TX  8
#define MAX_DATA_RX  20
#define CLEAR_FIFO_TIMEOUT 1000  /* 1 second */

/**************************************************************************************************************/
/** \defgroup SERAsyncLoopbackTimed

\brief This sample application demonstrates how to configure and use a SCA module for asynchronous timed loopback transmission.

The Serial Asynchronous Loopback Timed sample application illustrates the methods to call in the naibrd library to configure an SCA module
serial channel for timed transmission. The application will query the user on changing some of the timing parameters.

The main steps include:
- Querying the user for the card index and module number.
- Configuring the serial channel for asynchronous communication with timed loopback.
- Setting and changing the timed mode configuration.
- Transmitting data through the serial channel.
- Receiving the transmitted data and displaying it.
*/
/**************************************************************************************************************/
#if defined (__VXWORKS__)
int32_t SER_ASYNC_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 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 == NAIBRD_MODULE_ID_SCA)
               {
                  Run_SER_ASYNC_TIMED(cardIndex, module, moduleID);
               }
               else
               {
                  naiif_printf("This application can only be run on an SCA\r\n");
               }
            }
         }

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

/**************************************************************************************************************/
/** \ingroup SERAsyncLoopbackTimed
Configures a serial module for asynchronous timed transmission. The user is queried for the
serial channel to perform this transmission on. User is then given a menu to choose between enabling/disabling the timed mode.
Once the timed configuration is set, user can read back to ensure the channel's registers have been properly written to.
User also has the option to enable the timed mode if they wanted to test out different timing configurations.
\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_TIMED(int32_t cardIndex, int32_t module, uint32_t moduleID)
{
   int32_t i;
   int32_t channelCount;
   int32_t chanNum;
   int32_t nNumWordsSend = 0;
   int32_t nNumWordsRecv = 0;
   uint32_t baudRate;
   uint32_t SendData[NUM_DATA_TX], RecvDataStatus[MAX_DATA_RX];
   int32_t nCntlValueLo;
   bool_t bQuit = NAI_FALSE;
   int32_t option;
   int8_t inputBuffer[80];
   int32_t inputResponseCnt;
   uint32_t outEnable = 0x0u, outgapTime = 0x0u, outSubBytes = 0x0u, outFrameCnt = 0x0u;
   char* enable;

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

   naibrd_SER_ClearRxFifo(cardIndex, module, chanNum);
   naibrd_SER_ClearTxFifo(cardIndex, module, chanNum);
   nCntlValueLo = NAIBRD_SER_CTRL_CLEAR_RX_FIFO | NAIBRD_SER_CTRL_CLEAR_TX_FIFO;
   for (i = 0; i < CLEAR_FIFO_TIMEOUT && (nCntlValueLo & (NAIBRD_SER_CTRL_CLEAR_RX_FIFO | NAIBRD_SER_CTRL_CLEAR_TX_FIFO)); i++)
   {
      naibrd_ser_chanctrl chanCtrlRaw;
      naibrd_SER_GetChannelControlRaw(cardIndex, module, chanNum, &chanCtrlRaw);
      nCntlValueLo = chanCtrlRaw & 0x0000FFFF;
      naibrd_msDelay(1);
   }
   if (i == CLEAR_FIFO_TIMEOUT)
   {
      naiif_printf("Unable to clear FIFOs %d\r\n", chanNum);
      naiif_printf("Please press Enter to exit...");
      while (naiapp_query_ForQuitResponse(sizeof(inputBuffer), 0x0A, inputBuffer, &inputResponseCnt));
      return;
   }

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

   /* Module Configuration */
   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));       /* RS422 */
   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, 9600));                            /* 9600 baud */
   check_status(naibrd_SER_SetReceiverEnable(cardIndex, module, chanNum, 1));                         /* Enable Receiver */

   naiif_printf("\r\n\r\n*******************************\r\n");
   naiif_printf("\tSCA Menu\r\n");
   naiif_printf("*******************************\r\n\r\n");
   naiif_printf("Select Option then ENTER key.\r\n\r\n");
   naiif_printf("1. Enable/Disable Timed Mode\r\n");
   naiif_printf("2. Change Timed Mode Configuration\r\n");
   naiif_printf("3. View Timed Mode Configuration\r\n");
   naiif_printf("4. Change Baud Rate\r\n");
   naiif_printf("5. Initiate Transmit\r\n");

   bQuit = naiapp_query_ForQuitResponse(sizeof(inputBuffer), NAI_QUIT_CHAR, inputBuffer, &inputResponseCnt);
   if (!bQuit)
   {
      naiapp_query_NumberFromResponse(&option, inputBuffer, inputResponseCnt);

      switch (option)
      {
         case 1:
            naiif_printf("Do you wish to enable or disable timed mode? [disable (0) / enable (1)]");
            bQuit = naiapp_query_ForQuitResponse(sizeof(inputBuffer), NAI_QUIT_CHAR, inputBuffer, &inputResponseCnt);
            if (!bQuit)
            {
               naiapp_query_NumberFromResponse(&option, inputBuffer, inputResponseCnt);

               check_status(naibrd_SER_SetTimedSerialEnable(cardIndex, module, chanNum, (bool_t)option));
            }
            break;
         case 2:
            naiif_printf("Do you wish to enable or disable timed mode? [disable (0) / enable (1)]");
            bQuit = naiapp_query_ForQuitResponse(sizeof(inputBuffer), NAI_QUIT_CHAR, inputBuffer, &inputResponseCnt);
            if (!bQuit)
            {
               naiapp_query_NumberFromResponse(&option, inputBuffer, inputResponseCnt);
            }

            naiif_printf("Enter desired frame count (n) [use 0x]");
            bQuit = naiapp_query_ForQuitResponse(sizeof(inputBuffer), NAI_QUIT_CHAR, inputBuffer, &inputResponseCnt);
            if (!bQuit)
            {
               outFrameCnt = naiapp_utils_HexStrToDecUInt32(inputBuffer);
            }

            naiif_printf("Enter desired sub bytes (m) [use 0x]");
            bQuit = naiapp_query_ForQuitResponse(sizeof(inputBuffer), NAI_QUIT_CHAR, inputBuffer, &inputResponseCnt);
            if (!bQuit)
            {
               outSubBytes = naiapp_utils_HexStrToDecUInt32(inputBuffer);
            }

            naiif_printf("Enter desired gap time (k) [use 0x]");
            bQuit = naiapp_query_ForQuitResponse(sizeof(inputBuffer), NAI_QUIT_CHAR, inputBuffer, &inputResponseCnt);
            if (!bQuit)
            {
               outgapTime = naiapp_utils_HexStrToDecUInt32(inputBuffer);
            }
            check_status(naibrd_SER_SetTimedSerialConfig(cardIndex, module, chanNum, (uint32_t)option, outgapTime, outSubBytes, outFrameCnt));
            break;
         case 3:
            check_status(naibrd_SER_GetTimedSerialConfig(cardIndex, module, chanNum, &outEnable, &outgapTime, &outSubBytes, &outFrameCnt));
            enable = (outEnable) ? "yes" : "no";
            naiif_printf("Is chan %d's timed mode enabled? %s\r\n", chanNum, enable);
            naiif_printf("Current frame count: %d\r\n", outFrameCnt);
            naiif_printf("Current number of bytes to send: %d\r\n", outSubBytes);
            naiif_printf("Current number of bytes to wait between transmission: %d\r\n\r\n", outgapTime);
            break;
         case 4:
            naiif_printf("Enter your desired baud rate (bits/sec)");
            bQuit = naiapp_query_ForQuitResponse(sizeof(inputBuffer), NAI_QUIT_CHAR, inputBuffer, &inputResponseCnt);
            if (!bQuit)
            {
               naiapp_query_UnsignedNumberFromResponse(&baudRate, inputBuffer, inputResponseCnt);

               check_status(naibrd_SER_SetBaudrate(cardIndex, module, chanNum, baudRate));
            }
            break;
         case 5:
            for (i = 0; i < NUM_DATA_TX; i++)
            {
               SendData[i] = (uint8_t)i;           /* incremental data */
            }

            /* Send data */
            nNumWordsSend = i;
            naiif_printf("\r\nSending %d words ...", nNumWordsSend);
            check_status(naibrd_SER_LoadBufferWithTimeOut32(cardIndex, module, chanNum, SendData, nNumWordsSend, NUM_DATA_TX, NAIBRD_FIFO_TIMEOUT_NONE, &nNumWordsSend));
            naiif_printf(" %d words sent\r\n", nNumWordsSend);

            check_status(naibrd_SER_TransmitInitiate(cardIndex, module, chanNum));

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

            /* Read back data */
            naibrd_SER_GetRxBufferCnt(cardIndex, module, chanNum, (uint32_t*)&nNumWordsRecv);
            naiif_printf("\r\nReading back %d words ...", nNumWordsRecv);
            check_status(naibrd_SER_ReceiveBufferWithTimeOut32(cardIndex, module, chanNum, RecvDataStatus, MAX_DATA_RX, nNumWordsRecv, NAIBRD_FIFO_TIMEOUT_NONE,
               &nNumWordsRecv));
            naiif_printf(" %d words read\r\n", nNumWordsRecv);

            for (i = 0; i < nNumWordsRecv; i++)
            {
               naiif_printf("Sent 0x%02X; Recd 0x%02X, Status= %02X\r\n",
                  SendData[i], (RecvDataStatus[i] & 0x00FF), (RecvDataStatus[i] >> 8) & 0x00FF);
            }
            break;
      }
   }
}

Help Bot

X