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 Sample Application (SSK 1.x)

Overview

The SER Recv Summary sample application demonstrates how to monitor the receive summary status register across all serial channels on a module using the NAI Software Support Kit (SSK 1.x). The summary register is a single bit-mapped register where each bit indicates whether the corresponding channel has received data in its Rx FIFO. This allows you to monitor all channels with a single register read rather than polling each channel’s status register individually.

The sample configures every channel on the selected module for asynchronous receive operation, then offers two monitoring approaches: polling the real-time summary register or using interrupts on the latched summary register. This is more complex than a single-channel receive application like SER ASync Rx because it monitors all channels simultaneously through the summary mechanism.

This application does not transmit any data. To trigger the receive condition, you must send data to the module from an external source or run a separate transmit application such as SER ASync Loopback on another board or channel.

This sample supports the following SER module types: P8, PC, PD, Px, KB, SC, and newer SER variants. It also works with combination modules that include serial functionality, such as CMH.

Prerequisites

Before running this sample, make sure you have:

  • An NAI board with a SER module installed (P8, PC, PD, Px, KB, SC, or newer SER variant).

  • SSK 1.x installed on your development host.

  • The sample applications built. Refer to the SSK 1.x build instructions for your platform if you have not already compiled them.

  • An external transmitter or a separate running instance of a SER transmit sample to provide incoming data on one or more channels. Because this sample only receives, no data will appear unless something is actively sending.

How to Run

