MX Foundation 4
ar429_rx_event_handler.cs
/*******************************************************************************
//
// File:
// arinc429_rx_event_handler.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 how to set a basic periodic transmission.
// The receiver handler get data on specific label/sdi.
//
// Hardware Requirements:
// - MAXT Flex with loopback between first 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 arinc429_rx_event_handler
{
const int BUFFER_SIZE = 4096; // 4KB
const int LABEL = 5;
const int SDI = 0;
public static UInt32 RXmsgTotal;
/***************************************************************************************************************/
// Main
/***************************************************************************************************************/
static void Main(string[] args)
{
UInt32 rc;
UInt64 server;
UInt64 device = 0;
var module = new UInt64[1];
UInt64[] rxChannel = new UInt64[1], txChannel = new UInt64[1];
UInt64 asyncEvent = 0;
MXF_ASYNCEVENT_HANDLER asyncEventHandler = AsyncEventHandler;
UInt64 rxBuffer = 0;
UInt64[] txBuffer = new UInt64[2];
var asyncEventInfo = new MXF_ASYNCEVENT_CONDITION[2];
UInt64 count, indexBuffer;
IntPtr hostBuffer = IntPtr.Zero;
IntPtr rxRecBuffer = IntPtr.Zero;
var msgid = new MXF_MSGID_A429[1];
// Connect to services local or remote
#if LOCAL
rc = mxfServerConnect("0.0.0.0", "", "", Convert.ToUInt32(false), out server);
#else
rc = mxfServerConnect("192.168.0.1", "admin", "admin", 0, out server);
#endif
if (rc != MAXT_SUCCESS)
{
Console.Write("Failed to connect; rc=0x{0:x8}", rc);
Console.Write("\nPress a key to terminate\n");
Console.ReadKey();
return;
}
// Initialize the server
Console.Write("\nStarting\n");
rc = mxfSystemInit(server);
// Get the device handle
if (rc == MAXT_SUCCESS)
rc = mxfSystemDeviceGet(server, 0, out device);
// Get the module handle
if (rc == MAXT_SUCCESS)
rc = mxfDeviceModuleAllGet(device, MXF_MODULE_A429_EH, 1, out count, module);
// Get the first ARINC 429 Protocol RX channel (RX logical #0)
if (rc == MAXT_SUCCESS)
rc = mxfModuleChannelAllGet(module[0], MXF_CLASS_A429, MXF_SCLASS_RX_CHANNEL, 1, out count, rxChannel);
// Get the first ARINC 429 Protocol TX channel (TX logical #0)
if (rc == MAXT_SUCCESS)
rc = mxfModuleChannelAllGet(module[0], MXF_CLASS_A429, MXF_SCLASS_TX_CHANNEL, 1, out count, txChannel);
// Set the channels to low speed
if (rc == MAXT_SUCCESS)
rc = mxfAttributeUint64Set(rxChannel[0], KMXF_A429_SPEED, 12500);
if (rc == MAXT_SUCCESS)
rc = mxfAttributeUint64Set(txChannel[0], KMXF_A429_SPEED, 12500);
// Enable loopback
#if (LOOPBACK)
if (rc == MAXT_SUCCESS)
rc = mxfAttributeUint64Set(rxChannel[0], KMXF_A429_TX_RX_TEST_LB, VMXF_ENABLE);
#endif
// Set timebase to 64-bit nanoseconds
if (rc == MAXT_SUCCESS)
rc = mxfSystemTimeBaseSet(server, MXF_TIMEBASE_DEVICE_USEC);
// Alloc host buffer
if (rc == MAXT_SUCCESS)
{
try
{
hostBuffer = Marshal.AllocHGlobal(BUFFER_SIZE);
}
catch (OutOfMemoryException)
{
rc = MAXT_ERROR_MEM;
}
}
// Alloc rx buffer
if (rc == MAXT_SUCCESS)
{
try
{
rxRecBuffer = Marshal.AllocHGlobal(BUFFER_SIZE);
}
catch (OutOfMemoryException)
{
rc = MAXT_ERROR_MEM;
}
}
// Set the event handler
if (rc == MAXT_SUCCESS)
rc = mxfAsyncEventHandlerInit(server, asyncEventHandler, rxRecBuffer, out asyncEvent);
// Allocate RX sampling buffer
if (rc == MAXT_SUCCESS)
rc = mxfRxSamplingBufferAlloc(rxChannel[0], BUFFER_SIZE, out rxBuffer, IntPtr.Zero);
// Set the RX async event conditions
if (rc == MAXT_SUCCESS)
{
asyncEventInfo[0].condID = MXF_ASYNCEVENT_COND_RX_MSG;
asyncEventInfo[0].condition.rxMsg.channel = rxChannel[0];
asyncEventInfo[1].condID = MXF_ASYNCEVENT_COND_RX_ERROR;
asyncEventInfo[1].condition.rxErr.channel = rxChannel[0];
rc = mxfAsyncEventConditionsSet(asyncEvent, VMXF_ENABLE, 2, asyncEventInfo);
}
// Monitor a specific label/sdi
if (rc == MAXT_SUCCESS)
{
msgid[0].label = LABEL;
msgid[0].sdi = SDI;
rc = mxfA429AsyncEventRxMsgSelectSet(asyncEvent, rxChannel[0], MXF_MSG_SELECT_ADD, 1, msgid);
}
// Start sampling
if (rc == MAXT_SUCCESS)
rc = mxfRxSamplingStart(rxBuffer);
if (rc == MAXT_SUCCESS)
Console.Write("Sampling started\n\r");
// Allocate TX Periodic Update buffer
if (rc == MAXT_SUCCESS)
rc = mxfTxPeriodicUpdateMsgBufferAlloc(txChannel[0], LABEL, BUFFER_SIZE, out txBuffer[0], IntPtr.Zero);
if (rc == MAXT_SUCCESS)
rc = mxfTxPeriodicUpdateMsgBufferAlloc(txChannel[0], LABEL + 1, BUFFER_SIZE, out txBuffer[1], IntPtr.Zero);
// Set the Periodic Scheduler
if (rc == MAXT_SUCCESS)
TX429PeriodicScheduling(txChannel[0], txBuffer, hostBuffer);
// Stop sampling
if (rc == MAXT_SUCCESS)
rc = mxfRxSamplingStop(rxBuffer);
// Disable conditions
if (rc == MAXT_SUCCESS)
rc = mxfAsyncEventConditionsSet(asyncEvent, VMXF_DISABLE, 2, asyncEventInfo);
// Terminate async event handler
if (rc == MAXT_SUCCESS)
// 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");
}
//Frees all buffers
if (rxBuffer > 0)
for (indexBuffer = 0; indexBuffer < 2; indexBuffer++)
{
if (txBuffer[indexBuffer] > 0)
mxfTxPeriodicUpdateMsgBufferFree(txBuffer[indexBuffer]);
}
// Terminate
if (hostBuffer != IntPtr.Zero)
Marshal.FreeHGlobal(hostBuffer);
if (rxRecBuffer != IntPtr.Zero)
Marshal.FreeHGlobal(rxRecBuffer);
Console.Write("\nPress enter to terminate\n");
Console.ReadKey();
return;
}
//****************************************************************************************************************
// RX asynchronous event Handler
//****************************************************************************************************************
private static UInt32 AsyncEventHandler(UInt64 asyncEvent, IntPtr param)
{
UInt64 channel;
UInt64 pendingCount;
UInt64 label, sdi, status;
UInt64 i;
UInt32 rc = MAXT_SUCCESS;
UInt64 dev, mod, port;
UInt64 sampBuffer;
IntPtr recPtr = param;
// Build the list of pending events to process
rc = mxfAsyncEventPendingGet(asyncEvent, 64, out pendingCount, pendingList);
for (i = 0; rc == MAXT_SUCCESS && i < pendingCount; i++)
{
switch (pendingList[i].condID)
{
// An event was generated when the data on the specific (label/sdi) was received.
case MXF_ASYNCEVENT_COND_RX_MSG:
{
channel = pendingList[i].condition.rxMsg.channel;
label = pendingList[i].condition.rxMsg.msg.a429.label;
sdi = pendingList[i].condition.rxMsg.msg.a429.sdi;
// Get latest value
rc = mxfRxSamplingBufferGet(channel, out sampBuffer);
if (rc == MAXT_SUCCESS)
rc = mxfA429RxSamplingSingleRead(sampBuffer, MXF_RXSAMPLING_FLAG_DEFAULT, label, sdi, recPtr);
if (rc == MAXT_SUCCESS)
{
rec = (MXF_A429_SAMPREC)Marshal.PtrToStructure(recPtr, typeof(MXF_A429_SAMPREC));
Console.Write("Msg {0:00} received with label={1} sdi={2} (0x{3:x8})\n", RXmsgTotal++, label, sdi, rec.data);
}
else
Console.Write("Error getting latest value rc = 0x%08x\n", rc);
break;
}
case MXF_ASYNCEVENT_COND_RX_ERROR:
channel = pendingList[i].condition.rxErr.channel;
status = pendingList[i].condition.rxErr.status;
mxfChannelLocationGet(channel, out dev, out mod, out port);
Console.Write("Status 0x{0:x8} received on channel {1}.{2}.{3}\n", status, dev, mod, port);
break;
default:
Console.Write("Unknown condID 0x{0:x})", pendingList[i].condID);
break;
}
}
return rc;
}
/***************************************************************************************************************/
// TX429PeriodicScheduling
/***************************************************************************************************************/
private static UInt32 TX429PeriodicScheduling(UInt64 txChannel, UInt64[] txBuffer, IntPtr recPtr)
{
var rec429 = new MXF_A429_DATAREC();
UInt64 schedule;
UInt64 msg = 0;
UInt64 label, sdi, data, ssm, parity;
UInt32 rc;
// Set the A429 records and create the schedule
// Create the periodic scheduler
rc = mxfTxPeriodicScheduleNew(txChannel, out schedule);
// Set scheduling values: Rate=100 ms (.1sec), Phase=0 us
if (rc == MAXT_SUCCESS)
rc = mxfTxPeriodicScheduleMsgAdd(schedule, 100000, 0, out msg);
// Define the number of buffer for the list and link to it
if (rc == MAXT_SUCCESS)
rc = mxfTxPeriodicScheduleBufferListAdd(msg, 2, 0, txBuffer);
// Set record for the buffer: ARINC 429 LABEL=05, SDI=0
if (rc == MAXT_SUCCESS)
{
rec429.timeTag = 0;
rec429.control = 0;
rec429.repeatCount = 1;
rec429.reserved = 0;
label = LABEL;
sdi = SDI;
data = 0x7fe;
parity = VMXF_A429_PARITY_ODD;
ssm = 1;
rc = mxfA429ArwCompose(label, sdi, data, ssm, parity, out rec429.data);
Marshal.StructureToPtr(rec429, recPtr, false);
if (rc == MAXT_SUCCESS)
rc = mxfA429TxPeriodicUpdateMsgWrite(txBuffer[0], 1, recPtr);
}
// Set a record that will be ignored later on by the event handler
if (rc == MAXT_SUCCESS)
{
rec429.timeTag = 0;
rec429.control = 0;
rec429.repeatCount = 1;
rec429.reserved = 0;
label = LABEL + 1;
sdi = SDI;
data = 0x12;
parity = VMXF_A429_PARITY_ODD;
ssm = 1;
rc = mxfA429ArwCompose(label, sdi, data, ssm, parity, out rec429.data);
Marshal.StructureToPtr(rec429, recPtr, true);
if (rc == MAXT_SUCCESS)
rc = mxfA429TxPeriodicUpdateMsgWrite(txBuffer[1], 1, recPtr);
}
// Run the scheduler, update records
if (rc == MAXT_SUCCESS)
{
Console.Write("Running periodic transmission, please wait...\n\r");
// Run the schedule now
rc = mxfTxPeriodicScheduleRun(schedule);
}
// Wait 2 seconds
if (rc == MAXT_SUCCESS)
{
mxfSleep(2000);
rc = mxfTxPeriodicScheduleFree(schedule);
}
if (rc == MAXT_SUCCESS)
Console.Write("\n\rTransmission stopped\n\r");
return rc;
}
}
}
Updated 10/23/2023