MX Foundation 4
mil1553_embedded_async_to_1553.c
/*****************************************************************************
//
// File:
// mil1553_embedded_async_to_1553.c
//
// Copyright (c) MAX Technologies Inc. 1988-2016, All Rights Reserved.
// CONFIDENTIAL AND PROPRIETARY INFORMATION WHICH IS THE
// PROPERTY OF MAX TECHNOLOGIES INC.
//
// This example demonstrates how to route ASYNC port data to MIL1553 BC to
// update data of a BC-RT command.
// The communication queues are used to communicate between host and embedded
// application parts. MIL1553 BM is returned through communication queue.
// Asynchronous event is used for async receiver threshold.
//
// This file is used to generate the two parts of the application.
// The function "testHostPart" is used by host application.
// The function "testEmbeddedPart" is used by embedded application.
// The embedded makefile must define "EMBEDDED_PART" to build embedded
// part function.
//
// Hardware requirements:
// - MAXT Flex1553-PCIe or FlexMulti with PCIe option
//
*****************************************************************************/
#include "example.h"
#define MAX_TX_RECORDS_TO_TRANSMIT 8
#define EX_USER_COMMAND_ID_START 0x80000001
#define EX_USER_COMMAND_ID_STOP 0x80000002
#define EX_USER_COMMAND_ID_READ 0x80000003
#define EX_USER_COMMAND_ID_TERMINATE 0x80000005
#define EX_USER_COMMAND_ACK 0xA5A5A5A5
#define RT_ADDRESS 1
#define RT_SUBADDRESS 2
//#define LOOPBACK
#define DWORD_SWAP(dword) ((dword & 0x0000ffff) << 16 | (dword & 0xffff0000) >> 16)
typedef struct
{
HMXF_SERVER server;
HMXF_DEVICE device;
HMXF_MODULE moduleAsync;
HMXF_MODULE module1553;
HMXF_CHANNEL rxChannel;
HMXF_CHANNEL txChannel;
HMXF_CHANNEL bcChannel;
HMXF_CHANNEL bmChannel;
HMXF_BUFFER commTxBuffer;
HMXF_BUFFER commRxBuffer;
}
TEST_INFO;
typedef struct
{
uint32 command;
uint32 paramNum;
uint32 param[32];
}
EX_COMMAND;
typedef struct
{
MXF_ASYNCEH_DATAREC* rxHostBuffer;
MXF_MIL1553_DATAREC* bcHostBuffer;
uint64 rxBufferSize;
HMXF_BUFFER bcBuffer;
}
EVENT_INFO;
uint32 initHandler(HMXF_SERVER server, uint64 deviceIndex, uint64 moduleIndex, uint64 channelIndex, uint64 attrib, uint64* value);
uint32 commandSend(HMXF_BUFFER txBuffer, HMXF_BUFFER rxBuffer, EX_COMMAND* cmd);
uint32 commandRead(HMXF_BUFFER rxBuffer, uint64* readCnt, EX_COMMAND* cmd);
uint32 testEmbeddedPart(TEST_INFO info);
uint32 testHostPart(TEST_INFO info);
uint32 eventHandler(HMXF_ASYNCEVENT asyncEvent, void* param);
int
main(void)
{
TEST_INFO info;
uint32 rc;
uint64 moduleCount=0;
uint64 channelCount=0;
#ifndef EMBEDDED_PART
char temp[10];
#endif
// Connect to MX Foundation library
rc = mxfServerConnect("0.0.0.0", "", "", FALSE, &info.server);
// Set initialisation handler
if(!rc)
rc = mxfSystemInitAttributeUint64CallbackHandler(info.server, &initHandler);
// Initialize MX Foundation library
if(!rc)
{
printf("Starting ...\n\r");
rc = mxfSystemInit(info.server);
}
// Get the device handle
if(!rc)
rc = mxfSystemDeviceGet(info.server, 0, &info.device);
// Get handle of first ASYNC-EH module
if(!rc)
rc = mxfDeviceModuleAllGet(info.device, MXF_MODULE_ASYNC_EH, 1, &moduleCount, &info.moduleAsync);
// Get handle of first ASYNC-EH RX channel
if(!rc && moduleCount)
rc = mxfModuleChannelAllGet(info.moduleAsync, MXF_CLASS_ASYNC_ENHANCED, MXF_SCLASS_RX_CHANNEL, 1, &channelCount, &info.rxChannel);
// Get handle of first ASYNC-EH TX channel
if(!rc && channelCount)
rc = mxfModuleChannelAllGet(info.moduleAsync, MXF_CLASS_ASYNC_ENHANCED, MXF_SCLASS_TX_CHANNEL, 1, &channelCount, &info.txChannel);
if(!rc && !channelCount)
rc = MAXT_ERROR_NOT_FOUND;
// Get handle of first 1553-EH module
if(!rc)
rc = mxfDeviceModuleAllGet(info.device, MXF_MODULE_MIL1553MRT_EH, 1, &moduleCount, &info.module1553);
// Get handle of first MIL1553 BC channel
if(!rc && moduleCount)
rc = mxfModuleChannelAllGet(info.module1553, MXF_CLASS_MIL1553, MXF_SCLASS_BC_CHANNEL, 1, &channelCount, &info.bcChannel);
// Get handle of first MIL1553 BM channel
if(!rc && channelCount)
rc = mxfModuleChannelAllGet(info.module1553, MXF_CLASS_MIL1553, MXF_SCLASS_BM_CHANNEL, 1, &channelCount, &info.bmChannel);
if(!rc && !channelCount)
rc = MAXT_ERROR_NOT_FOUND;
if(!rc)
{
#ifdef EMBEDDED_PART
rc=testEmbeddedPart(info);
#else
rc=testHostPart(info);
#endif
}
if(rc)
{
char errorString[200];
if(mxfSystemErrorStringGet(0, rc, sizeof(errorString), errorString))
sprintf (errorString,"ERROR # 0x%X", rc);
printf("%s\n\r", errorString);
}
printf("Terminating ...\n\r");
// Free device buffers
mxfDeviceBuffersFree(info.device);
// Unload MX Foundation library
mxfSystemTerminate(info.server);
// Disconnect from MX Foundation library
mxfServerDisconnect(info.server);
#ifndef EMBEDDED_PART
printf("Press enter to terminate\n\r");
fgets(temp, 10, stdin);
#endif
return rc;
}
uint32
initHandler(HMXF_SERVER server, uint64 deviceIndex, uint64 moduleIndex, uint64 channelIndex, uint64 attrib, uint64* value)
{
server=server;
deviceIndex=deviceIndex;
moduleIndex=moduleIndex;
channelIndex=channelIndex;
if(attrib == KMXF_DEVICE_COMM_QUEUE_NUM)
{
// Set the communication queue number attribute
*value = 2;
return TRUE;
}
return FALSE;
}
uint32
commandSend(HMXF_BUFFER txBuffer, HMXF_BUFFER rxBuffer, EX_COMMAND* cmd)
{
uint64 readCnt;
uint64 byteCnt;
uint32 rc=0;
memset(&msg, 0, sizeof(msg));
msg.dataSize = (2+cmd->paramNum)*4;
memcpy(msg.data, cmd, msg.dataSize);
// Write command in the communication queue
rc=mxfDeviceCommBufferWrite(txBuffer, 1, &msg);
if(!rc && rxBuffer)
{
while(!rc)
{
// Wait acknowledge of embedded application
rc=mxfDeviceCommBufferRead(rxBuffer, 1, sizeof(msg), &readCnt, &byteCnt, &msg);
if(readCnt && msg.data[0]==EX_USER_COMMAND_ACK)
break;
}
}
return rc;
}
uint32
commandRead(HMXF_BUFFER rxBuffer, uint64* readCnt, EX_COMMAND* cmd)
{
uint64 byteCnt;
uint32 rc;
memset(cmd, 0, sizeof(*cmd));
// Read command from the communication queue
rc=mxfDeviceCommBufferRead(rxBuffer, 1, sizeof(*cmd), readCnt, &byteCnt, &msg);
if(!rc && *readCnt)
{
cmd->command = msg.data[0];
cmd->paramNum = msg.data[1];
memcpy(cmd->param, &msg.data[2], cmd->paramNum*4);
}
return rc;
}
uint32
testHostPart(TEST_INFO info)
{
EX_COMMAND cmd;
MXF_ASYNCEH_DATAREC* recAsync=NULL;
MXF_EMBEDDED_DATAREC* commRec=NULL;
HMXF_BUFFER txBuffer=0;
uint32 rc;
MXF_ASYNCEH_DATAREC* txHostBuffer=0;
size_t txBufferSize=0;
uint64 msgCount=0;
uint64 byteCount=0;
uint64 data;
uint64 byte;
uint64 word;
MXF_EMBEDDED_DATAREC* rxHostBuffer=0;
size_t rxBufferSize=0;
// Set ASYNC RX & TX channels speed to 1 mbps
rc=mxfAttributeUint64Set(info.rxChannel, KMXF_ASYNCEH_SPEED, 1000000);
if(!rc)
rc=mxfAttributeUint64Set(info.txChannel, KMXF_ASYNCEH_SPEED, 1000000);
// Set RX string gap to 1 bit
if(!rc)
rc=mxfAttributeUint64Set(info.rxChannel, KMXF_ASYNCEH_RX_STRING_GAP, 1);
#ifdef LOOPBACK
// Set internal loopback async channel
if(!rc)
rc=mxfAttributeUint64Set(info.rxChannel, KMXF_ASYNCEH_TX_RX_TEST_LB, VMXF_ENABLE);
// Set internal loopback Mil1553 channel
if(!rc)
rc=mxfAttributeUint64Set(info.bmChannel, KMXF_MIL1553_TX_RX_TEST_LB, VMXF_ENABLE);
#endif
if(!rc)
{
// Allocate 10 KB buffer for tx data
txBufferSize = 10*1024;
// Allocate TX Aperiodic buffer for HIGH priority queue
rc=mxfTxAperiodicBufferAlloc(info.txChannel, MXF_TXAPERIODIC_PRIORITY_HIGH, txBufferSize, &txBuffer, NULL);
// Host buffer allocation
if(!rc)
{
txBufferSize = 10*1024;
txHostBuffer = (MXF_ASYNCEH_DATAREC*)calloc(1, txBufferSize);
if(!txHostBuffer)
rc = MAXT_ERROR_MEM;
}
}
// Allocate 10 KB buffer for TX communication queue
if(!rc)
{
txBufferSize = 10*1024;
// Allocate buffer for comm queue #0
rc=mxfDeviceCommBufferAlloc(info.device, 0, txBufferSize, &info.commTxBuffer, NULL);
}
// Allocate 10 KB buffer for RX communication queue
if(!rc)
{
rxBufferSize = 10*1024;
// Allocate buffer for comm queue #1
rc=mxfDeviceCommBufferAlloc(info.device, 1, rxBufferSize, &info.commRxBuffer, NULL);
// Host buffer allocation
if(!rc)
{
rxHostBuffer = (MXF_EMBEDDED_DATAREC*)calloc(1, rxBufferSize);
if(!rxHostBuffer)
rc = MAXT_ERROR_MEM;
}
}
// TX data simulation @ 500 msec
if(!rc)
{
uint64 startTime = 500*1000*1000; //500 msec
uint64 delay = 100*1000*1000; //100 msec
uint8 value=0;
// Prepare string array (8 bytes per string with delay of 100 msec between each)
recAsync = txHostBuffer;
for(data=0; !rc && data<MAX_TX_RECORDS_TO_TRANSMIT; data++, value++)
{
recAsync->timeTag = startTime+(delay*data);
recAsync->control = 0;
recAsync->repeatCount = 1;
recAsync->dataSize = 8;
for (byte=0; byte < recAsync->dataSize; byte++)
recAsync->data[byte] = value;
recAsync->reserved = 0;
rc = mxfASYNCEHNextDataRecordPtrGet(recAsync, &recAsync);
}
if(!rc)
{
printf("Transmitting simulation data...\n\r");
// Transmit strings on relative record time
rc = mxfASYNCEHTxAperiodicWrite(txBuffer, MXF_TXAPERIODIC_FLAG_USE_RECORD_RELATIVE_TIME, 0, MAX_TX_RECORDS_TO_TRANSMIT, txHostBuffer);
}
}
// Upload and start embedded part
if(!rc)
{
fflush(stdout);
rc=mxfDeviceFileUpload(info.device, MXF_DEVICE_FILETYPE_APPLICATION, "mil1553_embedded_async_to_1553-flex.mxf");
}
// Send START command to embedded part
if(!rc)
{
cmd.command=EX_USER_COMMAND_ID_START;
cmd.paramNum=0;
rc=commandSend(info.commTxBuffer, info.commRxBuffer, &cmd);
}
// Wait 3 seconds
if(!rc)
mxfSleep(3000);
// Send STOP command to embedded part
if(!rc)
{
cmd.command=EX_USER_COMMAND_ID_STOP;
cmd.paramNum=0;
rc=commandSend(info.commTxBuffer, info.commRxBuffer, &cmd);
}
// Send READ command to embedded part
if(!rc)
{
cmd.command=EX_USER_COMMAND_ID_READ;
cmd.paramNum=0;
rc=commandSend(info.commTxBuffer, info.commRxBuffer, &cmd);
}
// Read RX communication buffer (BM messages)
if(!rc)
{
mxfSleep(100);
rc=mxfDeviceCommBufferRead(info.commRxBuffer, 0, rxBufferSize, &msgCount, &byteCount, rxHostBuffer);
if(!rc)
printf("String received count = %llu \n\r", msgCount);
if(!rc)
{
// Display received strings
commRec = (MXF_EMBEDDED_DATAREC*)rxHostBuffer;
for(data=0; data<msgCount; data++)
{
printf(" %02llu: Timetag=%012llu, Size=%u, Data=", data, commRec->timeTag, commRec->dataSize);
for(word=0; word<commRec->dataSize/2; word++)
printf("%04X", ((uint16 *)commRec->data)[word]);
printf("\n\r");
mxfNextRecordPtrGet(MXF_CLASS_EMBEDDED, MXF_RECTYPE_DATAREC, commRec, (void**)&commRec);
}
}
}
// Send TERMINATE command to embedded part
if(!rc)
{
cmd.command=EX_USER_COMMAND_ID_TERMINATE;
cmd.paramNum=0;
rc=commandSend(info.commTxBuffer, info.commRxBuffer, &cmd);
}
// Free host buffers
if(txHostBuffer)
free(txHostBuffer);
if(rxHostBuffer)
free(rxHostBuffer);
// Reload MXF
if(!rc)
rc=mxfSystemResourcesRelease(info.server, 0);
if(!rc)
rc=mxfSystemResourcesInit(info.server, 0);
return rc;
}
uint32
testEmbeddedPart(TEST_INFO info)
{
MXF_EMBEDDED_DATAREC* commRec=NULL;
EX_COMMAND cmd;
HMXF_BUFFER rxBuffer=0;
HMXF_BUFFER bmBuffer=0;
HMXF_BUFFER bcBuffer=0;
uint32 rc;
int run=TRUE;
MXF_MIL1553_DATAREC* bmHostBuffer=0;
MXF_EMBEDDED_DATAREC* commTxHostBuffer=0;
size_t rxBufferSize=0;
size_t txBufferSize=0;
uint64 status=0;
uint64 msgCount=0;
uint64 byteCount=0;
uint64 data;
uint64 byte;
HMXF_ASYNCEVENT asyncEvent=0;
EVENT_INFO eventInfo;
memset(&eventInfo, 0, sizeof(eventInfo));
// Set timebase to RTC nsec
rc=mxfSystemTimeBaseSet(info.server, MXF_TIMEBASE_DEVICE_NSEC);
// Get TX communication buffer
if(!rc)
rc=mxfDeviceCommBufferGet(info.device, 1, &info.commTxBuffer);
// Get RX communication buffer
if(!rc)
rc=mxfDeviceCommBufferGet(info.device, 0, &info.commRxBuffer);
// Allocate 10 KB buffer for RX acquisition
if(!rc)
{
rxBufferSize = 10*1024;
// Allocate RX data acquisition buffer
rc=mxfRxAcqBufferAlloc(info.rxChannel, rxBufferSize, &rxBuffer, NULL);
// Host buffer allocation
if(!rc)
{
eventInfo.rxHostBuffer = (MXF_ASYNCEH_DATAREC*)calloc(1, rxBufferSize);
if(!eventInfo.rxHostBuffer)
rc = MAXT_ERROR_MEM;
}
}
// Allocate 10 KB buffer for BM acquisition
if(!rc)
{
rxBufferSize = 10*1024;
// Allocate RX data acquisition buffer
rc=mxfRxAcqBufferAlloc(info.bmChannel, rxBufferSize, &bmBuffer, NULL);
// Host buffer allocation
if(!rc)
{
bmHostBuffer = (MXF_MIL1553_DATAREC*)calloc(1, rxBufferSize);
if(!bmHostBuffer)
rc = MAXT_ERROR_MEM;
}
}
// Allocate 1 KB buffer for BC update
if(!rc)
{
txBufferSize = 1*1024;
// Allocate BC update buffer for RT1 SA2 RX
rc=mxfTxPeriodicUpdateMsgBufferAlloc(info.bcChannel, 0, txBufferSize, &bcBuffer, NULL);
// Host buffer allocation
if(!rc)
{
eventInfo.bcHostBuffer = (MXF_MIL1553_DATAREC*)calloc(1, txBufferSize);
if(!eventInfo.bcHostBuffer)
rc = MAXT_ERROR_MEM;
}
}
// Allocate 10 KB buffer for host comm tx transmission
if(!rc)
{
txBufferSize = 10*1024;
commTxHostBuffer = (MXF_EMBEDDED_DATAREC*)malloc(txBufferSize);
if(!commTxHostBuffer)
rc = MAXT_ERROR_MEM;
}
// Initialize condition event for acq threshold on async channel
memset(&condition, 0, sizeof(condition));
condition.condID = MXF_ASYNCEVENT_COND_RXACQ_BUFFER_THRESHOLD;
condition.condition.rxAcqBufferThreshold.buffer = rxBuffer;
while(!rc && run)
{
rc=commandRead(info.commRxBuffer, &msgCount, &cmd);
if(!rc && msgCount)
{
msgCount=0;
switch(cmd.command)
{
case EX_USER_COMMAND_ID_START:
// Set the minor frame #0 using 1 Command
memset(&minorFrame, 0, sizeof(minorFrame));
// Command #0 : Address 1, Subaddress 2, RX, 4 words
rc = mxfMIL1553CommandCompose(RT_ADDRESS, RT_SUBADDRESS, MXF_MIL1553_COMMAND_DIR_RX, 4, &minorFrame.command);
// Set Mil1553 frame
if(!rc)
{
minorFrame.modulo = 1;
minorFrame.buffer = bcBuffer;
rc=mxfMIL1553TxPeriodicMajorFrameSet(info.bcChannel, 0, 0, 1, &minorFrame, NULL);
}
// attach async event handler
if(!rc)
{
eventInfo.rxBufferSize = rxBufferSize;
eventInfo.bcBuffer = bcBuffer;
rc=mxfAsyncEventHandlerInit(info.server, eventHandler, &eventInfo, &asyncEvent);
}
// set event condition on RX acquisition threshold
if(!rc)
rc=mxfAsyncEventConditionsSet(asyncEvent, TRUE, 1, &condition);
// Start acquisition on RX
if(!rc)
rc=mxfRxAcqStart(rxBuffer, MXF_RXACQ_FLAG_DEFAULT, 0, 0);
// Start acquisition on BM
if(!rc)
rc=mxfRxAcqStart(bmBuffer, MXF_RXACQ_FLAG_DEFAULT, 0, 0);
// Start BC frame with 50 msec rate
if(!rc)
rc=mxfMIL1553TxPeriodicMajorFrameStart(info.bcChannel, 0, 50000000, NULL);
printf("Recorder started !\n\r");
break;
case EX_USER_COMMAND_ID_STOP:
// Stop Mil1553 frame
rc=mxfTxPeriodicMajorFrameStop(info.bcChannel, 0, 0);
// Stop acquisition on RX
if(!rc)
rc=mxfRxAcqStop(rxBuffer);
// Stop acquisition on BM
if(!rc)
rc=mxfRxAcqStop(bmBuffer);
// Clear Mil1553 frame
if(!rc)
rc=mxfTxPeriodicMajorFrameClear(info.bcChannel, MXF_TXPERIODIC_UPDATEMSG_CLEAR_OPT_DEFAULT);
// Disable condition
if(!rc)
rc=mxfAsyncEventConditionsSet(asyncEvent, FALSE, 1, &condition);
// Detach event handler
if(!rc)
printf("Recorder stopped !\n\r");
break;
case EX_USER_COMMAND_ID_READ:
if(!rc)
{
printf("Reading ...\n\r");
// Read rx data buffer
rc=mxfMIL1553RxAcqRead(bmBuffer, 0, rxBufferSize, &status, &msgCount, &byteCount, bmHostBuffer);
if(!rc)
{
uint32* dw;
printf("Message received count = %llu \n\r", msgCount);
rec = bmHostBuffer;
commRec = commTxHostBuffer;
// Copy and swap words array (Communication queue data are 32-bit)
for(data=0; data<msgCount && !rc; data++)
{
memcpy(commRec, rec, 24);
memcpy(commRec->data, rec->data, rec->dataSize);
for(byte=0, dw=(uint32*)commRec->data; byte<commRec->dataSize; byte+=4, dw++)
*dw=DWORD_SWAP(*dw);
mxfNextRecordPtrGet(MXF_CLASS_EMBEDDED, MXF_RECTYPE_DATAREC, commRec, (void **)&commRec);
}
}
}
break;
case EX_USER_COMMAND_ID_TERMINATE:
run=FALSE;
printf("Embedded Application terminated !\n\r");
break;
}
// Send ACK to host application
cmd.command = EX_USER_COMMAND_ACK;
cmd.paramNum = 1;
cmd.param[0] = rc;
commandSend(info.commTxBuffer, 0, &cmd);
// Write BM data to communication buffer directly after READ command ACK
if(msgCount)
rc=mxfDeviceCommBufferWrite(info.commTxBuffer, msgCount, commTxHostBuffer);
}
}
// Free buffers
if(eventInfo.rxHostBuffer)
free(eventInfo.rxHostBuffer);
if(bmHostBuffer)
free(bmHostBuffer);
if(eventInfo.bcHostBuffer)
free(eventInfo.bcHostBuffer);
if(commTxHostBuffer)
free(commTxHostBuffer);
return rc;
}
uint32 eventHandler(HMXF_ASYNCEVENT asyncEvent, void* param)
{
EVENT_INFO* eventInfo=(EVENT_INFO*)param;
uint32 rc=0;
uint64 eventCount;
uint64 status, msgCount, byteCount;
// Get pending event
rc=mxfAsyncEventPendingGet(asyncEvent, 1, &eventCount, &pendingList);
if(!rc)
{
switch(pendingList.condID)
{
case MXF_ASYNCEVENT_COND_RXACQ_BUFFER_THRESHOLD:
// Read async channel message
rc=mxfASYNCEHRxAcqRead(pendingList.condition.rxAcqBufferThreshold.buffer, 1, eventInfo->rxBufferSize, &status, &msgCount, &byteCount, eventInfo->rxHostBuffer);
if(!rc)
{
// Copy async message to Mil1553 buffer
memset(eventInfo->bcHostBuffer, 0, sizeof(MXF_MIL1553_DATAREC));
eventInfo->bcHostBuffer->repeatCount = 1;
eventInfo->bcHostBuffer->dataSize = min(64, eventInfo->rxHostBuffer->dataSize);
eventInfo->bcHostBuffer->dataSize += 2; // +2 for command
memcpy(&eventInfo->bcHostBuffer->data[1], eventInfo->rxHostBuffer->data, eventInfo->bcHostBuffer->dataSize);
// Update Mil1553 message
rc=mxfMIL1553TxPeriodicUpdateMsgWrite(eventInfo->bcBuffer, 1, eventInfo->bcHostBuffer);
}
break;
}
}
if(rc)
printf("event handler rc=0x%08x\n\r", rc);
return rc;
}
Updated 10/23/2023