Launch the SER_Recv_Summary executable from your build output directory. On startup the application looks for a configuration file (default_SERRecv_Summary.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 configures all channels on the module for async loopback receive, asks whether to use polling or interrupts, then enters a timed monitoring loop that reports which channels have received data.

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. For details on board connection configuration, see the First Time Setup Guide.

The main() function follows a standard SSK 1.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_SERRecv_Summary.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_GetModuleID() and verify it is non-zero before proceeding.

  5. Call SER_Receive_Summary_Run(cardIndex, module, moduleID) to configure all channels and begin monitoring.

#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)
      {
         stop = naiapp_query_CardIndex(naiapp_GetBoardCnt(), DEF_SER_CARD_INDEX, &cardIndex);
         if (stop != TRUE)
         {
            check_status(naibrd_GetModuleCount(cardIndex, &moduleCnt));
            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;
}
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.

  • Invalid card or module index — indices are zero-based for cards and one-based for modules. Ensure the values you pass match your hardware setup.

  • Module not present at selected slot — the slot you selected does not contain a SER module. Use the board menu to verify which slots are populated.

Program Structure

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

The application flow proceeds as follows:

  1. Load the saved configuration (or present the board menu) via naiapp_RunBoardMenu().

  2. Query the user for card index, module slot, and retrieve the module ID.

  3. Call SER_Receive_Summary_Run() to configure all channels and monitor the summary register.

  4. Prompt the user to quit or restart with a different module.

The sample defines these constants used throughout the application:

  • DEF_SER_CARD_INDEX (0) — default card index.

  • DEF_SER_MODULE (1) — default module slot number.

  • SER_MAX_RECV (1024) — the maximum number of 32-bit words to read per channel in a single receive call.

  • SER_MAX_CHANNELS (8) — the maximum number of channels the application will track. The actual channel count is retrieved at runtime from naibrd_SER_GetChannelCount().

  • DEF_USE_INTERRUPTS (FALSE) — the default monitoring mode is polling.

  • INTERRUPT_VECTOR (0xA0) — the interrupt vector assigned to the summary status interrupt.

  • CLEAR_FIFO_TIMEOUT (1000) — the number of 1 ms polling iterations to wait for FIFO clears to complete, giving a 1-second timeout.

The sample also declares a global flag irqFlag used to communicate between the interrupt callback and the main monitoring loop.

Note
The menu system and interactive prompts are a sample convenience. In your own code, call these API functions directly with your known card index, module number, and configuration parameters.

Channel Configuration

The SER_Receive_Summary_Run() function configures every channel on the module for asynchronous receive operation. Because the summary register covers all channels simultaneously, every channel must be initialized before monitoring begins.

Clearing the FIFOs

Before configuring any channel, clear both the Rx and Tx FIFOs to ensure no stale data remains from a previous operation:

naibrd_SER_ClearRxFifo(cardIndex, module, serChannels[ch]);
naibrd_SER_ClearTxFifo(cardIndex, module, serChannels[ch]);

These calls request the hardware to flush the respective FIFOs. The requests are asynchronous — the hardware sets control-register bits while the clear is in progress and drops them once the operation completes.

FIFO Clear Timeout Polling

After requesting the clear, poll the channel control register until the FIFO-clear bits are deasserted. The sample uses a 1 ms polling interval with a 1-second (1000-iteration) timeout:

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

The loop reads the raw channel control register and masks the lower 16 bits. As long as either FIFO-clear bit remains set, the hardware is still processing the request. Once both bits drop to zero, the FIFOs are clear and the channel is ready for configuration.

Protocol and Interface Setup

After clearing the FIFOs, configure each channel for async protocol, internal loopback interface, 115200 baud, and enable the receiver:

check_status(naibrd_SER_SetProtocol(cardIndex, module, serChannels[ch], NAI_SER_PROTOCOL_ASYNC));
check_status(naibrd_SER_SetInterfaceLevel(cardIndex, module, serChannels[ch], NAI_SER_INTF_LOOPBACK));
check_status(naibrd_SER_SetBaudrate(cardIndex, module, serChannels[ch], 115200));
check_status(naibrd_SER_SetReceiverEnable(cardIndex, module, serChannels[ch], TRUE));
  • naibrd_SER_SetProtocol() — sets the serial protocol. NAI_SER_PROTOCOL_ASYNC selects standard asynchronous (UART) mode.

  • naibrd_SER_SetInterfaceLevel() — sets the physical interface. NAI_SER_INTF_LOOPBACK routes the transmit output back to the receive input internally, which is useful for testing without external wiring. In your own application, change this to NAI_SER_INTF_RS232, NAI_SER_INTF_RS422, or NAI_SER_INTF_RS485 to match your physical connection.

  • naibrd_SER_SetBaudrate() — sets the baud rate. Both endpoints must use the same baud rate.

  • naibrd_SER_SetReceiverEnable() — enables the channel’s receiver so it can accept incoming data.

This configuration is applied to every channel on the module in a loop, preparing all channels for simultaneous receive monitoring.

Important

Common Errors

  • NAI_ERROR_NOT_SUPPORTED — the selected module does not support one of the requested settings (e.g., a protocol mode not available on older hardware). Consult your module manual for supported protocols and interface levels.

  • FIFO clear timeout — if the control register bits do not deassert within 1 second, the hardware may be in a fault state. Power-cycle the board and retry.

  • Baud rate mismatch — if the transmitter uses a different baud rate than the receiver, received data will be garbled or no data will be detected. Ensure both endpoints are configured identically.

Polling vs. Interrupt Monitoring

This sample demonstrates two approaches for detecting new data across all channels: polling the real-time summary register and using interrupts on the latched summary register. The user selects the approach at runtime via the GetInterruptOrPoll() helper function.

Choosing the Monitoring Mode

The sample prompts the user to select interrupt mode (1) or polling mode (0):

printf("\nUse Interrupt(1) or Poll Summary Register(0) or type %c to quit? [default=%d]: ",
       NAI_QUIT_CHAR, defUseInterrupt);

The default is polling (DEF_USE_INTERRUPTS = FALSE). In your own application, choose the approach that best fits your system architecture:

  • Polling — simpler to implement, no ISR setup required, but consumes CPU cycles in the polling loop. Best suited for applications where the CPU has idle time available or where interrupt latency is a concern.

  • Interrupts — the CPU is notified only when new data arrives, freeing it for other tasks between events. Requires ISR installation and proper interrupt steering configuration. Best suited for event-driven architectures or systems with tight CPU budgets.

The Summary Register

The key concept in this sample is the Rx summary status register. This is a single 32-bit register where each bit corresponds to one serial channel on the module. Bit 0 maps to channel 1, bit 1 to channel 2, and so on. When a channel has unread data in its Rx FIFO, the corresponding bit is set to 1.

There are two variants of the summary register:

  • Real-time (NAI_SER_STATUS_SUMMARY_RX_AVAIL_REALTIME) — reflects the current state of each channel’s Rx FIFO. A bit is 1 as long as data is present in the FIFO, and drops to 0 once the FIFO is empty. Used for polling.

  • Latched (NAI_SER_STATUS_SUMMARY_RX_AVAIL_LATCHED) — once a bit is set, it remains set until explicitly cleared by software, even if the FIFO has been read out. Used for interrupt-driven monitoring where the ISR sets a flag and the main loop clears the register after processing.

Interrupt Configuration

If the user selects interrupt-based monitoring, the sample configures the interrupt system in two phases: per-channel settings (inside the channel configuration loop) and module-level interrupt routing (after all channels are configured).

Per-Channel Interrupt Settings

For each channel, set the interrupt trigger type and enable the interrupt on the summary status register:

check_status(naibrd_SER_SetChannelMappedInterruptTriggerType(cardIndex, module,
   NAI_SER_STATUS_SUMMARY_RX_AVAIL_LATCHED, 0));   /* Level trigger */
check_status(naibrd_SER_SetChannelMappedInterruptEnable(cardIndex, module,
   NAI_SER_STATUS_SUMMARY_RX_AVAIL_LATCHED, 0xF));  /* Enable on channels */
  • naibrd_SER_SetChannelMappedInterruptTriggerType() — sets the trigger type for the summary status. A value of 0 selects level-triggered interrupts, meaning the interrupt fires whenever the status bit is active.

  • naibrd_SER_SetChannelMappedInterruptEnable() — enables interrupt generation for the specified channels. The bitmask 0xF enables interrupts on channels 1 through 4. Adjust this mask to match the channels you want to monitor.

Module-Level Interrupt Routing

After all channels are configured, install the ISR callback and configure interrupt steering and vector assignment:

/* Install the ISR callback */
check_status(naibrd_InstallISR(cardIndex, NAIBRD_IRQ_ID_ON_BOARD_0, (nai_isr_t)SampleCallBack, NULL));

/* Set interrupt steering to the on-board ARM processor */
check_status(naibrd_SER_SetChannelMappedInterruptSteering(cardIndex, module,
   NAI_SER_STATUS_SUMMARY_RX_AVAIL_LATCHED, NAIBRD_INT_STEERING_ON_BOARD_0));

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

/* Clear any pre-existing latched status so interrupts can fire */
check_status(naibrd_SER_ClearChannelMappedStatus(cardIndex, module,
   NAI_SER_STATUS_SUMMARY_RX_AVAIL_LATCHED, 0xFFFFFFFFu));
  • naibrd_InstallISR() — registers the SampleCallBack function as the interrupt service routine for the specified IRQ ID. When an interrupt fires, the SSK calls this function with the interrupt vector.

  • naibrd_SER_SetChannelMappedInterruptSteering() — routes the interrupt to the on-board ARM processor (NAIBRD_INT_STEERING_ON_BOARD_0). Other options include VME, PCIe, or cPCI steering depending on your board’s bus architecture.

  • naibrd_SER_SetChannelMappedInterruptVector() — assigns the vector value 0xA0 to this interrupt source. The callback uses this vector to identify the interrupt.

  • naibrd_SER_ClearChannelMappedStatus() — clears all bits in the latched summary register. This is essential — if any bits are already latched from a previous run, the interrupt will not fire again until they are cleared first.

The Interrupt Callback

The SampleCallBack function is minimal by design. It checks the interrupt vector and sets the global irqFlag:

static void SampleCallBack(void* param, uint32_t vector)
{
   printf("Interrupt Received!!! Vector:0x%x\n", vector);
   if ((vector & 0xFF) == INTERRUPT_VECTOR)
   {
      irqFlag = TRUE;
   }
}

The callback intentionally does not read the FIFO or perform heavy processing. In an interrupt context, you should set a flag and defer data processing to the main loop. The irqFlag variable signals the main monitoring loop that new data is available.

Important

Common Errors

  • Interrupts never fire — the most common cause is failing to clear the latched status register before entering the monitoring loop. Pre-existing latched bits prevent new interrupts from being generated. Always call naibrd_SER_ClearChannelMappedStatus() after configuring interrupts.

  • Wrong interrupt steering — if the interrupt is steered to VME but you are connected via Ethernet, the callback will never be invoked. Match the steering to your connection type.

  • Vector mismatch — if INTERRUPT_VECTOR in the callback check does not match the vector assigned via naibrd_SER_SetChannelMappedInterruptVector(), the flag will not be set. Ensure both use the same value.

  • Interrupt enable mask too narrow — 0xF only covers channels 1-4. If your module has more channels and you want to monitor all of them, expand the mask accordingly (e.g., 0xFF for 8 channels).

Monitoring the Summary Register

The RxAndDisplayFIFOMsgs() function implements the timed monitoring loop. It prompts the user for a duration (in seconds), then polls or waits for interrupts during that period. Each iteration sleeps 10 ms, so the timeout counter runs at 100 iterations per second.

Polling Mode

In polling mode, the loop reads the real-time summary register on every iteration:

check_status(naibrd_SER_GetChannelMappedStatus(cardIndex, module,
   NAI_SER_STATUS_SUMMARY_RX_AVAIL_REALTIME, &regValue));

if (regValue > 0)
{
   for (chan = 1; chan <= maxChannels; chan++)
   {
      if ((regValue & (1u << (chan - 1))) > 0u)
      {
         printf("Summary real-time register read: 0x%08X\n", regValue);
         printf("Channel %d data detected\n", chan);
         FetchNewMessagesFromRxFIFO(cardIndex, module, chan);
      }
   }
}

The real-time register reflects the live state of each channel’s Rx FIFO. Each iteration reads the register, and for any channel whose bit is set, the sample calls FetchNewMessagesFromRxFIFO() to drain that channel’s FIFO. No explicit clear is needed because the real-time register automatically updates as the FIFO is read.

To implement this in your own application, read NAI_SER_STATUS_SUMMARY_RX_AVAIL_REALTIME at your desired polling interval. Use the bitmask to determine which channels to service, then read those channels' FIFOs.

Interrupt Mode

In interrupt mode, the loop checks the irqFlag set by the ISR callback:

if (irqFlag)
{
   irqFlag = FALSE;

   /* Read the latched summary register */
   check_status(naibrd_SER_GetChannelMappedStatus(cardIndex, module,
      NAI_SER_STATUS_SUMMARY_RX_AVAIL_LATCHED, &regValue));

   if (regValue > 0)
   {
      for (chan = 1; chan <= maxChannels; chan++)
      {
         if ((regValue & (1u << (chan - 1))) > 0u)
         {
            printf("Summary latched register read: 0x%08X\n", regValue);
            printf("Channel %d data detected\n", chan);
            FetchNewMessagesFromRxFIFO(cardIndex, module, chan);
         }
      }
   }

   /* Clear the latched register to allow new interrupts */
   check_status(naibrd_SER_ClearChannelMappedStatus(cardIndex, module,
      NAI_SER_STATUS_SUMMARY_RX_AVAIL_LATCHED, regValue));
}

When the ISR fires, it sets irqFlag = TRUE. The main loop detects this, clears the flag, reads the latched summary register to determine which channels have data, drains those channels' FIFOs, and then clears the latched register. Clearing the latched register is critical — without this step, the interrupt will not fire again for those channels.

To implement interrupt-driven summary monitoring in your own application:

  1. Install your ISR callback with naibrd_InstallISR().

  2. Configure steering, vector, trigger type, and enable mask.

  3. Clear the latched register before entering your main loop.

  4. In your callback, set a flag (do not perform heavy processing).

  5. In your main loop, when the flag is set, read the latched register, service the indicated channels, and clear the latched register.

Important

Common Errors

  • Missed data in polling mode — if your polling interval is too slow relative to the data rate, the Rx FIFO may overflow before you read it. Increase the polling frequency or use interrupts for high-throughput scenarios.

  • Latched register not cleared — in interrupt mode, forgetting to call naibrd_SER_ClearChannelMappedStatus() after processing will prevent subsequent interrupts. Always clear the register after reading.

  • Duration timeout with no data — the monitoring loop runs for a user-specified number of seconds. If no transmitter is active, no data will be detected. Ensure a transmit source is sending data before starting the receive test.

Reading the Rx FIFO

The FetchNewMessagesFromRxFIFO() function handles the actual data retrieval from a specific channel’s receive buffer. It is called whenever the summary register indicates that a channel has data available.

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

   /* Read out all available data */
   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]);
      }
   }
}

