MX Foundation 4
ar429_embedded_bridge.c
/********************************************************************************
//
// File:
// arinc429_embedded_bridge.c
//
// Copyright (c) MAX Technologies Inc. 1988-2019, All Rights Reserved.
// CONFIDENTIAL AND PROPRIETARY INFORMATION WHICH IS THE
// PROPERTY OF MAX TECHNOLOGIES INC.
//
// This demo shows low level bridge routing API usage.
// In this example shows the bridging between two channels with traffic filtering.
//
// More specifically this demo works a follow;
//
// The program send data (256 word) on first card channel txChannel[0].
// Each data words is sent with a new label address from 1 to 255.
// When the data is received on rxChannel[0] the data is 'bridged' to txChannel1[1]
// if the label is < 50. if >= 50 the words are not redirected and the
// data implicitly filtered. When the words are redirected, the data label
// is modified to 0252 using a mask. The data is then retransmitted and received
// again (50 words) this time on the acquisition channel rxChannel[1].
//
// Hardware Requirements:
// - MAXT Flex or PCI-500 carrier
// - Loopback between first and second TX and RX ARINC 429 channels.
//
*********************************************************************************/
#include "example.h"
//#define LOOPBACK
//#define LOCAL
#define MAX_CHANNELS 2
#define BUFFER_SIZE 8192 // 8KB
#define MAX_TX_RECORDS_TO_TRANSMIT 256
/******************************************************************************/
// Main
/******************************************************************************/
int main(void)
{
uint32 rc;
HMXF_SERVER server;
HMXF_DEVICE device = 0;
HMXF_MODULE module = 0;
uint64 count = 0, type = 0;
HMXF_CHANNEL txChannel[MAX_CHANNELS] = { 0, 0 }; // txChannel[0] = application transmit channel
// txChannel[1] = bridge channel linked to rxChannel[0]
HMXF_CHANNEL rxChannel[MAX_CHANNELS] = { 0, 0 }; // rxChannel[0] = receive bridge channel
// rxChannel[1] = application receive channel
HMXF_BUFFER rxBuffer = 0;
HMXF_BUFFER txBuffer[MAX_CHANNELS] = { 0, 0 };
HMXF_BRIDGE bridge = 0;
MXF_A429_DATAREC* rec429 = NULL;
uint64 i, indexBuffer;
char mask[36] = "DM:XXXXXXXXXXXXXXXXXXXXXXXX10101010";
uint64 modulo = 1;
uint64 status, msgsCount = 0, bytesCount;
uint64 label, sdi, data, ssm, parity;
// Connect to services local or remote
#ifdef LOCAL
rc = mxfServerConnect("0.0.0.0", "", "", FALSE, &server);
#else
rc = mxfServerConnect("192.168.0.1", "admin", "admin", FALSE, &server);
#endif
if (rc != MAXT_SUCCESS)
{
printf("Failed to connect; rc=0x%08x", rc);
printf("\nPress a key to terminate\n");
getchar();
return 0;
}
// Initialize the server
printf("\nStarting\n");
rc = mxfSystemInit(server);
// Get the first device handle
if (!rc)
rc = mxfSystemDeviceGet(server, 0, &device);
// Obtain the first ARINC 429 Protocol RX channel
if (!rc)
rc = mxfChannelAllGet(server, MXF_CLASS_A429, MXF_SCLASS_RX_CHANNEL, MXF_MODULE_ALL, MAX_CHANNELS, &count, rxChannel);
// Obtain the first ARINC 429 Protocol TX channel
if (!rc && count)
rc = mxfChannelAllGet(server, MXF_CLASS_A429, MXF_SCLASS_TX_CHANNEL, MXF_MODULE_ALL, MAX_CHANNELS, &count, txChannel);
// If channel not found, return an error
if (!rc && !count)
rc = MAXT_ERROR_NOT_FOUND;
// Set timebase to 64-bit microseconds
if (!rc)
rc = mxfSystemTimeBaseSet(server, MXF_TIMEBASE_DEVICE_USEC);
// Configure the channels
for (i = 0; i < MAX_CHANNELS && !rc; i++)
{
//Get module type
if (!rc)
rc = mxfChannelInfoGet(rxChannel[i], NULL, &module);
if (!rc)
rc = mxfAttributeUint64Get(module, KMXF_MODULE_TYPE, &type);
// If Ipm-429
if (!rc && type == MXF_MODULE_A429E)
{
// Set the channels to high speed
if (!rc)
rc = mxfAttributeUint64Set(rxChannel[i], KMXF_A429_SPEED_SELECT, VMXF_A429_SPEED_SELECT_HIGH);
if (!rc)
rc = mxfAttributeUint64Set(txChannel[i], KMXF_A429_SPEED_SELECT, VMXF_A429_SPEED_SELECT_HIGH);
}
else
{
// Set the channels to high speed
if (!rc)
rc = mxfAttributeUint64Set(rxChannel[i], KMXF_A429_SPEED, 100000);
if (!rc)
rc = mxfAttributeUint64Set(txChannel[i], KMXF_A429_SPEED, 100000);
}
//Activate loopback before transmission and reception
#ifdef LOOPBACK
if (!rc)
rc = mxfAttributeUint64Set(rxChannel[i], KMXF_A429_TX_RX_TEST_LB, VMXF_ENABLE);
#endif
}
// Allocate RX acquisition buffer
if (!rc)
rc = mxfRxAcqBufferAlloc(rxChannel[1], BUFFER_SIZE, &rxBuffer, NULL);
// Allocate Aperiodic TX static buffer for HIGH priority queue
if (!rc)
rc = mxfTxAperiodicBufferAlloc(txChannel[0], MXF_TXAPERIODIC_PRIORITY_HIGH, BUFFER_SIZE, &txBuffer[0], NULL);
// Allocate Aperiodic TX static buffer for HIGH priority queue
if (!rc)
rc = mxfTxAperiodicBufferAlloc(txChannel[1], MXF_TXAPERIODIC_PRIORITY_HIGH, BUFFER_SIZE, &txBuffer[1], NULL);
// Allocate host buffer
if (!rc)
{
rec429 = (MXF_A429_DATAREC*)malloc(BUFFER_SIZE);
if (!rec429)
rc = MAXT_ERROR_MEM;
}
// Start the acquisition mode
if (!rc)
rc = mxfRxAcqModeSet(rxBuffer, MXF_RXACQ_MODE_LINEAR);
// Set aging timeout
if (!rc)
rc = mxfAttributeUint64Set(module, KMXF_A429_MODULE_RX_FIFO_AGING, 512);
// Start acquisition
if (!rc)
{
rc = mxfRxAcqStart(rxBuffer, MXF_RXACQ_FLAG_DEFAULT, 0, 0);
if (!rc)
printf("\nAcquisition started\n");
}
// Create the Embedded Bridge:
// - the source is the first RX channel
// - the destination is the transmission buffer of the second TX channel
if (!rc)
rc = mxfBridgeCreate(rxChannel[0], txBuffer[1], &bridge);
// Set the internal transit delay to 1.5ms
if (!rc)
rc = mxfBridgeConfigSet(bridge, 1500);
// For all data received on rxChannel[0] with a label<50,
// they are bridged to txChannel[1] on label 0252 (ARINC 429 Label Octal 1010101b=0252)
for (i = 0; i <= 50 && !rc; i++)
rc = mxfBridgeSelectSet(bridge, i, modulo, mask);
// Start the bridge
if (!rc)
{
rc = mxfBridgeStart(bridge);
if (!rc)
printf("\nBridge started\n");
}
if (!rc)
{
printf("Starting transmission\n");
p = rec429;
// Send aperiodic messages with a new label each time (+1)
for (i = 0; i < MAX_TX_RECORDS_TO_TRANSMIT && !rc; i++)
{
// Set each records
p->timeTag = 0;
p->control = 0;
p->repeatCount = 1;
p->reserved = 0;
parity = VMXF_A429_PARITY_ODD;
ssm = 0;
data = 0x135;
sdi = 2;
label = i;
// Format ARINC word
rc = mxfA429ArwCompose(label, sdi, data, ssm, parity, &p->data);
}
}
// Transmit the array of records
if (!rc)
{
rc = mxfA429TxAperiodicWrite(txBuffer[0], MXF_TXAPERIODIC_FLAG_DEFAULT, 0, MAX_TX_RECORDS_TO_TRANSMIT, rec429);
if (rc == MAXT_SUCCESS)
printf("%d records transmitted\n", MAX_TX_RECORDS_TO_TRANSMIT);
}
// Wait a little for transmission to occur
mxfSleep(100);
// Read and display records
if (!rc)
rc = mxfA429RxAcqRead(rxBuffer, 0, BUFFER_SIZE, &status, &msgsCount, &bytesCount, rec429);
p = rec429;
for (i = 0; i < msgsCount && !rc; i++)
{
mxfA429ArwDecompose(p->data, &label, &sdi, &data, &ssm, &parity);
printf("%02llu: Timetag %llu - ARINC word=[%lld,%lld,%05llX,%lld,%03llo]\n",
i, p->timeTag, parity, ssm, data, sdi, label);
}
// Stop the bridge process and delete the object
if (!rc)
{
rc = mxfBridgeStop(bridge);
if (!rc)
{
printf("\nBridge stopped\n");
rc = mxfBridgeTerminate(bridge);
}
}
if (!rc)
{
rc = mxfRxAcqStop(rxBuffer);
if (!rc)
{
printf("\nAcquisition stopped\n");
rc = mxfRxAcqClear(rxBuffer);
}
}
// Catch any previous error
if (rc)
{
char buffer[256];
rc = mxfSystemErrorStringGet(server, rc, sizeof(buffer), buffer);
printf("%s\n", buffer);
}
printf("\nTerminating\n");
// Free all buffers and terminate
if (rxBuffer)
mxfRxAcqBufferFree(rxBuffer);
for (indexBuffer = 0; indexBuffer < 2; indexBuffer++)
{
if (txBuffer[indexBuffer])
mxfTxAperiodicBufferFree(txBuffer[indexBuffer]);
}
if (rec429)
free(rec429);
printf("\nPress enter to terminate\n");
getchar();
return rc;
}
Updated 10/23/2023