MX Foundation 4
ar429_embedded_comm_queues.c
/*****************************************************************************
//
## File:
## ar429_embedded_comm_queues.c
//
// Copyright (c) MAX Technologies Inc. 1988-2019, All Rights Reserved.
// CONFIDENTIAL AND PROPRIETARY INFORMATION WHICH IS THE
// PROPERTY OF MAX TECHNOLOGIES INC.
//
// This program demonstrates the use of MX Foundation embedded service
// for downloading and controlling the ARINC 429 embedded application.
// Two queues are used for bidirectional communication:
// Queue #0: Tx queue (command)
// Queue #1: Rx queue (response)
//
// The host program "ar429_comm_queues.c" is required by this program
// and compiled executable must be located in
// the same folder as the embedded application executable.
//
// Hardware Requirements:
// - MAXT Flex with loopback between first TX and RX ARINC 429 Enhanced channels.
//
*****************************************************************************/
#include "example.h"
// User defines
#define BUFFER_SIZE 4096
#define EX_MAX_PARAM 8
#define EX_USER_COMMAND_ID_INIT 0x0
#define EX_USER_COMMAND_ID_START_TX 0x1
#define EX_USER_COMMAND_ID_STOP_TX 0x2
#define EX_USER_COMMAND_ID_START_ACQ 0x3
#define EX_USER_COMMAND_ID_STOP_ACQ 0x4
#define EX_USER_COMMAND_ID_TERMINATE 0x5
#define EX_USER_COMMAND_ACK 0xA5A5A5A5
#define TX_INDEX 1
#define RX_INDEX 0
// Global Variables
HMXF_CHANNEL rxChannel=0;
HMXF_CHANNEL txChannel=0;
HMXF_BUFFER rx429Buffer=0;
HMXF_BUFFER tx429Buffer=0;
HMXF_ASYNCEVENT asyncEvent=0;
MXF_ASYNCEVENT_CONDITION asyncEventInfoAcq;
HMXF_SCHED schedule=0;
HMXF_SCHED_MSG schedmsg;
uint32 acqStarted=FALSE;
uint32 bRun=TRUE;
// User structure
typedef struct
{
uint32 command;
uint32 paramNum;
uint32 param[EX_MAX_PARAM];
}
EX_COMMAND;
typedef struct
{
HMXF_MODULE module;
HMXF_BUFFER txCommBuffer;
MXF_A429_DATAREC *hostBuffer;
}
ASYNC_EVENT_PARAM;
uint32 asyncEventHandler(HMXF_ASYNCEVENT asyncEvent, void* param);
uint32 CommandExecute(HMXF_BUFFER txCommBuffer, HMXF_MODULE module, EX_COMMAND *cmd);
uint32 CommandSend(HMXF_BUFFER txCommBuffer, EX_COMMAND *cmd);
uint32 readAcquisition(HMXF_BUFFER buffer, MXF_A429_DATAREC *hostBuffer);
/***************************************************************************************************************/
// Main
/***************************************************************************************************************/
int main(void)
{
HMXF_SERVER server;
HMXF_DEVICE device=0;
HMXF_MODULE module=0;
uint64 count=0;
HMXF_BUFFER rxCommBuffer=0;
HMXF_BUFFER txCommBuffer=0;
MXF_ASYNCEVENT_CONDITION asyncEventInfoComm;
char buffer[64];
uint32 rc=0;
ASYNC_EVENT_PARAM asyncEventParam;
MXF_A429_DATAREC *hostBuffer=NULL;
// Connect to MXF locally
rc = mxfServerConnect("0.0.0.0", "", "", FALSE, &server);
if (rc)
{
printf("\nCannot connect locally to server (0x%08x)\n", rc);
exit(0);
}
printf("\nLoading\n");
// Initialize the library
rc = mxfSystemResourcesInit(server, FALSE);
// Get the device handle
if (!rc)
rc = mxfSystemDeviceGet(server, 0, &device);
// Get the first A429-EH module handle
if (!rc)
rc = mxfDeviceModuleAllGet(device, MXF_MODULE_A429_EH, 1, &count, &module);
// If not A429-EH module found, return an error
if(!rc && !count)
rc = MAXT_ERROR_NOT_FOUND;
// Get communication queues
if (!rc)
rc = mxfDeviceCommBufferGet(device, RX_INDEX, &rxCommBuffer);
if (!rc)
rc = mxfDeviceCommBufferGet(device, TX_INDEX, &txCommBuffer);
// Alloc host buffer
if(!rc)
{
hostBuffer = (MXF_A429_DATAREC *)malloc(BUFFER_SIZE);
if(!hostBuffer)
rc = MAXT_ERROR_MEM;
}
// Set the event handler
if(!rc)
{
asyncEventParam.txCommBuffer = txCommBuffer;
asyncEventParam.hostBuffer = hostBuffer;
asyncEventParam.module = module;
rc = mxfAsyncEventHandlerInit(server, &asyncEventHandler, &asyncEventParam, &asyncEvent);
}
// Set the RX comm buffer threshold async event condition
if(!rc)
{
memset(&asyncEventInfoComm, 0, sizeof(asyncEventInfoComm));
asyncEventInfoComm.condID = MXF_ASYNCEVENT_COND_COMM_RX_BUFFER_THRESHOLD;
asyncEventInfoComm.condition.commBufferThreshold.buffer = rxCommBuffer;
asyncEventInfoComm.condition.commBufferThreshold.almostFull = 1;
asyncEventInfoComm.condition.commBufferThreshold.almostEmpty = 0;
rc = mxfAsyncEventConditionsSet(asyncEvent, TRUE, 1, &asyncEventInfoComm);
}
// Wait for terminate command
while (bRun && !rc)
{
mxfSleep(100);
}
// Disable condition
if(!rc)
rc = mxfAsyncEventConditionsSet(asyncEvent, FALSE, 1, &asyncEventInfoComm);
if(!rc)
if(rc)
{
// Get the error message string
mxfSystemErrorStringGet(server, rc, sizeof(buffer), buffer);
printf("\n\r%s\n\r", buffer);
}
// Free the buffers at the end
if(device)
// Terminate MXF
if (server)
{
}
printf("Stopped\n");
return 0;
}
//****************************************************************************************************************
// Asynchronous Event Handler
//****************************************************************************************************************
uint32 asyncEventHandler(HMXF_ASYNCEVENT hAsyncEvent, void* param)
{
uint64 maxCount=64, pendingCount;
uint64 i;
uint32 rc;
uint64 readCnt, byteCnt;
ASYNC_EVENT_PARAM *asyncEventParam=(ASYNC_EVENT_PARAM *)param;
// Get the list of pending events to process
rc = mxfAsyncEventPendingGet(hAsyncEvent, maxCount, &pendingCount, pendingList);
for (i=0; !rc && i<pendingCount; i++)
{
switch(pendingList[i].condID)
{
case MXF_ASYNCEVENT_COND_COMM_RX_BUFFER_THRESHOLD:
{
rc = mxfDeviceCommBufferRead(pendingList[i].condition.commBufferThreshold.buffer, 1, sizeof(msg), &readCnt, &byteCnt, &msg);
if (!rc && readCnt)
rc = CommandExecute(asyncEventParam->txCommBuffer, asyncEventParam->module, (EX_COMMAND*)& msg.data);
break;
}
case MXF_ASYNCEVENT_COND_RXACQ_BUFFER_THRESHOLD:
readAcquisition(pendingList[i].condition.rxAcqBufferThreshold.buffer, asyncEventParam->hostBuffer);
break;
default:
printf("Unknown condID 0x%llx)", pendingList[i].condID);
break;
}
}
return rc;
}
/***************************************************************************************************************/
// CommandExecute
/***************************************************************************************************************/
uint32 CommandExecute(HMXF_BUFFER txCommBuffer, HMXF_MODULE module, EX_COMMAND *cmd)
{
EX_COMMAND ack;
uint32 rc=0;
switch(cmd->command)
{
case EX_USER_COMMAND_ID_INIT:
// Initialize the server
printf("Starting\n\r");
break;
case EX_USER_COMMAND_ID_START_TX:
{
MXF_A429_DATAREC recTx429;
uint32 label, sdi, data, ssm, parity;
// Find the ARINC 429 TX channel
if (cmd->paramNum == 0)
{
printf("Error: no channel index passed to transmission");
rc = MAXT_ERROR_DATA;
}
if (!rc)
{
printf("Starting transmission on channel %d\n\r", cmd->param[0]);
rc = mxfModuleChannelGet(module, cmd->param[0], &txChannel);
}
// Create the periodic scheduler
if(!rc)
rc = mxfTxPeriodicScheduleNew(txChannel, &schedule);
// Set scheduling values: Rate=10 ms (.1sec), Phase=0 us
if(!rc)
rc = mxfTxPeriodicScheduleMsgAdd(schedule, 10000000LL, 0, &schedmsg);
// Allocate buffer for data
if(!rc)
rc = mxfTxPeriodicUpdateMsgBufferAlloc(txChannel, 1, BUFFER_SIZE, &tx429Buffer, NULL);
// Define the number of buffer for the list and link to it
if(!rc)
rc = mxfTxPeriodicScheduleBufferListAdd(schedmsg, 1, 0, &tx429Buffer);
// Set record defined for the schedule: ARINC 429 LABEL=01H, SDI=0
if(!rc)
{
recTx429.timeTag=0;
recTx429.control=0;
recTx429.repeatCount = 1;
recTx429.reserved = 0;
label = 1;
sdi = 0;
data = 0x7fe;
ssm = 1;
parity = VMXF_A429_PARITY_ODD;
rc = mxfA429ArwCompose(label, sdi, data, ssm, parity, &recTx429.data);
if(!rc)
rc = mxfA429TxPeriodicUpdateMsgWrite(tx429Buffer, 1, &recTx429);
}
// Run the schedule now
if(!rc)
rc = mxfTxPeriodicScheduleRun(schedule);
if(!rc)
printf("Periodic transmission running\n\r");
break;
}
case EX_USER_COMMAND_ID_START_ACQ:
{
if (cmd->paramNum == 0)
{
printf("Error: no channel index passed to acquisition");
rc = MAXT_ERROR_DATA;
}
// Obtain the first ARINC 429 Protocol RX channel (RX logical #0)
if (!rc)
{
printf("Starting acquisition on channel %d\n\r", cmd->param[0]);
rc = mxfModuleChannelGet(module, cmd->param[0], &rxChannel);
}
// Allocate RX acquisition buffers
if(!rc)
rc = mxfRxAcqBufferAlloc(rxChannel, BUFFER_SIZE, &rx429Buffer, NULL);
// Set the RX acquisition async event condition
if(!rc)
{
memset(&asyncEventInfoAcq, 0, sizeof(asyncEventInfoAcq));
asyncEventInfoAcq.condID = MXF_ASYNCEVENT_COND_RXACQ_BUFFER_THRESHOLD;
asyncEventInfoAcq.condition.rxAcqBufferThreshold.buffer = rx429Buffer;
asyncEventInfoAcq.condition.rxAcqBufferThreshold.almostFull = 50;
asyncEventInfoAcq.condition.rxAcqBufferThreshold.almostEmpty = 10;
rc = mxfAsyncEventConditionsSet(asyncEvent, TRUE, 1, &asyncEventInfoAcq);
}
// Start the acquisition process
if (!rc)
rc = mxfRxAcqModeSet(rx429Buffer, MXF_RXACQ_MODE_CIRCULAR);
if (!rc)
{
rc = mxfRxAcqStart(rx429Buffer, MXF_RXACQ_FLAG_DEFAULT, 0, 0);
if (!rc)
{
printf("Acquisition running\n\r");
acqStarted=TRUE;
}
}
break;
}
case EX_USER_COMMAND_ID_STOP_TX:
{
if(schedule)
{
printf("Stopping periodic transmission\n\r");
rc = mxfTxPeriodicScheduleFree(schedule);
if(rc)
printf("mxfTxPeriodicScheduleFree rc=0x%08x\n", rc);
//mxfSleep(100);
}
break;
}
case EX_USER_COMMAND_ID_STOP_ACQ:
{
printf("Stopping acquisition\n\r");
if (rx429Buffer)
{
// Stop and clear unread data
rc = mxfRxAcqStop(rx429Buffer);
if(!rc)
rc = mxfRxAcqClear(rx429Buffer);
if(!rc)
rc = mxfAsyncEventConditionsSet(asyncEvent, FALSE, 1, &asyncEventInfoAcq);
if (!rc)
printf("Acquisition stopped\n\r");
}
acqStarted=FALSE;
break;
}
case EX_USER_COMMAND_ID_TERMINATE:
{
printf("Terminating\n\r");
bRun=FALSE;
break;
}
default:
break;
}
#if 1
printf("Exit rc=0x%08x\n", rc);
#endif
// Send ACK to host application
ack.command = EX_USER_COMMAND_ACK;
ack.paramNum = 4;
ack.param[0] = rc;
CommandSend(txCommBuffer, &ack);
return rc;
}
/***************************************************************************************************************/
// CommandSend
/***************************************************************************************************************/
uint32 CommandSend(HMXF_BUFFER txCommBuffer, EX_COMMAND *cmd)
{
uint32 rc;
memset(&msg, 0, sizeof(msg));
msg.dataSize = (2+cmd->paramNum)*4;
memcpy(msg.data, cmd, msg.dataSize);
rc = mxfDeviceCommBufferWrite(txCommBuffer, 1, &msg);
if (rc)
printf("Error writing: rc=0x%08x\n", rc);
return rc;
}
//****************************************************************************************************************
// Acquisition Reception
//****************************************************************************************************************
uint32 readAcquisition(HMXF_BUFFER buffer, MXF_A429_DATAREC *hostBuffer)
{
MXF_A429_DATAREC *recPtr=hostBuffer;
uint64 status, msgsCount, bytesCount;
uint64 label, sdi, data, ssm, parity;
uint64 j;
uint32 rc;
// Read and display records
rc = mxfA429RxAcqRead(buffer, 0, BUFFER_SIZE, &status, &msgsCount, &bytesCount, hostBuffer);
if(!rc)
{
printf("Read %llu messages\n\r", msgsCount);
for (j=0; !rc && j<msgsCount; j++)
{
rc = mxfA429ArwDecompose(recPtr->data, &label, &sdi, &data, &ssm, &parity);
if(!rc)
{
printf("%02llu: Timetag %llu - ARINC word=[%03llo,%lld,%05llX,%lld,%s]\n",
j, recPtr->timeTag, label, sdi, data, ssm, (parity==VMXF_A429_PARITY_ODD)?"ODD":"EVEN");
if(!rc)
rc = mxfA429NextDataRecordPtrGet(recPtr, &recPtr);
}
}
}
if(rc)
printf("Acquisition read failed; rc=0x%08x\n", rc);
return rc;
}
Updated 10/23/2023