To read received data in your own application:

  1. Call naibrd_SER_GetRxBufferCnt() to determine how many 32-bit words are waiting in the Rx FIFO.

  2. Call naibrd_SER_ReceiveBuffer32() to read up to SER_MAX_RECV words into a local buffer. The function updates nNumWordsRecv with the actual number of words read.

  3. Process the received data as needed.

    • cardIndex — the logical card index for the board connection.

    • module — the one-based module slot number.

    • channel — the one-based channel number to read from.

    • RecvData — a caller-allocated buffer to hold the received words.

    • SER_MAX_RECV — the maximum number of words to read (1024 in this sample).

    • nNumWordsRecv — on return, holds the actual number of words read.

Important

Common Errors

  • Buffer count returns zero — the summary register may indicate data was available, but by the time you read the FIFO, the data may have already been consumed (e.g., by a concurrent reader or a previous iteration). This is normal in some race conditions; handle the zero case gracefully.

  • Data appears garbled — verify that the transmitter and receiver have matching protocol settings (baud rate, data bits, parity, stop bits). Also check that the interface level matches.

Troubleshooting Reference

The following table summarizes the errors and symptoms covered in the preceding sections. Consult your module manual for hardware-specific diagnostics and register definitions.

Error / Symptom Possible Causes Suggested Resolution

