SER Recv Summary
Edit this on GitLab
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:
-
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. -
Query the user for a card index with
naiapp_query_CardIndex(). -
Query for a module slot with
naiapp_query_ModuleNumber(). -
Retrieve the module ID with
naibrd_GetModuleID()and verify it is non-zero before proceeding. -
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:
|
Program Structure
The entry point is main() on most platforms, or SER_Summary_Sample() on VxWorks.
The application flow proceeds as follows:
-
Load the saved configuration (or present the board menu) via
naiapp_RunBoardMenu(). -
Query the user for card index, module slot, and retrieve the module ID.
-
Call
SER_Receive_Summary_Run()to configure all channels and monitor the summary register. -
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 fromnaibrd_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_ASYNCselects standard asynchronous (UART) mode. -
naibrd_SER_SetInterfaceLevel()— sets the physical interface.NAI_SER_INTF_LOOPBACKroutes the transmit output back to the receive input internally, which is useful for testing without external wiring. In your own application, change this toNAI_SER_INTF_RS232,NAI_SER_INTF_RS422, orNAI_SER_INTF_RS485to 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
|
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 bitmask0xFenables 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 theSampleCallBackfunction 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 value0xA0to 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
|
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, ®Value));
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, ®Value));
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:
-
Install your ISR callback with
naibrd_InstallISR(). -
Configure steering, vector, trigger type, and enable mask.
-
Clear the latched register before entering your main loop.
-
In your callback, set a flag (do not perform heavy processing).
-
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
|
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:
-
Call
naibrd_SER_GetRxBufferCnt()to determine how many 32-bit words are waiting in the Rx FIFO. -
Call
naibrd_SER_ReceiveBuffer32()to read up toSER_MAX_RECVwords into a local buffer. The function updatesnNumWordsRecvwith the actual number of words read. -
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
|
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. |
|
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 |
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 |
Latched register stops generating interrupts |
Latched register not cleared after reading in interrupt mode. |
Always call |
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, ®Value));
/* 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, ®Value));
/* 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
}