MX Foundation 4
write_read_async.c
/*****************************************************************************
//
// File:
// write_read_async.c
//
// 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 the basic usage of the functions mxfRxAcqReadAsync
// and mxfTxAperiodicWriteAsync.
//
// Hardware requirements:
// - FlexMulti
//
*****************************************************************************/
#include "example.h"
#define MAX_TX_RECORDS_TO_TRANSMIT 8
#define MAX_TX_SUBFRAMES_TO_TRANSMIT 4 //minimum 4 to have at least one full frame.
//#define LOCAL
//#define LOOPBACK
uint32 initHandler(HMXF_SERVER server, uint64 deviceIndex, uint64 moduleIndex, uint64 channelIndex, uint64 attrib, uint64* value);
void writeCompletion(HMXF_BUFFER bufferHandle, uint32 result, void* context, uint64* output);
void readCompletion(HMXF_BUFFER bufferHandle, uint32 result, void* context, uint64* output);
void DisplayDataArrayHDLC(uint64 recNum, MXF_HDLC_DATAREC* rec);
void DisplayDataArrayA717(uint64 recNum, MXF_A717_DATAREC* rec);
typedef struct
{
HMXF_SERVER server;
MXF_HDLC_DATAREC* HostBufferHDLC;
MXF_A717_DATAREC* HostBufferA717;
uint64 protocol; //Protocol number meaning : 0 means HDLC, 1 means ARINC 717
uint32 processed;
uint32 rc;
}
ASYNC_CALLBACK_INFO;
int main(void)
{
uint32 rc;
HMXF_SERVER server = 0;
HMXF_CHANNEL rxChannelHDLC = 0;
HMXF_CHANNEL rxChannelA717 = 0;
HMXF_CHANNEL txChannelHDLC = 0;
HMXF_CHANNEL txChannelA717 = 0;
HMXF_BUFFER rxBufferHDLC = 0;
HMXF_BUFFER txBufferHDLC = 0;
HMXF_BUFFER rxBufferA717 = 0;
HMXF_BUFFER txBufferA717 = 0;
MXF_HDLC_DATAREC* recHDLC = 0;
MXF_A717_DATAREC* recA717 = 0;
size_t txBufferSize = 0;
size_t rxBufferSize = 0;
MXF_HDLC_DATAREC* rxHostBufferHDLC = 0;
MXF_HDLC_DATAREC* txHostBufferHDLC = 0;
MXF_A717_DATAREC* rxHostBufferA717 = 0;
MXF_A717_DATAREC* txHostBufferA717 = 0;
uint64 rxAcqStatus = 0;
uint64 msgCount = 0;
uint64 byteCount = 0;
uint64 data, word, subframeSize;
uint64 freebytes;
ASYNC_CALLBACK_INFO asyncInfoHDLC, asyncInfoA717;
// Connects to services and initialize environment
#ifdef LOCAL
rc = mxfServerConnect("0.0.0.0", "", "", FALSE, &server);
#else
rc = mxfServerConnect("192.168.0.1", "admin", "admin", FALSE, &server);
#endif
//Configuration of the Multi port in HDLC
if (!rc)
// Initializes MX Foundation library
if (!rc)
{
printf("Starting ...\n");
rc = mxfSystemInit(server);
}
// Gets handle of first HDLC RX channel
if (!rc)
rc = mxfChannelGet(server, MXF_CLASS_HDLC, MXF_SCLASS_RX_CHANNEL, MXF_MODULE_MULTI_EH, 0, &rxChannelHDLC);
// Gets handle of first HDLC TX channel
if (!rc)
rc = mxfChannelGet(server, MXF_CLASS_HDLC, MXF_SCLASS_TX_CHANNEL, MXF_MODULE_MULTI_EH, 0, &txChannelHDLC);
// Gets handle of first ARINC 717 RX channel
if (!rc)
rc = mxfChannelGet(server, MXF_CLASS_A717, MXF_SCLASS_RX_CHANNEL, MXF_MODULE_MULTI_EH, 0, &rxChannelA717);
// Gets handle of first ARINC 717 TX channel
if (!rc)
rc = mxfChannelGet(server, MXF_CLASS_A717, MXF_SCLASS_TX_CHANNEL, MXF_MODULE_MULTI_EH, 0, &txChannelA717);
// Sets frame size and internal clock frequency
if (!rc)
rc = mxfAttributeUint64Set(rxChannelHDLC, KMXF_HDLC_FRAME_SIZE_ENABLE, VMXF_ENABLE);
if (!rc)
rc = mxfAttributeUint64Set(txChannelHDLC, KMXF_HDLC_FRAME_SIZE_ENABLE, VMXF_ENABLE);
if (!rc)
rc = mxfAttributeUint64Set(txChannelHDLC, KMXF_HDLC_CLOCK_SOURCE, VMXF_HDLC_CLOCK_SOURCE_INTERNAL);
if (!rc)
rc = mxfAttributeUint64Set(txChannelHDLC, KMXF_HDLC_INTERNAL_CLOCK_FREQ, 100000);
// Sets RX & TX channels subframe size to 128 words
subframeSize = 128;
if (!rc)
rc = mxfAttributeUint64Set(rxChannelA717, KMXF_A717_SUBFRAME_SIZE, subframeSize);
if (!rc)
rc = mxfAttributeUint64Set(txChannelA717, KMXF_A717_SUBFRAME_SIZE, subframeSize);
// Sets RX & TX channels bit encoding to harvard
if (!rc)
rc = mxfAttributeUint64Set(rxChannelA717, KMXF_A717_BIT_ENCODING, VMXF_A717_BIT_ENCODING_HARVARDBIPHASE);
if (!rc)
rc = mxfAttributeUint64Set(txChannelA717, KMXF_A717_BIT_ENCODING, VMXF_A717_BIT_ENCODING_HARVARDBIPHASE);
// Sets RX & TX channels electrical selection to default
if (!rc)
rc = mxfAttributeUint64Set(rxChannelA717, KMXF_A717_ELECTRICAL_SELECTION, VMXF_A717_ELECTRICAL_SELECT_DEFAULT);
if (!rc)
rc = mxfAttributeUint64Set(txChannelA717, KMXF_A717_ELECTRICAL_SELECTION, VMXF_A717_ELECTRICAL_SELECT_DEFAULT);
// Enables loopback
#ifdef LOOPBACK
if (!rc)
rc = mxfAttributeUint64Set(rxChannelHDLC, KMXF_HDLC_TX_RX_TEST_LB, VMXF_ENABLE);
if (!rc)
rc = mxfAttributeUint64Set(rxChannelA717, KMXF_A717_TX_RX_TEST_LB, VMXF_ENABLE);
#endif
// Allocates 4 KB buffer for tx HDLC data
if (!rc)
{
txBufferSize = 4 * 1024;
// Allocates TX Aperiodic static buffer for HIGH priority queue
rc = mxfTxAperiodicBufferAlloc(txChannelHDLC, MXF_TXAPERIODIC_PRIORITY_HIGH, txBufferSize, &txBufferHDLC, NULL);
// Host buffer allocation
if (!rc)
{
txHostBufferHDLC = (MXF_HDLC_DATAREC*)calloc(1, txBufferSize);
if (!txHostBufferHDLC)
rc = MAXT_ERROR_MEM;
}
}
// Allocates 4 KB buffer for RX HDLC data
if (!rc)
{
rxBufferSize = 4 * 1024;
// Allocates RX acquisition static buffer
rc = mxfRxAcqBufferAlloc(rxChannelHDLC, rxBufferSize, &rxBufferHDLC, NULL);
// Host buffer allocation
if (!rc)
{
rxHostBufferHDLC = (MXF_HDLC_DATAREC*)calloc(1, rxBufferSize);
if (!rxHostBufferHDLC)
rc = MAXT_ERROR_MEM;
}
}
asyncInfoHDLC.HostBufferHDLC = rxHostBufferHDLC;
asyncInfoHDLC.protocol = 0;
asyncInfoHDLC.processed = 0;
asyncInfoHDLC.rc = 0;
// Allocates buffer for tx ARINC 717 data
if (!rc)
{
txBufferSize = MAX_TX_SUBFRAMES_TO_TRANSMIT * sizeof(MXF_A717_DATAREC);
// Allocates TX Aperiodic static buffer for HIGH priority queue
rc = mxfTxAperiodicBufferAlloc(txChannelA717, MXF_TXAPERIODIC_PRIORITY_HIGH, txBufferSize, &txBufferA717, NULL);
// Host buffer allocation
if (!rc)
{
txHostBufferA717 = (MXF_A717_DATAREC*)calloc(1, txBufferSize);
if (!txHostBufferA717)
rc = MAXT_ERROR_MEM;
}
}
// Allocates buffer for rx ARINC 717 data
if (!rc)
{
rxBufferSize = MAX_TX_SUBFRAMES_TO_TRANSMIT * sizeof(MXF_A717_DATAREC);
// Allocates RX acquisition static buffer
rc = mxfRxAcqBufferAlloc(rxChannelA717, rxBufferSize, &rxBufferA717, NULL);
// Host buffer allocation
if (!rc)
{
rxHostBufferA717 = (MXF_A717_DATAREC*)calloc(1, rxBufferSize);
if (!rxHostBufferA717)
rc = MAXT_ERROR_MEM;
}
}
asyncInfoA717.HostBufferA717 = rxHostBufferA717;
asyncInfoA717.protocol = 1;
asyncInfoA717.processed = 0;
asyncInfoA717.rc = 0;
// Sets timebase to RTC nsec
if (!rc)
rc = mxfSystemTimeBaseSet(server, MXF_TIMEBASE_DEVICE_NSEC);
// Starts acquisition
if (!rc)
rc = mxfRxAcqStart(rxBufferHDLC, MXF_RXACQ_FLAG_DEFAULT, 0, 0);
if (!rc)
rc = mxfRxAcqStart(rxBufferA717, MXF_RXACQ_FLAG_DEFAULT, 0, 0);
if (!rc)
{
recHDLC = txHostBufferHDLC;
//Prepares an HDLC record to send
for (data = 0; data<MAX_TX_RECORDS_TO_TRANSMIT; data++)
{
recHDLC->timeTag = 0;
recHDLC->control = 0;
recHDLC->repeatCount = 1;
recHDLC->dataSize = 8;
recHDLC->reserved = 0;
for (word = 0; word < recHDLC->dataSize / 2; word++)
{
recHDLC->data[word] = (uint16)(0x0101 * data);
}
rc = mxfHDLCNextDataRecordPtrGet(recHDLC, &recHDLC);
}
}
if (!rc)
rc = mxfTxAperiodicWriteAsync(txBufferHDLC, MXF_TXAPERIODIC_FLAG_DEFAULT, 0, MAX_TX_RECORDS_TO_TRANSMIT, txHostBufferHDLC, writeCompletion, &asyncInfoHDLC);
if (!rc)
{
// Prepares an ARINC 717 string array
recA717 = txHostBufferA717;
for (data = 0; data<MAX_TX_SUBFRAMES_TO_TRANSMIT; data++)
{
recA717->timeTag = 0;
recA717->control = 0;
recA717->dataSize = 2 * (uint32)subframeSize; // 16 bits per word in subframe
recA717->repeatCount = 1;
recA717->reserved = 0;
for (word = 0; word < subframeSize; word++)
{
if (word == 0)
{
//1st word of each subframe has to be a sync word
// sync words are:
// - 0x247 for subframe #0
// - 0x5B8 for subframe #1
// - 0xA47 for subframe #2
// - 0xDB8 for subframe #3
switch (data % 4)
{
case 0:
recA717->data[word] = 0x247;
break;
case 1:
recA717->data[word] = 0x5B8;
break;
case 2:
recA717->data[word] = 0xA47;
break;
case 3:
recA717->data[word] = 0xDB8;
break;
default:
break;
}
}
else
recA717->data[word] = (uint16)(0x11 * word);
}
rc = mxfA717NextDataRecordPtrGet(recA717, &recA717);
}
}
if (!rc)
rc = mxfTxAperiodicWriteAsync(txBufferA717, MXF_TXAPERIODIC_FLAG_DEFAULT, 0, MAX_TX_SUBFRAMES_TO_TRANSMIT, txHostBufferA717, writeCompletion, &asyncInfoA717);
// Do something while the tx data are sent to the device
// Simply wait until all HDLC and A717 records are received on the interface
if (!rc)
{
do
{
} while (!asyncInfoHDLC.processed || !asyncInfoA717.processed);
if (asyncInfoHDLC.rc)
rc = asyncInfoHDLC.rc;
else if (asyncInfoA717.rc)
rc = asyncInfoA717.rc;
if (!rc)
{
uint64 msgCountA717 = 0;
do
{
mxfSleep(100);
rc = mxfRxAcqBufferStatusGet(rxBufferHDLC, &rxAcqStatus, &msgCount, &byteCount, &freebytes);
if (!rc)
rc = mxfRxAcqBufferStatusGet(rxBufferA717, &rxAcqStatus, &msgCountA717, &byteCount, &freebytes);
} while (!rc && ((msgCount != MAX_TX_RECORDS_TO_TRANSMIT) || (msgCountA717 != MAX_TX_SUBFRAMES_TO_TRANSMIT)));
}
}
if (!rc)
{
printf("Receiving ...\n\n");
// Reads rx buffer
asyncInfoHDLC.processed = 0;
asyncInfoA717.processed = 0;
rc = mxfRxAcqReadAsync(rxBufferHDLC, 0, rxBufferSize, asyncInfoHDLC.HostBufferHDLC, readCompletion, &asyncInfoHDLC);
if (!rc)
rc = mxfRxAcqReadAsync(rxBufferA717, 0, rxBufferSize, asyncInfoA717.HostBufferA717, readCompletion, &asyncInfoA717);
}
// Do something while the rx data are received from the device
// Simply wait until all HDLC and A717 records are read from the interface
if (!rc)
{
do
{
} while (!asyncInfoHDLC.processed || !asyncInfoA717.processed);
}
// Stops acquisition
if (!rc)
rc = mxfRxAcqStop(rxBufferHDLC);
if (!rc)
rc = mxfRxAcqStop(rxBufferA717);
// Frees device and host buffers
mxfTxAperiodicBufferFree(txBufferHDLC);
mxfTxAperiodicBufferFree(txBufferA717);
mxfRxAcqBufferFree(rxBufferHDLC);
mxfRxAcqBufferFree(rxBufferA717);
if (txHostBufferHDLC)
free(txHostBufferHDLC);
if (txHostBufferA717)
free(txHostBufferA717);
if (rxHostBufferHDLC)
free(rxHostBufferHDLC);
if (rxHostBufferA717)
free(rxHostBufferA717);
if (rc)
{
char errorString[200];
if (mxfSystemErrorStringGet(server, rc, sizeof(errorString), errorString))
sprintf(errorString, "ERROR # 0x%X", rc);
printf("%s\n\r", errorString);
}
printf("Terminating ...\n");
// Unloads MX Foundation library
// Disconnects from MX Foundation library
printf("\nPress a key to terminate\n");
getchar();
return rc;
}
uint32 initHandler(HMXF_SERVER server, uint64 deviceIndex, uint64 moduleIndex, uint64 channelIndex, uint64 attrib, uint64* value)
{
MXF_DEVICE_INFO info = { 0 };
HMXF_DEVICE device = 0;
uint32 rc = 0;
uint64 i = 0;
int64 modulePosition = 999;
//Get the 1st module multi position on the device
rc = mxfSystemDeviceGet(server, 0, &device);
if(!rc)
rc = mxfDeviceInfoGet(device, &info);
for (i = 0; i < info.moduleCount && !rc; i++)
{
if (info.modules[i].type == MXF_MODULE_MULTI_EH)
{
modulePosition = info.modules[i].position;
break;
}
}
// Sets IPM-MULTI-EH first TX and RX channel to HDLC
if (attrib == KMXF_CHANNEL_CLASS && !rc)
{
if ((deviceIndex == 0) && (moduleIndex == (uint64)modulePosition) && ((channelIndex == 0) || (channelIndex == 8)))
{
*value = MXF_CLASS_HDLC;
return TRUE;
}
//Sets the TX and RX channel clock
else if ((deviceIndex == 0) && (moduleIndex == (uint64)modulePosition) && ((channelIndex == 4) || (channelIndex == 12)))
{
*value = MXF_CLASS_CLOCK;
return TRUE;
}
//Sets IMP-MULTI-EH second TX and RX channel to ARINC 717
if ((deviceIndex == 0) && (moduleIndex == (uint64)modulePosition) && ((channelIndex == 1) || (channelIndex == 9)))
{
*value = MXF_CLASS_A717;
return TRUE;
}
}
return FALSE;
}
void writeCompletion(HMXF_BUFFER bufferHandle, uint32 result, void* context, uint64* output)
{
ASYNC_CALLBACK_INFO* info = (ASYNC_CALLBACK_INFO*)(context);
bufferHandle = bufferHandle;
if (!result)
{
if (info->protocol == 0)
{
printf("%llu HDLC records have been successfully transmitted.\n\n", output[0]);
}
else
{
printf("%llu ARINC 717 records have been successfully transmitted.\n\n", output[0]);
}
}
else
{
char errorString[200];
if (mxfSystemErrorStringGet(info->server, result, sizeof(errorString), errorString))
sprintf(errorString, "ERROR # 0x%X", result);
printf("%s\n\r", errorString);
}
info->rc = result;
info->processed = 1;
}
void readCompletion(HMXF_BUFFER bufferHandle, uint32 result, void* context, uint64* output)
{
ASYNC_CALLBACK_INFO* info = (ASYNC_CALLBACK_INFO*)(context);
bufferHandle = bufferHandle;
if (!result)
{
if (info->protocol == 0)
{
printf("HDLC string received count = %llu \n", output[1]);
DisplayDataArrayHDLC(output[1], info->HostBufferHDLC);
printf("\n");
}
else
{
printf("ARINC 717 string received count = %llu \n", output[1]);
DisplayDataArrayA717(output[1], info->HostBufferA717);
printf("\n");
}
}
else
{
char errorString[200];
if (mxfSystemErrorStringGet(info->server, result, sizeof(errorString), errorString))
sprintf(errorString, "ERROR # 0x%X", result);
printf("%s\n\r", errorString);
}
info->rc = result;
info->processed = 1;
}
void DisplayDataArrayHDLC(uint64 recNum, MXF_HDLC_DATAREC* rec)
{
uint64 iRec,
iData;
MXF_HDLC_DATAREC *p = rec;
printf("\n");
for (iRec = 0; iRec < recNum; iRec++)
{
printf("%03llu %010llu 0x%08x %02u ", iRec, p->timeTag, p->control, p->dataSize);
for (iData = 0; iData < p->dataSize / 2; iData++)
{
printf("%04x ", p->data[iData]);
if (!((iData + 1) % 8) && (iData + 1 < p->dataSize / 2))
printf("\n ");
}
printf("\n");
}
}
void DisplayDataArrayA717(uint64 recNum, MXF_A717_DATAREC* rec)
{
uint64 iRec,
iData;
MXF_A717_DATAREC *p = rec;
printf("\n");
for (iRec = 0; iRec < recNum; iRec++)
{
printf("%03llu %010llu 0x%08x %02u ", iRec, p->timeTag, p->control, p->dataSize);
for (iData = 0; iData < (p->dataSize) / 2; iData++)
{
printf("%03x", p->data[iData]);
if (!((iData + 1) % 16) && (iData + 1 < p->dataSize))
printf("\n ");
}
printf("\n");
}
}
Updated 10/23/2023