No board found

Board not powered, cable disconnected, incorrect interface/address in configuration file.

Verify power, physical connection, and configuration file settings.

Connection timeout

Network misconfiguration (Ethernet), bus configuration error (PCI/PCIe), firewall blocking traffic.

Check IP settings, bus enumeration, and firewall rules.

Invalid card or module index

Zero-based card index or one-based module index out of range.

Verify hardware setup and adjust indices accordingly.

Module not present

Selected slot does not contain a SER module.

Use the board menu to check which slots are populated.

FIFO clear timeout

Hardware in a fault state or channel not responding.

Power-cycle the board and retry.

NAI_ERROR_NOT_SUPPORTED

Requested setting (protocol, interface level) not supported by the hardware.

Consult the module manual for supported configuration options.

Interrupts never fire

Latched status register not cleared before monitoring; interrupt steering mismatch; interrupt enable mask does not cover the target channels.

Clear the latched register before entering the loop. Match steering to your connection type. Expand the enable mask as needed.

Interrupt vector mismatch

Callback checks for a different vector than the one assigned.

Ensure INTERRUPT_VECTOR matches in both the vector assignment and callback validation.

No data detected (polling or interrupt)

No transmitter is active; baud rate or interface level mismatch between endpoints.

Start a transmit application or connect an external transmitter. Verify matching serial parameters.

Received data is garbled

Baud rate, data bits, parity, or stop bit mismatch between transmitter and receiver.

Ensure both endpoints use identical protocol settings.

Summary register always zero

Receiver not enabled on one or more channels; FIFOs still clearing.

Verify naibrd_SER_SetReceiverEnable() was called for each channel. Wait for FIFO clears to complete.

Latched register stops generating interrupts

Latched register not cleared after reading in interrupt mode.

Always call naibrd_SER_ClearChannelMappedStatus() after processing each interrupt event.

Full Source

Full Source — SER_Recv_Summary.c (SSK 1.x)
#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