AR429 Xmit
Edit this on GitLab
AR429 Xmit Sample Application (SSK 2.x)
Overview
The AR429 Xmit sample application demonstrates how to configure an ARINC 429 channel for message transmission using the NAI Software Support Kit (SSK 2.x). The application supports three transmit modes: FIFO immediate (data transmits as soon as it is loaded), FIFO triggered (data waits for a trigger signal), and scheduled (messages are sent according to a predefined schedule with gap times). The user selects the card, module, channel, data rate, and transmit mode.
This sample supports AR module types including AR1 and AR2. It is designed to work with the AR429 Recv sample application for receive testing.
For the SSK 1.x version, see AR Transmit (SSK 1.x).
Prerequisites
Before running this sample, make sure you have:
-
An NAI board with an AR module installed (AR1 or AR2).
-
SSK 2.x installed on your development host.
-
The sample applications built. Refer to the SSK 2.x Software Development Guide for platform-specific build instructions.
Board Connection and Module Selection
|
Note
|
This startup sequence is common to all NAI sample applications. |
The main() function calls naiapp_RunBoardMenu() to load a saved configuration or present the board menu, then calls AR_Transmit_run() in a loop.
Channel Configuration
The AR_Transmit_run() function configures the transmitter:
check_status(naibrd_AR_SetBaudRate(cardIndex, module, archan, datarate));
check_status(naibrd_AR_SetTxFifoThreshold(cardIndex, module, archan, 32));
check_status(naibrd_AR_SetParityBitUsage(cardIndex, module, archan, NAIBRD_AR_PAR_ODD));
check_status(naibrd_AR_SetTxGapTime(cardIndex, module, archan, 6));
-
Tx FIFO threshold — set to 32; the Tx FIFO Almost Empty status is set when the count drops below this value.
-
Gap time — 6 bit-times between messages.
Transmit Modes
FIFO Immediate Mode
Data transmits as soon as it is loaded into the FIFO:
check_status(naibrd_AR_SetTransmitSendMode(cardIndex, module, channel, txmode));
check_status(naibrd_AR_SetTxEnable(cardIndex, module, channel, NAI_TRUE));
check_status(naibrd_AR_LoadTxFifo(cardIndex, module, channel, dataIndex, SendData, &nNumWordsSent));
The application loads data in blocks of 200 words, polls for Tx FIFO Almost Empty before loading the next block. In immediate mode, naibrd_AR_SendAsyncMsg() can also be used to inject a single asynchronous message into an active scheduled transmission.
FIFO Triggered Mode
Same as immediate mode but transmission does not start until a trigger is sent:
check_status(naibrd_AR_SetTxSendTrigger(cardIndex, module, channel));
Scheduled Mode
Messages are sent according to a predefined schedule using message memory and scheduler commands:
check_status(naibrd_AR_WriteMsgMem(cardIndex, module, channel, i, messageMemory[i]));
check_status(naibrd_AR_SetTxScheduleCmd(cardIndex, module, channel, i, cmd, parameter));
check_status(naibrd_AR_SetTxSendTrigger(cardIndex, module, channel));
Schedule commands include: Message, Gap, Fixed Gap, Jump, Stop, Pause, and Interrupt.
Once the schedule is running, naibrd_AR_SendAsyncMsg() can inject asynchronous data into the transmission stream. When the user is done, naibrd_AR_SetTxStop() halts the scheduled transmission.
The helper function waitForStatus() uses naibrd_AR_GetEventMappedStatusRaw() to poll for real-time channel status events such as Tx FIFO Almost Empty or Tx FIFO Empty before proceeding with the next operation.
Troubleshooting Reference
| Error / Symptom | Possible Causes | Suggested Resolution |
|---|---|---|
No board found or connection timeout |
Board not powered, incorrect configuration file |
Verify hardware is powered and connected. |
Data not received by companion application |
Cable not connected, data rate mismatch, wrong channel |
Verify ARINC 429 cabling and ensure both applications use the same data rate. |
Tx FIFO overflow |
Loading data faster than the transmitter can send |
Wait for Tx FIFO Almost Empty before loading more data. |
Triggered mode does not transmit |
Trigger not sent |
Call |
Schedule mode issues |
Incorrect schedule commands or message memory |
Verify the schedule command table and message memory entries. |
Module not present at selected slot |
No AR module installed |
Verify hardware configuration. |
Full Source
The complete source for this sample is provided below for reference. The sections above explain each part in detail.
Full Source — ar429_xmit.c (SSK 2.x)
/* nailib include files */
#include "nai_libs/nailib/include/naitypes.h"
#include "nai_libs/nailib/include/nailib.h"
#include "nai_libs/nailib/include/nailib_utils.h"
/* naibrd include files */
#include "nai_libs/naibrd/include/naibrd.h"
/* naiif include files */
#include "nai_libs/naiif/include/naiif_stdio.h"
/* Common Sample Program include files */
#include "nai_sample_apps/naiapp_common/include/naiapp_boardaccess_menu.h"
#include "nai_sample_apps/naiapp_common/include/naiapp_boardaccess_query.h"
#include "nai_sample_apps/naiapp_common/include/naiapp_boardaccess_access.h"
#include "nai_sample_apps/naiapp_common/include/naiapp_boardaccess_display.h"
#include "nai_sample_apps/naiapp_common/include/naiapp_boardaccess_utils.h"
/* AD Sample App include files */
#include "nai_sample_apps/naiapp_src/board_modules/ar429/ar429_common_utils/ar429_common_utils.h"
static const int8_t *CONFIG_FILE = (int8_t *)"default_ARXmit.txt";
/* Function prototypes */
static bool_t AR_Transmit_run();
static bool_t AR_TxFIFO(int32_t cardIndex, int32_t module, int32_t channel, naibrd_ar_tx_mode_t txmode);
static bool_t AR_TxSchedule(int32_t cardIndex, int32_t module, int32_t channel, naibrd_ar_tx_mode_t txmode);
static const char *commandToStr(naibrd_ar_sched_cmd_t cmd);
static void waitForStatus(int32_t cardIndex, int32_t module, int32_t channel, uint32_t status);
/* Default channel selection */
#define DEF_AR_CARD_INDEX 0
#define DEF_AR_MODULE 1
#define DEF_AR_XMIT_CHANNEL 1
/* Default channel configuration settings */
#define DEF_AR_DATA_RATE NAIBRD_AR_SPEED_LOW
#define DEF_AR_TX_MODE NAIBRD_AR_TX_SENDMODE_IMMED
#define DEF_AR_XMIT_DATA_COUNT 1
/**************************************************************************************************************/
/**
* <summary>
* The purpose of the ar429_xmit is to illustrate the methods to call in the naibrd library to configure
* the ARINC channel to transmit ARINC messages in FIFO mode.
*
* The following system configuration routines from the nai_sys_cfg.c file are called to assist with the configuration
* setup for this program prior to calling the naibrd 1553 routines.
* - ConfigDevice
* - DisplayDeviceCfg
* - GetBoardSNModCfg
* - CheckModule
*
* Note, the AR_Transmit application can run in conjunction with the AR_Receive, AR_ReceiveInterruptEther or
* AR_ReceiveInterruptBus applications to illustrate ARINC transmit and receive operations together with the NAI ARINC module.
* </summary>
*/
/**************************************************************************************************************/
#ifdef NAIBSP_CONFIG_SOFTWARE_OS_VXWORKS
int32_t ar429_xmit(void)
#else
int32_t main(void)
#endif
{
bool_t bQuit = NAI_FALSE;
int8_t inputBuffer[80];
int32_t inputResponseCnt;
if (naiapp_RunBoardMenu(CONFIG_FILE) == (bool_t)NAI_TRUE)
{
while (!bQuit)
{
bQuit = AR_Transmit_run();
}
naiif_printf("Type the Enter key to exit the program: ");
naiapp_query_ForQuitResponse(sizeof(inputBuffer), NAI_QUIT_CHAR, inputBuffer, &inputResponseCnt);
}
naiapp_access_CloseAllOpenCards();
return 0;
}
/**************************************************************************************************************/
/**
<summary>
Run_AR_Transmit queries the user for the card, module and channel to configure as the ARINC transmitter
as well as the data rate (high (100KHz) or low (12.5KHz)) and the mode of message transmission (FIFO Immediate,
Scheduled or FIFO Triggered). Methods in the naibrd library are invoked to configure the ARINC channel.
Once the ARINC channel is configured:
1) In FIFO Immediate mode, the user enters the number of words to transmit. When the Tx FIFO is loaded with data,
transmission begins immediately and the program polls the channel status to check Tx FIFO Almost Empty and if true,
more data (if any) is loaded into the Tx FIFO to keep the transmission going.
2) In FIFO Triggered mode, the user enters the number of words to transmit. When the Tx FIFO is loaded with data,
transmission does not begin immediately. Instead the user will be asked to send a trigger to initiate transmission
and the program polls the channel status to check Tx FIFO Almost Empty and if true, more data (if any) is loaded
into the Tx FIFO to keep the transmission going.
</summary>
*/
/**************************************************************************************************************/
static bool_t AR_Transmit_run()
{
int32_t archan;
naibrd_ar_datarate_t datarate;
bool_t bQuit = NAI_FALSE;
naibrd_ar_tx_mode_t txmode;
int32_t cardIndex, module;
bQuit = GetARCfg(DEF_AR_CARD_INDEX, DEF_AR_MODULE, DEF_AR_XMIT_CHANNEL, &cardIndex, &module, &archan);
if (!bQuit)
{
/* Get Data Rate */
bQuit = GetARINCDataRate(DEF_AR_DATA_RATE, &datarate);
if (!bQuit)
{
/* Set the transmission speed */
check_status(naibrd_AR_SetBaudRate(cardIndex, module, archan, datarate));
/* Set the Tx Fifo Threshold to 32 (max is 255). If the number of messages in the Tx FIFO falls under 32, the Tx FIFO Almost Empty Status will be set */
check_status(naibrd_AR_SetTxFifoThreshold(cardIndex, module, archan, 32));
/* Set the Parity Bit Usage to treat ARINC bit 32 as an odd parity bit and perform parity checking */
check_status(naibrd_AR_SetParityBitUsage(cardIndex, module, archan, NAIBRD_AR_PAR_ODD));
/* Set the inter-message transmission gap time (interval rate) */
check_status(naibrd_AR_SetTxGapTime(cardIndex, module, archan, 6)); /* 6 bit-times */
/* Get the Tx Mode */
bQuit = GetARTxMode(DEF_AR_TX_MODE, &txmode);
if (!bQuit)
{
/* Schedule mode not supported in naibrd library.. for now */
if (txmode == NAIBRD_AR_TX_SENDMODE_SCHED)
{
bQuit = AR_TxSchedule(cardIndex, module, archan, txmode);
}
else
{
bQuit = AR_TxFIFO(cardIndex, module, archan, txmode);
}
}
}
}
return bQuit;
}
static bool_t AR_TxFIFO(int32_t cardIndex, int32_t module, int32_t channel, naibrd_ar_tx_mode_t txmode)
{
bool_t bQuit = NAI_FALSE;
int32_t nNumWordsToSend = 1;
int32_t nNumWordsSent;
int32_t i, j;
int32_t blockCnt, dataCnt, dataIndex;
int32_t increment = 0x55555555;
uint32_t SendData[255];
int32_t blockSize = 200;
int8_t inputBuffer[80];
int32_t inputResponseCnt;
/* Set FIFO Transmission mode */
check_status(naibrd_AR_SetTransmitSendMode(cardIndex, module, channel, txmode));
/* Enable transmitter */
check_status(naibrd_AR_SetTxEnable(cardIndex, module, channel, NAI_TRUE));
while (!bQuit)
{
/* Query for the number of data words to send */
bQuit = GetARTransmitDataCount(DEF_AR_XMIT_DATA_COUNT, &nNumWordsToSend);
if (!bQuit)
{
/* Break up the FIFO updates to blocks of 200. The idea here is to load and transmit 200 ARINC words at a time */
/* until all of the words have been sent. The following code causes loading and re-loading of the Tx buffer to */
/* occur when the Tx FIFO is almost empty, which means less than 32 ARINC messages are in the FIFO and there is */
/* room in the buffer for 200 more messages. */
blockCnt = nNumWordsToSend / blockSize;
if (blockCnt * blockSize < nNumWordsToSend)
blockCnt++;
dataCnt = 0;
for (i = 0; i < blockCnt; i++)
{
dataIndex = 0;
do
{
SendData[dataIndex++] = (uint32_t)increment++; /* incremental data */
dataCnt++;
} while ((dataIndex < blockSize) && (dataCnt < nNumWordsToSend));
naiif_printf("\r\nLoading %d words ...\r\n", dataIndex);
for (j = 0; j < dataIndex; j++)
naiif_printf("0x%08X\r\n", SendData[j]);
check_status(naibrd_AR_LoadTxFifo(cardIndex, module, channel, dataIndex, SendData, &nNumWordsSent)); /* send data */
if (txmode == NAIBRD_AR_TX_SENDMODE_TRGF)
{
/* If Triggered Mode, user sends trigger signal to start transmission */
naiif_printf("Press Enter to send trigger signal and start transmission...\r\n");
naiapp_query_ForQuitResponse(sizeof(inputBuffer), NAI_QUIT_CHAR, inputBuffer, &inputResponseCnt);
check_status(naibrd_AR_SetTxSendTrigger(cardIndex, module, channel));
}
naiif_printf(" %d words sent. Total words sent = %d\r\n", nNumWordsSent, dataCnt);
/* Wait for Tx Buffer Almost Empty before loading more messages into Tx FIFO */
waitForStatus(cardIndex, module, channel, NAIBRD_AR_EVENT_STATUS_GENERAL_TX_FIFO_ALM_EMPTY);
}
if(txmode == NAIBRD_AR_TX_SENDMODE_IMMED)
/* Lastly, wait for Tx Buffer to empty */
waitForStatus(cardIndex, module, channel, NAIBRD_AR_EVENT_STATUS_GENERAL_TX_FIFO_EMPTY);
}
}
/* Disable transmitter */
check_status(naibrd_AR_SetTxEnable(cardIndex, module, channel, NAI_FALSE));
return bQuit;
}
static bool_t AR_TxSchedule(int32_t cardIndex, int32_t module, int32_t channel, naibrd_ar_tx_mode_t txmode)
{
bool_t bQuit = NAI_FALSE;
int8_t inputBuffer[80];
int32_t inputResponseCnt;
uint32_t i;
/* Sequentialy ordered; array index 0 corelates to message memory register 0 */
/* 1024 max memory entries */
const uint32_t messageMemory[] = {
0x55555555, 0xAAAAAAAA, 0xABCDEF55, 0x987654EE, 0x3210FD07,
0x555555EE, 0xAAAAAA0F, 0xFFFFFFFF, 0x00001234, 0x00002564
};
/* Sequentialy ordered; array index 0 corelates to schedule register 0 */
const struct
{
naibrd_ar_sched_cmd_t cmd;
uint16_t parameter;
}
/* 512 max command entries */
schedulerCmds[] =
{
{ NAIBRD_AR_TX_SCHED_MESSAGE, 0 },
{ NAIBRD_AR_TX_SCHED_FIXEDGAP, 9 },
{ NAIBRD_AR_TX_SCHED_MESSAGE, 1 },
{ NAIBRD_AR_TX_SCHED_GAP, 8 },
{ NAIBRD_AR_TX_SCHED_MESSAGE, 2 },
{ NAIBRD_AR_TX_SCHED_FIXEDGAP, 9 },
{ NAIBRD_AR_TX_SCHED_MESSAGE, 3 },
{ NAIBRD_AR_TX_SCHED_GAP, 8 },
{ NAIBRD_AR_TX_SCHED_MESSAGE, 4 },
{ NAIBRD_AR_TX_SCHED_FIXEDGAP, 9 },
{ NAIBRD_AR_TX_SCHED_MESSAGE, 5 },
{ NAIBRD_AR_TX_SCHED_GAP, 8 },
{ NAIBRD_AR_TX_SCHED_MESSAGE, 6 },
{ NAIBRD_AR_TX_SCHED_FIXEDGAP, 9 },
{ NAIBRD_AR_TX_SCHED_MESSAGE, 7 },
{ NAIBRD_AR_TX_SCHED_GAP, 8 },
{ NAIBRD_AR_TX_SCHED_JUMP, 0 },
{ NAIBRD_AR_TX_SCHED_STOP, 0 },
};
/* Set Scheduled Transmission mode */
check_status(naibrd_AR_SetTransmitSendMode(cardIndex, module, channel, txmode));
/* Enable transmitter */
check_status(naibrd_AR_SetTxEnable(cardIndex, module, channel, NAI_TRUE));
/************************************************************************/
/* Initialize Message Memory (0 - 255) with Message Words and Gap Times */
/************************************************************************/
naiif_printf("Initializing Message Memory\r\n");
for (i = 0; i < (sizeof(messageMemory) / sizeof(messageMemory[0])); i++)
{
check_status(naibrd_AR_WriteMsgMem(cardIndex, module, channel, i, messageMemory[i]));
}
/***********************************************************/
/* Build and Download Schedule - Schedule Memory (0 - 511) */
/***********************************************************/
naiif_printf("Building and Downloading Schedule\r\n");
naiif_printf("%8s %13s %5s\r\n", "Schedule", "Command Type", "Data");
for (i = 0; i < (sizeof(schedulerCmds) / sizeof(schedulerCmds[0])); i++)
{
naibrd_ar_sched_cmd_t cmd = schedulerCmds[i].cmd;
uint16_t parameter = schedulerCmds[i].parameter;
const char *cmdStr = commandToStr(cmd);
check_status(naibrd_AR_SetTxScheduleCmd(cardIndex, module, channel, i, cmd, parameter));
switch (cmd)
{
case NAIBRD_AR_TX_SCHED_STOP:
case NAIBRD_AR_TX_SCHED_PAUSE:
case NAIBRD_AR_TX_SCHED_INTERRUPT:
naiif_printf("%-9u %-13s %10s\r\n", i, cmdStr, "<None>");
break;
case NAIBRD_AR_TX_SCHED_JUMP:
naiif_printf("%-9u %-13s %#010x (Jumps to Schedule %hu)\r\n", i, cmdStr, messageMemory[parameter], parameter);
break;
default:
naiif_printf("%-9u %-13s %#010x\r\n", i, cmdStr, messageMemory[parameter]);
}
}
/* Start schedule mode */
naiif_printf("\r\nStarting Schedule\r\n");
check_status(naibrd_AR_SetTxSendTrigger(cardIndex, module, channel));
while (!bQuit)
{
naiif_printf("\r\nType A to send Async Data (0x11111111) or %c to quit (default: A) : ", NAI_QUIT_CHAR);
bQuit = naiapp_query_ForQuitResponse(sizeof(inputBuffer), NAI_QUIT_CHAR, inputBuffer, &inputResponseCnt);
if (!bQuit)
{
check_status(naibrd_AR_SendAsyncMsg(cardIndex, module, channel, 0x11111111));
}
}
/* Stop schedule mode */
naiif_printf("\r\nStopping Schedule\r\n");
check_status(naibrd_AR_SetTxStop(cardIndex, module, channel));
/* Disable transmitter */
/*check_status(naibrd_AR_SetTxEnable(cardIndex, module, channel, NAI_FALSE));*/
return bQuit;
}
static const char *commandToStr(naibrd_ar_sched_cmd_t cmd)
{
switch (cmd)
{
case NAIBRD_AR_TX_SCHED_STOP:
return "Stop";
case NAIBRD_AR_TX_SCHED_MESSAGE:
return "Message";
case NAIBRD_AR_TX_SCHED_GAP:
return "Gap";
case NAIBRD_AR_TX_SCHED_FIXEDGAP:
return "Fixed Gap";
case NAIBRD_AR_TX_SCHED_PAUSE:
return "Pause";
case NAIBRD_AR_TX_SCHED_INTERRUPT:
return "Interrupt";
case NAIBRD_AR_TX_SCHED_JUMP:
return "Jump";
default:
return "";
}
}
/* This function waits on one or more realtime (dynamic) channel status bits as defined by the user and exits when all bits are set. */
static void waitForStatus(int32_t cardIndex, int32_t module, int32_t channel, uint32_t status)
{
uint32_t chanStatus;
do
{
check_status(naibrd_AR_GetEventMappedStatusRaw(cardIndex, module, channel, NAI_STATUS_REALTIME, NAIBRD_AR_EVENT_MAP_GENERAL, &chanStatus));
naibrd_msDelay(1);
} while ((chanStatus & status) != status);
}