MX Foundation 4
discrete_event_handler.cs
/******************************************************************************
//
// File:
// discrete_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 example demonstrates how to read discrete input from event handler
// and to write to discrete output.
//
// Hardware requirements:
// - MAXT or MAXT 500 series carrier with IPM with discrete channel.
//
*******************************************************************************/
//#define LOOPBACK
#define LOCAL
using System;
using static MAXT.MXFoundation.mxf;
using System.Runtime.InteropServices;
using System.Text;
using System.IO;
namespace discrete_example
{
public struct EVENT_INFO
{
public UInt64 rxBufferSize;
public IntPtr rxHostBuffer;
}
class discrete_event_handler
{
static void Main(string[] args)
{
UInt32 rc;
UInt64 channelCount = 0;
UInt64 msgCount, pendingBytes, freeBytes;
UInt64 server;
var device = new UInt64[1];
var module = new UInt64[1];
var rx = new UInt64[1];
var tx = new UInt64[1];
UInt64 bufferRx = 0;
UInt64 bufferTx = 0;
UInt64 asyncEvent = 0;
MXF_ASYNCEVENT_HANDLER eventHandler = EventHandler;
var condition = new MXF_ASYNCEVENT_CONDITION[2];
EVENT_INFO eventInfo = new EVENT_INFO();
StringBuilder errorString = new StringBuilder();
UInt64 moduleType = 0;
UInt32 edge = 0x0010;
// Connect to services and initialize environment
#if LOCAL
rc = mxfServerConnect("0.0.0.0", "", "", 0, out server);
#else
rc = mxfServerConnect("192.168.0.1", "admin", "admin", 0, out server);
#endif
// Initialize MX Foundation library
if (rc == MAXT_SUCCESS)
{
Console.Write("Starting ...\n");
rc = mxfSystemInit(server);
};
// Get handle of discrete input channel
if (rc == MAXT_SUCCESS)
rc = mxfChannelAllGet(server, MXF_CLASS_DISCRETE, MXF_SCLASS_RX_CHANNEL, MXF_MODULE_ALL, 1, out channelCount, rx);
// Get handle of discrete output channel
if ((rc == MAXT_SUCCESS) && (channelCount > 0))
rc = mxfChannelAllGet(server, MXF_CLASS_DISCRETE, MXF_SCLASS_TX_CHANNEL, MXF_MODULE_ALL, 1, out channelCount, tx);
if ((rc == MAXT_SUCCESS) && (channelCount == 0))
rc = MAXT_ERROR_NOT_FOUND;
if (rc == MAXT_SUCCESS)
rc = mxfChannelInfoGet(rx, out device, out module);
// configure discrete input
if (rc == MAXT_SUCCESS)
rc = mxfAttributeUint64Set(rx[0], KMXF_DISCRETE_RX_EDGE_FALLING, 0xff);
if (rc == MAXT_SUCCESS)
rc = mxfAttributeUint64Set(rx[0], KMXF_DISCRETE_RX_EDGE_RISING, 0xff);
if (rc == MAXT_SUCCESS)
rc = mxfAttributeUint64Get(module[0], KMXF_MODULE_TYPE, out moduleType);
if (rc == MAXT_SUCCESS)
{
if(moduleType == MXF_MODULE_DIOFIFO_EH)
{
edge = 0xffff;
rc = mxfAttributeUint64Set(rx[0], KMXF_DISCRETE_RX_PULSE_WIDTH_FILTER, 100);
#if LOOPBACK
if (rc == MAXT_SUCCESS)
rc = mxfAttributeUint64Set(rx[0], KMXF_DISCRETE_TX_RX_TEST_LB, VMXF_ENABLE);
#endif
}
else
{
rc = mxfAttributeUint64Set(rx[0], KMXF_DISCRETE_DIRECTION, 0x00ff);
}
}
// Allocate 10KB buffer for rx data
if (rc == MAXT_SUCCESS)
{
eventInfo.rxBufferSize = 10 * 1024;
// Device allocation
rc = mxfRxAcqBufferAlloc(rx[0], eventInfo.rxBufferSize, out bufferRx, IntPtr.Zero);
// Host allocation
if (rc == MAXT_SUCCESS)
{
try
{
eventInfo.rxHostBuffer = Marshal.AllocHGlobal((int)eventInfo.rxBufferSize);
}
catch (OutOfMemoryException)
{
rc = MAXT_ERROR_MEM;
}
}
}
// Set timebase to RTC nsec
if (rc == MAXT_SUCCESS)
rc = mxfSystemTimeBaseSet(server, MXF_TIMEBASE_DEVICE_NSEC);
// Configure acquisition asynchronous event condition
if (rc == MAXT_SUCCESS)
{
IntPtr eventInfoPtr = IntPtr.Zero;
try
{
eventInfoPtr = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(EVENT_INFO)));
}
catch (OutOfMemoryException)
{
rc = MAXT_ERROR_MEM;
}
Marshal.StructureToPtr(eventInfo, eventInfoPtr, false);
rc = mxfAsyncEventHandlerInit(server, eventHandler, eventInfoPtr, out asyncEvent);
}
if (rc == MAXT_SUCCESS)
{
condition[0].condID = MXF_ASYNCEVENT_COND_RXACQ_BUFFER_THRESHOLD;
condition[0].condition.txAperiodicBufferThreshold.almostEmpty = 5;
condition[0].condition.txAperiodicBufferThreshold.almostFull = 10;
condition[0].condition.txAperiodicBufferThreshold.buffer = bufferRx;
rc = mxfAsyncEventConditionsSet(asyncEvent, VMXF_ENABLE, 1, condition);
}
// Start acquisition
if (rc == MAXT_SUCCESS)
rc = mxfRxAcqStart(bufferRx, MXF_RXACQ_FLAG_DEFAULT, 0, 0);
if (rc == MAXT_SUCCESS)
Console.Write("Acquisition started\n");
if (rc == MAXT_SUCCESS)
{
var dioRec = new MXF_DISCRETE_DATAREC[2];
UInt32 pulseCount;
UInt64 timer = 0;
// Allocate 1KB buffer for discrete tx data
rc = mxfTxAperiodicBufferAlloc(tx[0], MXF_TXAPERIODIC_PRIORITY_NORMAL, 1024, out bufferTx, IntPtr.Zero);
if (rc == MAXT_SUCCESS)
{
IntPtr dioRecBuffPtr = IntPtr.Zero;
//Allocate memory for the record to send
try
{
dioRecBuffPtr = Marshal.AllocHGlobal(dioRec.Length * Marshal.SizeOf(typeof(MXF_DISCRETE_DATAREC)));
}
catch (OutOfMemoryException)
{
rc = MAXT_ERROR_MEM;
}
if (rc == MAXT_SUCCESS)
rc = mxfDeviceTimerGet(device[0], out timer);
// Fill the queue with; (2*100ms requests) => 10 records/secs => 300 records for the next 30 secs (max)
for (pulseCount = 0; rc == MAXT_SUCCESS && pulseCount < 149 - 1; pulseCount++)
{
IntPtr recPtr = dioRecBuffPtr;
timer += (UInt64)100 * 1000 * 1000; // 100 msec
dioRec[0].repeatCount = 1;
dioRec[0].control = 0;
dioRec[0].timeTag = timer;
dioRec[0].edge = edge;
dioRec[0].data = 0x0010;
timer += 100 * 1000 * 1000; // +100 msec
dioRec[1].repeatCount = 1;
dioRec[1].control = 0;
dioRec[1].timeTag = timer;
dioRec[1].edge = edge;
dioRec[1].data = 0x0000;
Marshal.StructureToPtr(dioRec[0], recPtr, false);
if (rc == MAXT_SUCCESS)
rc = mxfDiscreteNextDataRecordPtrGet(recPtr, out recPtr);
Marshal.StructureToPtr(dioRec[1], recPtr, false);
if (rc == MAXT_SUCCESS)
rc = mxfDiscreteTxAperiodicWrite(bufferTx, MXF_TXAPERIODIC_FLAG_USE_RECORD_ABSOLUTE_TIME, 0, 2, dioRecBuffPtr);
if (rc != MAXT_SUCCESS)
Console.Write("mxfDiscreteTxAperiodicWrite() error; rc=0x{0:x8}, pulse count={1}\n", rc, pulseCount);
do
{
rc = mxfTxAperiodicBufferStatusGet(bufferTx, out msgCount, out pendingBytes, out freeBytes);
} while (msgCount != 0);
}
Marshal.FreeHGlobal(dioRecBuffPtr);
}
}
// Wait 3 seconds
if (rc == MAXT_SUCCESS)
mxfSleep(3000);
// Stop acquisition
if (rc == MAXT_SUCCESS)
rc = mxfRxAcqStop(bufferRx);
// Disable asynchronous event condition
if (rc == MAXT_SUCCESS)
rc = mxfAsyncEventConditionsSet(asyncEvent, VMXF_DISABLE, 1, condition);
// Clear the queue and terminate
if (rc == MAXT_SUCCESS)
rc = mxfAsyncEventPendingClear(asyncEvent);
if (rc == MAXT_SUCCESS)
// Clear what not sent yet (do not wait that queue is empty).
if (rc == MAXT_SUCCESS)
mxfTxAperiodicClear(bufferTx, MXF_TXAPERIODIC_CLEAR_OPT_HWFIFO);
// Read last messages
if (rc == MAXT_SUCCESS)
rc = ReadDiscreteInput(bufferRx, eventInfo);
Console.Write("\n");
// free buffers
if (eventInfo.rxHostBuffer != IntPtr.Zero)
Marshal.FreeHGlobal(eventInfo.rxHostBuffer);
if (rc != MAXT_SUCCESS)
{
if (mxfSystemErrorStringGet(server, rc, (UInt32)errorString.Length, errorString) > 0)
Console.Write(" {0} ERROR # 0x{1:X8}", errorString, rc);
Console.Write("{0}\n\r", errorString);
}
// Free all buffers and terminate
if (bufferRx > 0)
{
rc = mxfRxAcqBufferFree(bufferRx);
if (rc != MAXT_SUCCESS)
Console.Write("Free buffer failed !\n\r");
}
if (bufferTx > 0)
{
rc = mxfTxAperiodicBufferFree(bufferTx);
if (rc != MAXT_SUCCESS)
Console.Write("Free buffer failed !\n\r");
}
// Unload MX Foundation library
Console.Write("\nPress a key to terminate\n");
Console.ReadKey();
return;
}
private static UInt32 EventHandler(UInt64 asyncEvent, IntPtr param)
{
UInt32 rc;
UInt64 count;
var pendingInfo = new MXF_ASYNCEVENT_PENDING_INFO[1];
EVENT_INFO eventInfo = new EVENT_INFO();
eventInfo = (EVENT_INFO)Marshal.PtrToStructure(param, typeof(EVENT_INFO));
// get asynchronous event information
rc = mxfAsyncEventPendingGet(asyncEvent, 1, out count, pendingInfo);
if (rc == MAXT_SUCCESS && count > 0)
{
if (pendingInfo[0].condID == MXF_ASYNCEVENT_COND_RXACQ_BUFFER_THRESHOLD)
{
// Read discrete input
rc = ReadDiscreteInput(pendingInfo[0].condition.rxAcqBufferThreshold.buffer, eventInfo);
Console.Write("+");
}
}
if (rc != MAXT_SUCCESS)
Console.Write("event handler rc=0x{0:x8}\n", rc);
return rc;
}
private static UInt32 ReadDiscreteInput(UInt64 bufferRx, EVENT_INFO eventInfo)
{
UInt32 rc;
UInt64 status, msgCount, byteCount, msg;
rc = mxfDiscreteRxAcqRead(bufferRx, 0, eventInfo.rxBufferSize, out status, out msgCount, out byteCount, eventInfo.rxHostBuffer);
using (StreamWriter file = new StreamWriter("discrete_log.txt", true))
{
IntPtr rxRecPtr = eventInfo.rxHostBuffer;
for (msg = 0; msg < msgCount && rc == MAXT_SUCCESS; msg++)
{
rxRec = (MXF_DISCRETE_DATAREC)Marshal.PtrToStructure(rxRecPtr, typeof(MXF_DISCRETE_DATAREC));
file.WriteLine(String.Format("{0}: 0x{1:x4} 0x{2:x4}", rxRec.timeTag, rxRec.data, rxRec.edge));
file.WriteLine();
rc = mxfDiscreteNextDataRecordPtrGet(rxRecPtr, out rxRecPtr);
}
}
return rc;
}
}
}
Updated 10/23/2023