MX Foundation 4
ar429_embedded_bridge.cs
/********************************************************************************
//
// File:
// arinc429_embedded_bridge.cs
//
// 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 label >= 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 with loopback between first and second TX and RX ARINC 429 Enhanced channels.
//
*********************************************************************************/
//#define LOOPBACK
//#define LOCAL
using System;
using static MAXT.MXFoundation.mxf;
using System.Runtime.InteropServices;
using System.Text;
namespace ar429_example
{
class ar429_embedded_bridge
{
const int MAX_CHANNELS = 2;
const int BUFFER_SIZE = 8192; // 8KB
const int MAX_TX_RECORDS_TO_TRANSMIT = 256;
static void Main(string[] args)
{
UInt32 rc;
UInt64 server;
UInt64 device = 0;
var module = new UInt64[1];
UInt64 count = 0;
var txChannel = new UInt64[MAX_CHANNELS]; // txChannel[0] = application transmit channel
// txChannel[1] = bridge channel linked to rxChannel[0]
var rxChannel = new UInt64[MAX_CHANNELS]; // rxChannel[0] = receive bridge channel
// rxChannel[1] = application receive channel
UInt64 rxBuffer = 0;
var txBuffer = new UInt64[MAX_CHANNELS];
UInt64 bridge = 0;
UInt64 i, indexBuffer;
string mask = "DM:XXXXXXXXXXXXXXXXXXXXXXXX10101010";
UInt64 modulo = 1;
UInt64 status, msgsCount = 0, bytesCount;
UInt64 label, sdi, data, ssm, parity;
UInt64 allocated = 0;
IntPtr hostBuffer = IntPtr.Zero;
IntPtr recPtr = IntPtr.Zero;
// Connect to services local or remote
#if LOCAL
rc = mxfServerConnect("0.0.0.0", "", "", Convert.ToUInt64(false), out server);
#else
rc = mxfServerConnect("192.168.0.1", "admin", "admin", Convert.ToUInt64(false), out server);
#endif
if (rc != MAXT_SUCCESS)
{
Console.WriteLine("Failed to connect; rc=0x{0:x8}", rc);
Console.WriteLine("Press a key to terminate");
Console.Read();
return;
}
// Initialize the server
Console.WriteLine("Starting");
rc = mxfSystemInit(server);
// Get the first device handle
if (rc == MAXT_SUCCESS)
rc = mxfSystemDeviceGet(server, 0, out device);
if (rc == MAXT_SUCCESS)
rc = mxfDeviceModuleAllGet(device, MXF_MODULE_A429_EH, 1, out count, module);
// If module, return an error
if ((rc == MAXT_SUCCESS) && (count == 0))
rc = MAXT_ERROR_NOT_FOUND;
// Obtain the first two ARINC 429 Protocol RX channel
if (rc == MAXT_SUCCESS)
rc = mxfModuleChannelAllGet(module[0], MXF_CLASS_A429, MXF_SCLASS_RX_CHANNEL, MAX_CHANNELS, out count, rxChannel);
// Obtain the first two ARINC 429 Protocol TX channel
if ((rc == MAXT_SUCCESS) && (count == MAX_CHANNELS))
rc = mxfModuleChannelAllGet(module[0], MXF_CLASS_A429, MXF_SCLASS_TX_CHANNEL, MAX_CHANNELS, out count, txChannel);
// If channels not found, return an error
if ((rc == MAXT_SUCCESS) && (count != MAX_CHANNELS))
rc = MAXT_ERROR_NOT_FOUND;
// Set timebase to 64-bit microseconds
if (rc == MAXT_SUCCESS)
rc = mxfSystemTimeBaseSet(server, MXF_TIMEBASE_DEVICE_USEC);
// Configure the channels
for (i = 0; i < MAX_CHANNELS && (rc == MAXT_SUCCESS); i++)
{
// Set channels speed
rc = mxfAttributeUint64Set(rxChannel[i], KMXF_A429_SPEED, 100000);
if (rc == MAXT_SUCCESS)
rc = mxfAttributeUint64Set(txChannel[i], KMXF_A429_SPEED, 100000);
//Activate loopback before transmission and reception
#if LOOPBACK
if (rc == MAXT_SUCCESS)
rc = mxfAttributeUint64Set(rxChannel[i], KMXF_A429_TX_RX_TEST_LB, VMXF_ENABLE);
#endif
}
// Allocate RX acquisition buffer
if (rc == MAXT_SUCCESS)
rc = mxfRxAcqBufferAlloc(rxChannel[1], BUFFER_SIZE, out rxBuffer, out allocated);
// Allocate Aperiodic TX static buffer for HIGH priority queue
if (rc == MAXT_SUCCESS)
rc = mxfTxAperiodicBufferAlloc(txChannel[0], MXF_TXAPERIODIC_PRIORITY_HIGH, BUFFER_SIZE, out txBuffer[0], out allocated);
// Allocate Aperiodic TX static buffer for HIGH priority queue
if (rc == MAXT_SUCCESS)
rc = mxfTxAperiodicBufferAlloc(txChannel[1], MXF_TXAPERIODIC_PRIORITY_HIGH, BUFFER_SIZE, out txBuffer[1], out allocated);
// Allocate host buffer
if (rc == MAXT_SUCCESS)
{
try
{
hostBuffer = Marshal.AllocHGlobal(BUFFER_SIZE);
}
catch (OutOfMemoryException)
{
rc = MAXT_ERROR_MEM;
}
}
// Start the acquisition mode
if (rc == MAXT_SUCCESS)
rc = mxfRxAcqModeSet(rxBuffer, MXF_RXACQ_MODE_LINEAR);
// Set aging timeout
if (rc == MAXT_SUCCESS)
rc = mxfAttributeUint64Set(module[0], KMXF_A429_MODULE_RX_FIFO_AGING, 512);
// Start acquisition
if (rc == MAXT_SUCCESS)
{
rc = mxfRxAcqStart(rxBuffer, MXF_RXACQ_FLAG_DEFAULT, 0, 0);
if (rc == MAXT_SUCCESS)
{
Console.WriteLine();
Console.WriteLine("Acquisition started");
}
}
// Create the Embedded Bridge:
// - the source is the first RX channel
// - the destination is the transmission buffer of the second TX channel
if (rc == MAXT_SUCCESS)
rc = mxfBridgeCreate(rxChannel[0], txBuffer[1], out bridge);
// Set the internal transit delay to 1.5ms
if (rc == MAXT_SUCCESS)
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 == MAXT_SUCCESS); i++)
rc = mxfBridgeSelectSet(bridge, i, modulo, mask);
// Start the bridge
if (rc == MAXT_SUCCESS)
{
rc = mxfBridgeStart(bridge);
if (rc == MAXT_SUCCESS)
{
Console.WriteLine();
Console.WriteLine("Bridge started");
}
}
if (rc == MAXT_SUCCESS)
{
Console.WriteLine("Starting transmission");
recPtr = hostBuffer;
// Send aperiodic messages with a new label each time (+1)
for (i = 0; (i < MAX_TX_RECORDS_TO_TRANSMIT) && (rc == MAXT_SUCCESS); i++)
{
// Set each records
rec429.timeTag = 0;
rec429.control = 0;
rec429.repeatCount = 1;
rec429.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, out rec429.data);
Marshal.StructureToPtr(rec429, recPtr, false);
mxfA429NextDataRecordPtrGet(recPtr, out recPtr);
}
}
// Transmit the array of records
if (rc == MAXT_SUCCESS)
{
rc = mxfA429TxAperiodicWrite(txBuffer[0], MXF_TXAPERIODIC_FLAG_DEFAULT, 0, MAX_TX_RECORDS_TO_TRANSMIT, hostBuffer);
if (rc == MAXT_SUCCESS)
Console.WriteLine("{0} records transmitted", MAX_TX_RECORDS_TO_TRANSMIT);
}
// Wait a little for transmission to occur
mxfSleep(100);
// Read and display records
if (rc == MAXT_SUCCESS)
rc = mxfA429RxAcqRead(rxBuffer, 0, BUFFER_SIZE, out status, out msgsCount, out bytesCount, hostBuffer);
recPtr = hostBuffer;
for (i = 0; (i < msgsCount) && (rc == MAXT_SUCCESS); i++)
{
rec429 = (MXF_A429_DATAREC)Marshal.PtrToStructure(recPtr, typeof(MXF_A429_DATAREC));
rc = mxfA429ArwDecompose(rec429.data, out label, out sdi, out data, out ssm, out parity);
Console.WriteLine("{0:D2}: Timetag {1} - ARINC word=[{2},{3},{4:X5},{5},{6}]",
i, rec429.timeTag, parity, ssm, data, sdi, Convert.ToString((int)label, 8).PadLeft(3, '0'));
if (rc == MAXT_SUCCESS)
rc = mxfA429NextDataRecordPtrGet(recPtr, out recPtr);
}
// Stop the bridge process and delete the object
if (rc == MAXT_SUCCESS)
{
rc = mxfBridgeStop(bridge);
if (rc == MAXT_SUCCESS)
{
Console.WriteLine();
Console.WriteLine("Bridge stopped");
rc = mxfBridgeTerminate(bridge);
}
}
if (rc == MAXT_SUCCESS)
{
rc = mxfRxAcqStop(rxBuffer);
if (rc == MAXT_SUCCESS)
{
Console.WriteLine();
Console.WriteLine("Acquisition stopped");
rc = mxfRxAcqClear(rxBuffer);
}
}
// Catch any previous error
if (rc != MAXT_SUCCESS)
{
StringBuilder buffer = new StringBuilder(256);
if (mxfSystemErrorStringGet(server, rc, (UInt32)buffer.Capacity, buffer) != MAXT_SUCCESS)
{
buffer.Clear();
buffer.Append(string.Format("ERROR # 0x{0:x8}", rc));
}
Console.Write(buffer + "\n\r");
}
Console.WriteLine();
Console.WriteLine("Terminating");
// Free all buffers and terminate
if (rxBuffer != 0)
mxfRxAcqBufferFree(rxBuffer);
for (indexBuffer = 0; indexBuffer < 2; indexBuffer++)
{
if (txBuffer[indexBuffer] != 0)
mxfTxAperiodicBufferFree(txBuffer[indexBuffer]);
}
if (hostBuffer != IntPtr.Zero)
Marshal.FreeHGlobal(hostBuffer);
Console.WriteLine();
Console.WriteLine("Press enter to terminate");
Console.Read();
return;
}
}
}
Updated 10/23/2023