SER HDLC LOOPBACK
Edit this on GitLab
SER HDLC LOOPBACK
Explanation
About This Sample Application Code
Overview
This C sample application code demonstrates how to interact with North Atlantic Industries (NAI) embedded function modules, specifically for serial HDLC loopback transmission. It utilizes the NAI software support kit (SSK) and associated libraries to configure, transmit, and receive data using NAI serial modules.
File Inclusions
The code includes several header files for necessary functions and definitions:
-
Standard Libraries:
-
stdio.h
,stdlib.h
,string.h
,time.h
,ctype.h
-
NAI Application Specific Libraries:
-
naiapp_boardaccess_menu.h
-
naiapp_boardaccess_query.h
-
naiapp_boardaccess_access.h
-
naiapp_boardaccess_display.h
-
naiapp_boardaccess_utils.h
-
nai.h
(NAI general definitions) -
naibrd.h
(Board-specific definitions) -
naibrd_ser.h
(Serial-specific definitions) -
nai_ether_adv.h
(Advanced Ethernet functions)
Key Definitions and Constants
-
CONFIG_FILE
: Specifies the default configuration file for the application (default_SerHDLC_LOOPBACK.txt
). -
NUM_DATA_TX
: Number of words to transmit (10). -
MAX_DATA_RX
: Maximum number of words to receive, set toNUM_DATA_TX
. -
MAX_TIMEOUT
: Timeout for data reception set to 10 milliseconds.
Main Function
Platform-Specific Entry Point
-
On systems running VxWorks: The entry point is
int32_t SER_HDLC_Sample(void)
. -
On other systems: The entry point is
int32_t main(void)
.
Application Loop
-
Configuration and User Queries: The application starts by running the board menu with
naiapp_RunBoardMenu(CONFIG_FILE)
. If successful, it enters a loop to query the user for the card index, module number, and module details. -
Module Validation:
-
Fetches and validates the module ID and FPGA revision.
-
Displays error messages if the module is invalid or if the module does not support synchronous serial communication.
-
-
Running the Loopback Test:
-
Calls the
Run_SER_HDLC_LOOPBACK()
function based on the module details.
-
-
Quitting or Restarting the Application:
-
After each run, the application checks if the user wants to quit or restart.
-
Run_SER_HDLC_LOOPBACK() Function
This function configures the serial module and runs the HDLC loopback test. It operates differently based on the generation of the serial module.
-
Gen 2/3 Modules:
-
Internal loopback.
-
Configures one channel.
-
Clears FIFOs and sets up HDLC synchronous protocol.
-
Sends data and waits for an acknowledgment.
-
Gen 5 Modules:
-
External loopback between two channels.
-
Configures both transmitter and receiver channels.
-
Clears FIFOs, sets up HDLC synchronous protocol, and prepares the channels.
-
Sends data, tests transmission, and receives data.
Function Breakdowns
Run_SER_HDLC_LOOPBACK()
Gen 2/3 Modules Execution Flow:
-
Query user for the channel number.
-
Reset channel and clear FIFOs.
-
Configure HDLC mode, loopback interface, and baud rate.
-
Enable the receiver.
-
Send data and receive acknowledgment.
-
Receive data and display.
Gen 5 Modules Execution Flow:
-
Query user for transmitter and receiver channels.
-
Reset channels and clear FIFOs.
-
Configure transmitter for HDLC mode and external clock.
-
Configure receiver for HDLC mode and internal clock.
-
Enable the receiver.
-
Send data via transmitter and receive acknowledgment.
-
Receive data and display.
Note: The code contains several predefined macros and helper functions like check_status
, naiapp_query_ChannelNumber
, and nai_msDelay
, which perform various utility tasks such as error checking, querying user input, and introducing delays.
This sample code demonstrates the intricate process involved in configuring and utilizing serial communication modules from NAI using their specialized libraries and functions. It covers the essential aspects from initiation to configuration, transmission, reception, and validation of data, making it a comprehensive guide for engaging with NAI serial modules.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <ctype.h>
/* 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"
#include "advanced/nai_ether_adv.h"
static const int8_t *CONFIG_FILE = (const int8_t *)"default_SerHDLC_LOOPBACK.txt";
/* Function prototypes */
void Run_SER_HDLC_LOOPBACK(int32_t cardIndex, int32_t module, uint32_t moduleID);
#define NUM_DATA_TX 10
#define MAX_DATA_RX NUM_DATA_TX
#define MAX_TIMEOUT 10 /* 10ms timeout */
/**************************************************************************************************************/
/** \defgroup SERLoopbackHDLC Serial Loopback - Synchronous/HDLC
The purpose of the Serial Loopback Synchronous Sample Application is to illustrate the methods to call in the
naibrd library to configure a given serial channel for loopback HDLC transmission. In the case that the NAI
serial module is a Gen 2 or Gen 3 module, internal loopback on a single channel will be used. In the case that
the NAI serial module is a Gen 5 module, external loopback on two channels will be used (via a physical connection)
The application will write data to the selected serial channel's transmit buffer, transmit it via an internal or
physical loopback, and receive and print the data.
Using a wrap connection between 2 channels (one tx channel and one rx channel) Tx and Rx channels are user
defined, but the user must connect these channels as follows:
\verbatim
Tx Channel | Rx Channel
Tx+ --> Rx+
Tx- --> Rx-
Clk+ --> Clk+
Clk- --> Clk-
\endverbatim
*/
/**************************************************************************************************************/
#if defined (__VXWORKS__)
int32_t SER_HDLC_Sample(void)
#else
int32_t main(void)
#endif
{
bool_t stop = FALSE;
int32_t cardIndex;
int32_t moduleCnt;
int32_t module;
uint32_t moduleID = 0;
uint32_t fpgaRev, modProcRev;
int8_t inputBuffer[80];
int32_t inputResponseCnt;
if (naiapp_RunBoardMenu(CONFIG_FILE) == (bool_t)TRUE)
{
while (stop != TRUE)
{
/* Query the user for the card index */
stop = naiapp_query_CardIndex(naiapp_GetBoardCnt(), 0, &cardIndex);
if (stop != TRUE)
{
check_status(naibrd_GetModuleCount(cardIndex, &moduleCnt));
/* Query the user for the module number */
stop = naiapp_query_ModuleNumber(moduleCnt, 1, &module);
if (stop != TRUE)
{
/* Check to make sure the module is NOT an SC3 */
moduleID = naibrd_GetModuleID(cardIndex, module);
check_status(naibrd_GetModuleRev(cardIndex, module, &modProcRev, &fpgaRev));
if (moduleID == 0)
{
printf("\nInvalid Module\n");
}
else if ((moduleID == NAI_MODULE_ID_SC3) && (fpgaRev < NAI_SC3_REV_1_0))
{
printf("\nSC3 does not support synchronous serial communications.\n");
}
else
{
Run_SER_HDLC_LOOPBACK(cardIndex, module, moduleID);
}
}
}
printf("\nType Q to quit or Enter key to restart application:\n");
stop = naiapp_query_ForQuitResponse(sizeof(inputBuffer), NAI_QUIT_CHAR, inputBuffer, &inputResponseCnt);
}
}
printf("\nType the Enter key to exit the program: ");
naiapp_query_ForQuitResponse(sizeof(inputBuffer), NAI_QUIT_CHAR, inputBuffer, &inputResponseCnt);
naiapp_access_CloseAllOpenCards();
return 0;
}
/**************************************************************************************************************/
/** \ingroup SERLoopbackHDLC
Gen 2/3 Serial Module: Configures a serial module for synchronous internal loopback transmission. The user is queried
for which channel they would like to internal loopback on.
Gen 5 Serial module: Configures the serial module for synchronous transmission between two channels on the same
module. The user is queried for which channels they would like to transmit and receive on.
\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_HDLC_LOOPBACK(int32_t cardIndex, int32_t module, uint32_t moduleID)
{
int32_t ch, i;
int32_t channelCount;
int32_t nNumWordsSend, nNumWordsRecv;
int32_t nCntlValueLo, nConfigWordLo;
uint32_t SendData[NUM_DATA_TX], RecvDataStatus[MAX_DATA_RX];
channelCount = naibrd_SER_GetChannelCount(moduleID);
if (NAI_MODULE_ID_P8 == moduleID || NAI_MODULE_ID_PC == moduleID || NAI_MODULE_ID_PD == moduleID ||
NAI_MODULE_ID_Px == moduleID || NAI_MODULE_ID_KB == moduleID)
{
/*************** Gen 2/3 ******************/
int32_t chanNum;
naiapp_query_ChannelNumber(channelCount, 1, &chanNum);
check_status(naibrd_SER_ChannelReset(cardIndex, module, chanNum));
check_status(naibrd_SER_ClearRxFifo(cardIndex, module, chanNum));
check_status(naibrd_SER_ClearTxFifo(cardIndex, module, chanNum));
nCntlValueLo = NAI_SER_CTRLLO_CLEAR_RX_FIFO | NAI_SER_CTRLLO_CLEAR_TX_FIFO;
for (i = 0; i < 1000 && (nCntlValueLo & (NAI_SER_CTRLLO_CLEAR_RX_FIFO | NAI_SER_CTRLLO_CLEAR_TX_FIFO)); i++)
{
nai_ser_chanctrl chanCtrlRaw;
check_status(naibrd_SER_GetChannelControlRaw(cardIndex, module, chanNum, &chanCtrlRaw));
nCntlValueLo = chanCtrlRaw & 0x0000FFFF;
nai_msDelay(1);
}
if (i == 1000)
{
printf("Unable to clear FIFOs %d\n", chanNum);
printf("Please press Enter to exit...");
while ((ch = getchar()) != 0x0A);
return;
}
printf("\nSerial Channel # %d\n", chanNum);
check_status(naibrd_SER_SetProtocol(cardIndex, module, chanNum, NAI_SER_PROTOCOL_HDLC)); /* HDLC mode */
check_status(naibrd_SER_SetInterfaceLevel(cardIndex, module, chanNum, NAI_SER_INTF_LOOPBACK)); /* LoopBack */
check_status(naibrd_SER_SetClockMode(cardIndex, module, chanNum, TXINT_RXINT)); /* Tx and Rx internal */
check_status(naibrd_SER_SetBaudrate(cardIndex, module, chanNum, 115200)); /* 115,200 HDLC/sync mode */
check_status(naibrd_SER_SetRxHdlcAddrsSyncChar(cardIndex, module, chanNum, 0x247A)); /* recv sync char - must be same as xmit for loopback */
check_status(naibrd_SER_SetTxHdlcAddrsSyncChar(cardIndex, module, chanNum, 0x247A)); /* xmit sync char - must be same as recv for loopback */
nConfigWordLo = (NAI_SER_CFGLO_ADDR_LEN_16 | NAI_SER_CFGLO_ADDR_REC); /* 16-bit HDLC addr recognition */
check_status(naibrd_SER_SetChannelConfigRaw(cardIndex, module, chanNum, nConfigWordLo));
nai_msDelay(20); /* Allow 20ms for the HW to acknowledge the configuration (GEN 2/3 only)*/
check_status(naibrd_SER_SetReceiverEnable(cardIndex, module, chanNum, 1)); /* Enable the Receiver */
/* 100 millisecond wait to ensure the receiver is on. */
nai_msDelay(100);
for (i = 0; i < NUM_DATA_TX; i++)
SendData[i] = (uint8_t)(i + 0x31); /* incremental data */
nNumWordsSend = i;
printf("Sending %d words ...", nNumWordsSend);
/* Load the transmit FIFO with data. */
naibrd_SER_TransmitBuffer(cardIndex, module, chanNum, sizeof(SendData[0]), SendData, nNumWordsSend, (uint32_t*)&nNumWordsRecv);
/* Initiate Transmit */
naibrd_SER_TransmitInitiate(cardIndex, module, chanNum);
printf(" %d words sent\n", nNumWordsRecv);
printf("Please press Enter to read back data...");
while ((ch = getchar()) != 0x0A);
nNumWordsRecv = 0;
check_status(naibrd_SER_GetHDLCPacket32(cardIndex, module, chanNum, RecvDataStatus, MAX_DATA_RX,
(uint32_t*)&nNumWordsRecv, MAX_TIMEOUT));
printf(" %d words read\n", nNumWordsRecv);
for (i = 0; i < nNumWordsRecv; i++)
printf("Sent 0x%02X; Recd 0x%02X, Status= %02X\n",
SendData[i], (RecvDataStatus[i] & 0x00FF), (RecvDataStatus[i] >> 8) & 0x00FF);
}
else
{
/************************************************ Gen5 ***************************************/
/* Using a wrap connection between 2 channels (one tx channel and one rx channel) */
/* Tx and Rx channels are user defined, but the user must connect these channels as follows: */
/* */
/* Tx Channel | Rx Channel */
/* Tx+ --> Rx+ */
/* Tx- --> Rx- */
/* Clk+ --> Clk+ */
/* Clk- --> Clk- */
/*********************************************************************************************/
int32_t txChanNum, rxChanNum;
printf("\nSelect Transmitter channel.");
naiapp_query_ChannelNumber(channelCount, 1, &txChanNum);
printf("Select Receiver channel.");
naiapp_query_ChannelNumber(channelCount, 2, &rxChanNum);
/* Reset and clear Transmitters FIFOs. */
check_status(naibrd_SER_ChannelReset(cardIndex, module, txChanNum));
check_status(naibrd_SER_ClearRxFifo(cardIndex, module, txChanNum));
check_status(naibrd_SER_ClearTxFifo(cardIndex, module, txChanNum));
nCntlValueLo = NAI_SER_CTRLLO_CLEAR_RX_FIFO | NAI_SER_CTRLLO_CLEAR_TX_FIFO;
for (i = 0; i < 1000 && (nCntlValueLo & (NAI_SER_CTRLLO_CLEAR_RX_FIFO | NAI_SER_CTRLLO_CLEAR_TX_FIFO)); i++)
{
nai_ser_chanctrl chanCtrlRaw;
check_status(naibrd_SER_GetChannelControlRaw(cardIndex, module, txChanNum, &chanCtrlRaw));
nCntlValueLo = chanCtrlRaw & 0x0000FFFF;
nai_msDelay(1);
}
if (i == 1000)
{
printf("Unable to clear Transmitter FIFOs %d\n", txChanNum);
printf("Please press Enter to exit...");
while ((ch = getchar()) != 0x0A);
return;
}
/* Reset and clear Receivers FIFOs. */
check_status(naibrd_SER_ChannelReset(cardIndex, module, rxChanNum));
check_status(naibrd_SER_ClearRxFifo(cardIndex, module, rxChanNum));
check_status(naibrd_SER_ClearTxFifo(cardIndex, module, rxChanNum));
nCntlValueLo = NAI_SER_CTRLLO_CLEAR_RX_FIFO | NAI_SER_CTRLLO_CLEAR_TX_FIFO;
for (i = 0; i < 1000 && (nCntlValueLo & (NAI_SER_CTRLLO_CLEAR_RX_FIFO | NAI_SER_CTRLLO_CLEAR_TX_FIFO)); i++)
{
nai_ser_chanctrl chanCtrlRaw;
check_status(naibrd_SER_GetChannelControlRaw(cardIndex, module, rxChanNum, &chanCtrlRaw));
nCntlValueLo = chanCtrlRaw & 0x0000FFFF;
nai_msDelay(1);
}
if (i == 1000)
{
printf("Unable to clear Receiver FIFOs %d\n", rxChanNum);
printf("Please press Enter to exit...");
while ((ch = getchar()) != 0x0A);
return;
}
/* Configure Transmitter. */
printf("\nTransmitter Serial Channel # %d\n", txChanNum);
check_status(naibrd_SER_SetProtocol(cardIndex, module, txChanNum, NAI_SER_PROTOCOL_HDLC)); /* HDLC mode */
check_status(naibrd_SER_SetInterfaceLevel(cardIndex, module, txChanNum, NAI_SER_GEN5_INTF_RS422)); /* RS422 */
check_status(naibrd_SER_SetClockMode(cardIndex, module, txChanNum, TXEXT_RXEXT)); /* External clock (receiving clock input). */
check_status(naibrd_SER_SetBaudrate(cardIndex, module, txChanNum, 1000000)); /* 1Mbps */
/* Configure Receiver. */
printf("Receiver Serial Channel # %d\n", rxChanNum);
check_status(naibrd_SER_SetProtocol(cardIndex, module, rxChanNum, NAI_SER_PROTOCOL_HDLC)); /* HDLC mode */
check_status(naibrd_SER_SetInterfaceLevel(cardIndex, module, rxChanNum, NAI_SER_GEN5_INTF_RS422)); /* RS422 */
check_status(naibrd_SER_SetClockMode(cardIndex, module, rxChanNum, TXINT_RXINT)); /* Internal clock (driving clock). */
check_status(naibrd_SER_SetBaudrate(cardIndex, module, rxChanNum, 1000000)); /* 1Mbps*/
check_status(naibrd_SER_SetReceiverEnable(cardIndex, module, rxChanNum, 1)); /* Enable the Receiver */
/* 100 millisecond wait to ensure the receiver is on. */
//nai_msDelay(100); /* TODO: Remove me.. */
for (i = 0; i < NUM_DATA_TX; i++)
SendData[i] = (uint8_t)(i + 0x31); /* incremental data */
nNumWordsSend = i;
printf("Sending %d words ...", nNumWordsSend);
/* Load the transmit FIFO with data. */
naibrd_SER_TransmitBuffer(cardIndex, module, txChanNum, sizeof(SendData[0]), SendData, nNumWordsSend, (uint32_t*)&nNumWordsRecv);
/* Initiate Transmit. */
naibrd_SER_TransmitInitiate(cardIndex, module, txChanNum);
printf(" %d words sent\n", nNumWordsRecv);
nai_msDelay(5);
printf("Please press Enter to read back data...");
while ((ch = getchar()) != 0x0A);
nNumWordsRecv = 0;
check_status(naibrd_SER_ReceiveBuffer32(cardIndex, module, rxChanNum, RecvDataStatus, MAX_DATA_RX, (uint32_t *)&nNumWordsRecv));
printf(" %d words read\n", nNumWordsRecv);
for (i = 0; i < nNumWordsRecv; i++)
{
printf("Sent 0x%02X; Recd 0x%02X, Status= %02X",
SendData[i], (RecvDataStatus[i] & 0x00FF), (RecvDataStatus[i] >> 8) & 0x00FF);
if (((RecvDataStatus[i] >> 8) & 0x00FF) == NAI_SER_SYNC_BOF)
{
printf("\tBeginning of HDLC frame (BOF)\n");
}
else if (((RecvDataStatus[i] >> 8) & 0x00FF) == NAI_SER_SYNC_EOF)
{
printf("\tEnd of HDLC frame (EOF)\n");
}
else
{
printf("\n");
}
}
}
return;
}