MX Foundation 4
ar664_end_system.c
/*******************************************************************************
//
// File:
// ar664_end_system.c
//
// Copyright (c) MAX Technologies Inc. 1988-2016, All Rights Reserved.
// CONFIDENTIAL AND PROPRIETARY INFORMATION WHICH IS THE
// PROPERTY OF MAX TECHNOLOGIES INC.
//
// This demo shows how to configure a client for a Boeing End System (ES).
// In this case the ES 23.1 ACP-CAP T) ES_ACP_FO is configured for 3 VL.
//
// Hardware Requirements:
// - FlexMulti A664
//
*******************************************************************************/
#include "example.h"
//#define LOOPBACK
//#define LOCAL
#define TEST_DATASIZE 64
#define TEST_MAX_CHANNELS 2
#define DATARECS_BUFFER_SIZE_MAX 64*1024
/* -------------------- VL - COM Ports Configuration Tables -----------------*/
#define ES_ACP_FO "ES_ACP-FO"
uint64 gFrameType = MXF_A664_FRAME_TYPE_BOEING;
#define VL_33569 33569
#define UDP_PORT_60256 60256
#define UDP_PORT_60257 60257
#define VL_33570 33570
#define UDP_PORT_60262 60262
#define VL_33571 33571
#define UDP_PORT_60265 60265
#define EQUIPMENT_CLASS 23
#define EQUIPMENT_POSITION 1
#define PARTITION_ID 0
static uint32 recvCount = 0;
static uint32 TxCount = 0;
/*******************************************************************************/
// Methods: COM Ports configurtion tables
/*******************************************************************************/
#define MAX_PORTS 4
#define STATE_DISABLE 0
#define STATE_ENABLE 1
struct A664_ES_PORT {
uint64 index;
uint16 direction;
uint16 vlId;
uint32 destPort;
HMXF_PORT port;
HMXF_VL vl;
struct {
HMXF_BUFFER bufferHandle;
void* bufferPtr;
uint32* reserved;
} buffer;
uint32 (*initChannel)(void*);
void (*rxProcessRequest)(uint16 vlId, uint16 port, uint8* bufferPtr);
uint32 (*txUpdateDatarecPDU)(struct A664_ES_PORT*, void*);
uint32 *reserved;
uint32 status;
uint32 reserved1;
};
typedef struct A664_ES_PORT A664_ES_PORT;
A664_ES_PORT portRxTable[MAX_PORTS];
#define A664_ES_PORT_RX_TABLE_SIZE sizeof(portRxTable) / sizeof(A664_ES_PORT)
A664_ES_PORT portTxTable[MAX_PORTS];
#define A664_ES_PORT_TX_TABLE_SIZE sizeof(portTxTable) / sizeof(A664_ES_PORT)
/* -------------------------- VL Attributes Tables -----------------------*/
typedef struct {
uint32 equipmentClass;
uint32 equipmentPosition;
uint32 vlId;
uint32 subVL;
uint32 destPort;
uint32 bag;
uint32 maxBuffers;
uint32 buffSize;
uint32 edeEnable;
uint32 edeSID;
uint32 icEnable;
uint32 frameSizeMax;
uint32 jitter;
} A664_ES_VL_TX_LIST_ATTRIBUTE;
A664_ES_VL_TX_LIST_ATTRIBUTE esVLTxAttrib[] =
{
{ EQUIPMENT_CLASS, EQUIPMENT_POSITION, VL_33569, 1, UDP_PORT_60257, 1*1000*1000, 16, 1024, TRUE, 0x04, TRUE, 1024, 0 },
{ EQUIPMENT_CLASS, EQUIPMENT_POSITION, VL_33569, 1, UDP_PORT_60256, 1*1000*1000, 32, 1024, TRUE, 0x05, TRUE, 1024, 0 },
{ EQUIPMENT_CLASS, EQUIPMENT_POSITION, VL_33570, 1, UDP_PORT_60262, 1*1000*1000, 16, 1024, TRUE, 0x06, TRUE, 1024, 0 },
{ EQUIPMENT_CLASS, EQUIPMENT_POSITION, VL_33571, 1, UDP_PORT_60265, 1*1000*1000, 16, 1024, TRUE, 0x06, TRUE, 1024, 0 }
};
#define A664_ES_VL_TX_ATTRIBUTE_LIST_SIZE sizeof(esVLTxAttrib) / sizeof(A664_ES_VL_TX_LIST_ATTRIBUTE)
typedef struct {
uint32 equipmentClass;
uint32 equipmentPosition;
uint32 vlId;
uint32 destPort;
uint32 maxBuffers;
uint32 buffSize;
uint32 edeEnable;
uint32 edeSID;
uint32 icEnable;
uint32 skewMax;
uint32 frameSizeMax;
} A664_ES_VL_RX_LIST_ATTRIBUTE;
A664_ES_VL_RX_LIST_ATTRIBUTE esVLRxAttrib[] =
{
{ EQUIPMENT_CLASS, EQUIPMENT_POSITION, VL_33569, UDP_PORT_60256, 10, 1024, TRUE, 0x04, TRUE, 900*1000, 1024 },
{ EQUIPMENT_CLASS, EQUIPMENT_POSITION, VL_33569, UDP_PORT_60257, 10, 1024, TRUE, 0x04, TRUE, 900*1000, 1024 },
{ EQUIPMENT_CLASS, EQUIPMENT_POSITION, VL_33570, UDP_PORT_60262, 20, 1024, TRUE, 0x05, TRUE, 900*1000, 900 },
{ EQUIPMENT_CLASS, EQUIPMENT_POSITION, VL_33571, UDP_PORT_60265, 12, 1024, TRUE, 0x06, TRUE, 800*1000, 600 }
};
#define A664_ES_VL_RX_ATTRIBUTE_LIST_SIZE sizeof(esVLRxAttrib) / sizeof(A664_ES_VL_RX_LIST_ATTRIBUTE)
typedef struct {
uint32 equipmentClass;
uint32 equipmentPosition;
uint32 partitionId;
uint32 vlId;
uint32 multicast;
uint32 dstIpAdrs;
uint16 srcPort;
uint16 destPort;
uint32 maxBuffers;
uint32 buffSize;
uint32 edeEnable;
uint32 ageValidationEnable;
uint32 edeOrdinalEnable;
uint32 edeSID;
uint32 frameSizeMax;
char* esName;
} A664_ES_PORT_ATTRIBUTES;
A664_ES_PORT_ATTRIBUTES esCOMAttrib[] =
{
{ EQUIPMENT_CLASS, EQUIPMENT_POSITION, PARTITION_ID, VL_33569, TRUE, 0, 60257, 60257, 10, 1024, TRUE, FALSE, TRUE, 0x04, 1200, ES_ACP_FO },
{ EQUIPMENT_CLASS, EQUIPMENT_POSITION, PARTITION_ID, VL_33569, TRUE, 0, 60256, 60256, 10, 1024, TRUE, FALSE, TRUE, 0x04, 1200, ES_ACP_FO },
{ EQUIPMENT_CLASS, EQUIPMENT_POSITION, PARTITION_ID, VL_33570, TRUE, 0, 60262, 60262, 10, 1024, TRUE, FALSE, TRUE, 0x04, 1200, ES_ACP_FO },
{ EQUIPMENT_CLASS, EQUIPMENT_POSITION, PARTITION_ID, VL_33571, TRUE, 0, 60265, 60265, 10, 1024, TRUE, FALSE, TRUE, 0x04, 1200, ES_ACP_FO },
};
#define A664_ES_PORT_COM_ATTRIBUTES_SIZE sizeof(esCOMAttrib) / sizeof(A664_ES_PORT_ATTRIBUTES)
/*******************************************************************************/
// Methods: VL33569Port60257
/*******************************************************************************/
typedef struct {
struct {
uint32 Reserved_Word;
uint32 FSS; // Functional_Status_set
} header;
// bit start 64
uint32 PA_PPT_ECHO : 1;
uint32 SPEAKER_STATUS : 1;
uint32 HANDMIC_PPT_ECHO : 1;
uint32 GLARESHIELD_PPT_ECHO : 1;
uint32 CONTROL_WHEEL_PPT_ECHO : 1;
uint32 ACT_MIC_PPT_ECHO : 1;
uint32 bitfill1 : 26;
uint32 wordfill1;
// bit start 96
uint16 WARN_AUD_ENUM_RTN_1_A;
uint16 WARN_AUD_ENUM_RTN_1_B;
uint16 WARN_AUD_ENUM_RTN_2_A;
uint16 WARN_AUD_ENUM_RTN_2_B;
uint16 WARN_AUD_ENUM_RTN_3_A;
uint16 WARN_AUD_ENUM_RTN_3_B;
uint16 WARN_AUD_ENUM_RTN_4_A;
uint16 WARN_AUD_ENUM_RTN_4_B;
// bit start 224
uint32 CDN_REVERSION_STATUS : 1;
uint32 bitfill2 : 31;
// bit start 256
uint32 HF_L_PPT : 1;
uint32 HF_R_PPT : 1;
uint32 SAT_L1_PPT : 1;
uint32 SAT_L2_PPT : 1;
uint32 VHF_C_PPT : 1;
uint32 VHF_L_PPT : 1;
uint32 VHF_R_PPT : 1;
uint32 FLT_PPT : 1;
uint32 SAT_R1_PPT : 1;
uint32 SAT_R2_PPT : 1;
uint32 bitfill3 : 31;
// bit start 288
uint32 CAB_PPT : 2;
uint32 PA_PPT : 2;
// bit start 320
uint32 HF_L_SELCAL_RESET : 1;
uint32 HF_R_SELCAL_RESET : 1;
uint32 VHF_C_SELCAL_RESET : 1;
uint32 VHF_L_SELCAL_RESET : 1;
uint32 VHF_R_SELCAL_RESET : 1;
uint32 MIC_ON_VHF_L : 1;
uint32 MIC_ON_VHF_C : 1;
uint32 MIC_ON_VHF_R : 1;
uint32 SAT_L1_MIC_ON : 1;
uint32 SAT_L2_MIC_ON : 1;
uint32 SAT_R1_MIC_ON : 1;
uint32 SAT_R2_MIC_ON : 1;
// bit start 252
uint32 MIC_ON_CAB : 2;
uint32 CAB_PRIORITY_CALL : 2;
uint32 FLT_RESET : 2;
uint32 TUNING_DISPLAY_CODE : 8;
// bit start 416
uint32 CAP_USING_OBS_ACP : 1;
uint32 OXY_MIC_ON : 1;
uint32 FO_USING_OBS_ACP : 1;
} A664_PORT60257_PDU;
void showPort60257Status(uint16 vlId, uint16 port, uint8* bufferPtr)
{
A664_PORT60257_PDU* port60257 = (A664_PORT60257_PDU*)bufferPtr;
printf("\n<= %03d: Receiving Status from VL %d Port %d\n\n", ++recvCount, vlId, port);
printf(" PA-PPT_ECHO: %s\n", port60257->PA_PPT_ECHO ? "is active" : "is not active");
printf(" SPEAKER_STATUS: %s\n", port60257->SPEAKER_STATUS ? "Appropriate speaker_current exist" : "is not Active");
printf(" HANDMIC_PPT_ECHO: %s\n", port60257->HANDMIC_PPT_ECHO ? "is active" : "is not active");
printf(" GLARESHIELD_PPT_ECHO: %s\n", port60257->GLARESHIELD_PPT_ECHO ? "is active" : "is not active");
printf(" CONTROL_WHEEL_PPT_ECHO: %s\n", port60257->GLARESHIELD_PPT_ECHO ? "is active" : "is not active");
printf(" ACT_MIC_PPT_ECHO: %s\n", port60257->ACT_MIC_PPT_ECHO ? "is active" : "is not active");
printf(" WARN_AUD_ENUM_RTN_1_A: 0x%04hx\n", port60257->WARN_AUD_ENUM_RTN_1_A);
printf(" WARN_AUD_ENUM_RTN_1_B: 0x%04hx\n", port60257->WARN_AUD_ENUM_RTN_1_B);
printf(" CDN_REVERSION_STATUS: %s\n", port60257->CDN_REVERSION_STATUS ? "asserted" : "not asserted");
printf(" HF-L_PPT: PPT Keyline %s\n", port60257->HF_L_PPT ? "is active" : "is not actived");
printf(" HF-R_PPT: PPT Keyline %s\n", port60257->HF_R_PPT ? "is active" : "is not actived");
printf(" HF-MIC_ON_VHF_L: Mic Switch %s\n", port60257->HF_L_PPT ? "selected" : "not selected");
printf(" HF-MIC_ON_CAB: %s\n", port60257->MIC_ON_CAB ? "valid" : "invalid");
printf(" TUNING_DISPLAY_CODE: %s\n", port60257->TUNING_DISPLAY_CODE ? "valid" : "invalid");
printf(" CAP_USING_OBS_ACP: %s\n", port60257->CAP_USING_OBS_ACP ? "valid" : "invalid");
printf(" OXY_MIC_ON: oxigen mask %s\n", port60257->OXY_MIC_ON ? "deployed" : " not deployed");
printf(" FO_USING_OBS_ACP: First Officer using Observer audio : %s\n", port60257->FO_USING_OBS_ACP ? "yes" : "no");
printf("\n\n");
}
uint32 txUpdateParmsVL33569Port60257(A664_ES_PORT* port, void* pdu)
{
A664_PORT60257_PDU* port60257;
uint32 length = 0;
// Build the updated status vector
port60257 = (A664_PORT60257_PDU*)port->buffer.bufferPtr;
if (port60257)
{
port60257->header.Reserved_Word = 0;
port60257->header.FSS = 0;
port60257->PA_PPT_ECHO = FALSE;
port60257->SPEAKER_STATUS = TRUE;
port60257->HANDMIC_PPT_ECHO = FALSE;
port60257->GLARESHIELD_PPT_ECHO = FALSE;
port60257->CONTROL_WHEEL_PPT_ECHO = FALSE;
port60257->ACT_MIC_PPT_ECHO = FALSE;
port60257->WARN_AUD_ENUM_RTN_1_A += 0x0010;
port60257->WARN_AUD_ENUM_RTN_1_B += 0x0020;
port60257->CDN_REVERSION_STATUS = FALSE;
port60257->MIC_ON_VHF_L = TRUE;
port60257->MIC_ON_VHF_C = TRUE;
port60257->MIC_ON_VHF_R = TRUE;
port60257->MIC_ON_CAB = FALSE;
port60257->OXY_MIC_ON = FALSE;
port60257->FO_USING_OBS_ACP = TRUE;
memcpy(pdu, port60257, sizeof(A664_PORT60257_PDU));
length = sizeof(A664_PORT60257_PDU);
}
else
printf("COM Port buffer not assigned for VL=%d, port=%d\n", port->vlId, port->destPort);
return length;
}
/*******************************************************************************/
// Methods: VL33569Port60256
/*******************************************************************************/
enum NAV_SELECT_CODE { VOR_L, VOR_R, ADF_L, ADF_R };
enum APP_SELECT_CODE { APP_L, APP_R, MK_R, Invalid };
enum VBR_CODE { VOICE, BOTH, RANGE };
typedef struct {
struct {
uint32 Reserved_Word;
uint32 FSS; // Functional_Status_set
} header;
// bit start 64
uint32 NAV_SELECT_CODE : 2;
uint32 APP_SELECT_CODE : 2;
uint32 VBR_CODE : 2;
// bit start 96
uint16 VHF_L_VOLUME;
uint16 VHF_C_VOLUME;
uint16 VHF_R_VOLUME;
uint16 FLT_VOLUME;
uint16 CAB_VOLUME;
uint16 PA_VOLUME;
uint16 HF_L_VOLUME;
uint16 HF_R_VOLUME;
uint16 SAT1_VOLUME;
uint16 SAT2_VOLUME;
uint16 NAV_VOLUME;
uint16 APPROACH_VOLUME;
uint16 SPEAKER_VOLUME;
uint16 reserved;
} A664_PORT60256_PDU;
void showPort60256Status(uint16 vlId, uint16 port, uint8* bufferPtr)
{
A664_PORT60256_PDU* port60256 = (A664_PORT60256_PDU*)bufferPtr;
printf("\n<= %03d: Receiving Status from VL %d Port %d\n\n", ++recvCount, vlId, port);
printf(" NAV_SELECT_CODE: %d\n", port60256->NAV_SELECT_CODE);
printf(" APP_SELECT_CODE: %d\n", port60256->APP_SELECT_CODE);
printf(" VBR_CODE: %d\n", port60256->VBR_CODE);
printf(" VBR_CODE: %d\n", port60256->VBR_CODE);
printf(" VHF_L_VOLUME: %d\n", port60256->VHF_L_VOLUME);
printf(" VHF_C_VOLUME: %d\n", port60256->VHF_C_VOLUME);
printf(" VHF_R_VOLUME: %d\n", port60256->VHF_C_VOLUME);
printf(" FLT_VOLUME: %d\n", port60256->FLT_VOLUME);
printf(" CAB_VOLUME: %d\n", port60256->CAB_VOLUME);
printf(" PA_VOLUME: %d\n", port60256->PA_VOLUME);
printf(" HF_L_VOLUME: %d\n", port60256->HF_L_VOLUME);
printf(" HF_R_VOLUME: %d\n", port60256->HF_R_VOLUME);
printf(" SAT1_VOLUME: %d\n", port60256->SAT1_VOLUME);
printf(" SAT2_VOLUME: %d\n", port60256->SAT2_VOLUME);
printf(" NAV_VOLUME: %d\n", port60256->NAV_VOLUME);
printf(" APPROACH_VOLUME: %d\n", port60256->APPROACH_VOLUME);
printf(" SPEAKER_VOLUME: %d\n", port60256->SPEAKER_VOLUME);
}
uint32 txUpdateParmsVL33569Port60256(A664_ES_PORT* port, void* pdu)
{
A664_PORT60256_PDU* port60256;
uint32 length = 0;
// Build the updated status vector
port60256 = (A664_PORT60256_PDU*)port->buffer.bufferPtr;
if (port60256)
{
memset(port60256, 0, sizeof(A664_PORT60256_PDU));
port60256->header.Reserved_Word = 0;
port60256->header.FSS = 0;
port60256->NAV_SELECT_CODE = ADF_L;
port60256->APP_SELECT_CODE = APP_L;
port60256->VBR_CODE = BOTH;
port60256->VHF_L_VOLUME = 5000;
port60256->VHF_C_VOLUME = 6000;
port60256->VHF_R_VOLUME = 5000;
port60256->FLT_VOLUME = 7000;
port60256->CAB_VOLUME = 7000;
port60256->HF_L_VOLUME = 5000;
port60256->HF_R_VOLUME = 5000;
port60256->SAT1_VOLUME = 6000;
port60256->SAT2_VOLUME = 6000;
port60256->NAV_VOLUME = 10000;
port60256->APPROACH_VOLUME = 10000;
port60256->SPEAKER_VOLUME = 10000;
memcpy(pdu, port60256, sizeof(A664_PORT60256_PDU));
length = sizeof(A664_PORT60256_PDU);
}
else
printf("COM Port buffer not assigned for VL=%d, port=%d\n", port->vlId, port->destPort);
return length;
}
/*******************************************************************************/
// Methods: Inbound - Outbound Messages
/*******************************************************************************/
uint32 processPartitionOutboundTraffic(void)
{
uint32 portIdx, dataIdx;
void* bufferPtr;
uint32 rc = 0;
uint64 count;
for (portIdx = 0; portIdx < A664_ES_PORT_TX_TABLE_SIZE; portIdx++)
{
bufferPtr = portTxTable[portIdx].buffer.bufferPtr;
if (!bufferPtr)
{
printf("parm vector not assigned for vlId=%d, port=%d", portTxTable[portIdx].vlId, portTxTable[portIdx].destPort);
continue;
}
if (portTxTable[portIdx].status & STATE_ENABLE)
{
// Something to send
memset(&datarec, 0, sizeof(MXF_A664_DATAREC));
// Build the Transmit Record
datarec.timeTag = 0;
datarec.control = 0;
datarec.repeatCount = 1;
datarec.dataSize = portTxTable[portIdx].txUpdateDatarecPDU(&portTxTable[portIdx], &datarec.data[0]);
#if 1
printf("==> %03d: Sending for vlId=%d, port=%d\n", TxCount++, portTxTable[portIdx].vlId, portTxTable[portIdx].destPort);
printf(" timeTag=%012llx, control=%d, dataSize=%d", datarec.timeTag, datarec.control, datarec.dataSize);
printf("\n data=");
for (dataIdx = 0; dataIdx < datarec.dataSize; dataIdx++)
{
printf("%02X ", datarec.data[dataIdx]);
if (!((dataIdx + 1) % 8) && (dataIdx + 1 < datarec.dataSize))
printf("\n ");
}
printf("\n\n");
#endif
// Ethernet RJ45 TX and Systen unit light 1 indicate the transmission
rc = mxfA664TxAperiodicWrite(portTxTable[portIdx].port, MXF_TXAPERIODIC_FLAG_DEFAULT, 0, 1, &datarec, &count);
if (rc)
printf("Transmission Error rc=0x%08x\r", rc);
}
}
mxfSleep(2000);
return rc;
}
uint32 processPartitionInboundTraffic(void)
{
MXF_A664_DATAREC* bufferPtr;
A664_ES_PORT* portRx;
HMXF_BUFFER bufferHandle;
uint64 status, msgsCount, bytesCount;
uint32 portIdx;
uint32 maxPorts, rc = 0;
maxPorts = A664_ES_PORT_RX_TABLE_SIZE;
// Free the Resources Allocated
for (portIdx = 0; portIdx < maxPorts; portIdx++)
{
portRx = &portRxTable[portIdx];
if (portRx->status & STATE_ENABLE)
{
bufferHandle = portRx->buffer.bufferHandle;
bufferPtr = portRx->buffer.bufferPtr;
rc = mxfRxAcqBufferStatusGet(bufferHandle, &status, &msgsCount, NULL, NULL);
if (rc || !(status & MXF_RXACQ_STATUS_RUNNING))
{
printf("Acquisition stopped; status=%llx, rc=0x%08x\n\n", status, rc);
continue;
}
if (msgsCount > 0)
{
// Read the data
rc = mxfA664RxAcqRead(bufferHandle, 0, DATARECS_BUFFER_SIZE_MAX, &status, &msgsCount, &bytesCount, bufferPtr);
if (!rc)
portRx->rxProcessRequest(portRx->vlId, (uint16)portRx->destPort, &bufferPtr->data[0]);
}
}
}
return rc;
}
/*******************************************************************************/
// Methods: Resources Allocation
/*******************************************************************************/
uint32 CreateVl(HMXF_CHANNEL phy, void* parm, uint32 vlid, uint32 direction, uint64 frameType, HMXF_VL* vl)
{
uint32 rc;
memset(&param, 0, sizeof(MXF_A664_VL_PARAM));
*vl = 0;
param.direction = direction;
param.VLId = vlid;
param.frameType = frameType;
switch (direction)
{
case MXF_A664_VL_DIR_TX:
{
A664_ES_VL_TX_LIST_ATTRIBUTE* attrib = (A664_ES_VL_TX_LIST_ATTRIBUTE*)parm;
param.frameSizeMax = attrib->frameSizeMax;
param.dir.Tx.subVlNumber = attrib->subVL;
param.dir.Tx.bag = attrib->bag;
param.dir.Tx.netSelection = MXF_A664_NETSELECT_ALL;
param.dir.Tx.Ede.enable = attrib->edeEnable;
param.dir.Tx.subVl[0].maxBuffers = attrib->maxBuffers;
param.dir.Tx.subVl[0].bufferSize = attrib->buffSize;
rc = mxfA664VlCreate(phy, &param, vl);
}
break;
case MXF_A664_VL_DIR_RX:
{
A664_ES_VL_RX_LIST_ATTRIBUTE* attrib = (A664_ES_VL_RX_LIST_ATTRIBUTE*)parm;
param.frameSizeMax = attrib->frameSizeMax;
if (attrib->edeEnable)
{
// Boeing EDE
param.dir.Rx.Ede.enable = attrib->edeEnable;
param.dir.Rx.Ede.skewMax = attrib->skewMax;
}
else
{
// ARINC MAC
param.dir.Rx.Mac.skewMax = 4000;
param.dir.Rx.Mac.rmPSNRange = 2;
}
// Create the VL
rc = mxfA664VlCreate(phy, &param, vl);
}
break;
default:
rc = MAXT_ERROR_DIRECTION;
break;
}
if (rc == MAXT_ERROR_VL_IN_USE)
{
// The VL was created previously; return the VL handle
rc = mxfA664VlGet(phy, &param, vl);
}
return rc;
}
uint32 CreateCOMPort(HMXF_VL vl, uint64 direction, uint64 mode, A664_ES_PORT_ATTRIBUTES* attribCOM, HMXF_PORT* port, HMXF_BUFFER* bufferHandle)
{
HMXF_PORT portHandle;
uint32 srcIpAdrs, dstIpAdrs;
uint32 rc;
srcIpAdrs = 0x0A000000 | ((attribCOM->equipmentClass & 0xff) << 16) | ((attribCOM->equipmentPosition & 0xff) << 8) | (attribCOM->equipmentClass & 0xff);
memset(&portParam, 0, sizeof(MXF_A664_PORT_PARAM));
portParam.portType = MXF_A664_PORT_TYPE_COM;
portParam.family = MXF_A664_PORT_FAMILY_IPV4;
portParam.mode = mode;
if (direction == MXF_A664_VL_DIR_RX)
{
portParam.dir.Rx.bufferSize = attribCOM->buffSize;
portParam.dir.Rx.maxBuffers = attribCOM->maxBuffers;
portParam.dir.Rx.network = MXF_A664_NETSELECT_ALL;
}
else
portParam.dir.Tx.subVl = 0;
if (attribCOM->edeEnable)
portParam.Ede.sid = attribCOM->edeSID;
portParam.type.COM.srcAddress.version.IPv4.address = srcIpAdrs;
portParam.type.COM.srcAddress.port = attribCOM->srcPort;
if (attribCOM->multicast)
dstIpAdrs = 0xE0E00000 | attribCOM->vlId;
else
dstIpAdrs = attribCOM->dstIpAdrs;
portParam.type.COM.destAddress.version.IPv4.address = dstIpAdrs;
portParam.type.COM.destAddress.port = attribCOM->destPort;
#if 1
printf("\nCreating %s COM Port (vlId=%d)\n", direction == MXF_A664_VL_DIR_TX ? "Tx" : "Rx", attribCOM->vlId);
printf(" srcAddress=0x%08x\n", srcIpAdrs);
printf(" srcPort=0x%08x (%d)\n", attribCOM->srcPort, attribCOM->srcPort);
printf(" destAddress=0x%08x\n", dstIpAdrs);
printf(" dstPort=0x%08x (%d)\n", attribCOM->destPort, attribCOM->destPort);
#endif
// Allocate the TX buffer for the port - just create the handle...)
rc = mxfA664PortCreate(vl, &portParam, &portHandle);
if (!rc)
{
switch (direction)
{
case MXF_A664_VL_DIR_TX:
rc = mxfTxAperiodicBufferGet(vl, portParam.dir.Tx.subVl, bufferHandle);
break;
case MXF_A664_VL_DIR_RX:
rc = mxfRxAcqBufferGet(portHandle, bufferHandle);
break;
}
if (!rc)
*port = portHandle;
}
return rc;
}
uint32 allocateTxCOMChannelsResources(HMXF_CHANNEL phy)
{
uint32 rc=0;
HMXF_VL vl;
HMXF_PORT port;
HMXF_BUFFER bufferHandle;
void* bufferPtr;
int vlIdx, portIdx, comIdx;
for (comIdx = 0; comIdx < A664_ES_PORT_COM_ATTRIBUTES_SIZE && !rc; comIdx++)
{
for (portIdx = 0; portIdx < A664_ES_PORT_TX_TABLE_SIZE && !rc; portIdx++)
{
if (esCOMAttrib[comIdx].vlId == portTxTable[portIdx].vlId &&
esCOMAttrib[comIdx].destPort == portTxTable[portIdx].destPort)
{
for (vlIdx = 0; vlIdx < A664_ES_VL_TX_ATTRIBUTE_LIST_SIZE; vlIdx++)
{
// Locate attribute for the VL Creation
if (esCOMAttrib[comIdx].vlId == esVLTxAttrib[vlIdx].vlId)
{
// Allocate a Tx Port
rc = CreateVl(phy, &esVLTxAttrib[vlIdx], esVLTxAttrib[vlIdx].vlId, MXF_A664_VL_DIR_TX, MXF_A664_FRAME_TYPE_BOEING, &vl);
if (!rc)
{
// Add TX COM Port(s) to the VL
rc = CreateCOMPort(vl, MXF_A664_VL_DIR_TX, MXF_A664_PORT_MODE_QUEUING, &esCOMAttrib[comIdx], &port, &bufferHandle);
if (!rc)
{
bufferPtr = malloc(DATARECS_BUFFER_SIZE_MAX);
// Add a new session to list
if (bufferPtr)
{
memset(bufferPtr, 0, DATARECS_BUFFER_SIZE_MAX);
portTxTable[portIdx].index = portIdx;
portTxTable[portIdx].direction = MXF_A664_VL_DIR_TX;
portTxTable[portIdx].vl = vl;
portTxTable[portIdx].port = port;
portTxTable[portIdx].buffer.bufferHandle = bufferHandle;
portTxTable[portIdx].buffer.bufferPtr = bufferPtr;
printf("Port TX %lld allocated for vlId=%d destPort=%d\n", portRxTable[portIdx].index, portTxTable[portIdx].vlId, portTxTable[portIdx].destPort);
break;
}
}
break;
}
}
}
}
}
}
printf("\n");
return rc;
}
uint32 allocateRxCOMChannelResources(HMXF_CHANNEL phy)
{
uint32 rc = 0;
HMXF_VL vl;
HMXF_PORT port;
HMXF_BUFFER rxBuffer;
uint32 vlIdx, comIdx, portIdx;
void* bufferPtr;
// Define the Rx COM Port
for (comIdx = 0; comIdx < A664_ES_PORT_COM_ATTRIBUTES_SIZE && !rc; comIdx++)
{
for (portIdx = 0; portIdx < A664_ES_PORT_RX_TABLE_SIZE && !rc; portIdx++)
{
if (esCOMAttrib[comIdx].vlId == portRxTable[portIdx].vlId &&
esCOMAttrib[comIdx].destPort == portRxTable[portIdx].destPort)
{
for (vlIdx = 0; vlIdx < A664_ES_VL_RX_ATTRIBUTE_LIST_SIZE; vlIdx++)
{
// Locate attribute for the VL Creation
if (esCOMAttrib[comIdx].vlId == esVLRxAttrib[vlIdx].vlId)
{
// Allocate the receive VL
rc = CreateVl(phy, &esVLRxAttrib[vlIdx], esVLRxAttrib[vlIdx].vlId, MXF_A664_VL_DIR_RX, MXF_A664_FRAME_TYPE_BOEING, &vl);
if (!rc)
{
rc = CreateCOMPort(vl, MXF_A664_VL_DIR_RX, MXF_A664_PORT_MODE_QUEUING, &esCOMAttrib[comIdx], &port, &rxBuffer);
if (!rc)
{
bufferPtr = malloc(DATARECS_BUFFER_SIZE_MAX);
if (bufferPtr)
{
memset(bufferPtr, 0, DATARECS_BUFFER_SIZE_MAX);
// Set and start acquisition channel
rc = mxfRxAcqModeSet(rxBuffer, MXF_RXACQ_MODE_LINEAR);
if (!rc)
rc = mxfRxAcqStart(rxBuffer, MXF_RXACQ_FLAG_DEFAULT, 0, 0);
if (!rc)
{
portRxTable[portIdx].index = portIdx;
portRxTable[portIdx].vl = vl;
portRxTable[portIdx].port = port;
portRxTable[portIdx].buffer.bufferHandle = rxBuffer;
portRxTable[portIdx].buffer.bufferPtr = bufferPtr;
portRxTable[portIdx].direction = MXF_A664_VL_DIR_RX;
printf("Port RX %lld allocated for vlId=%d, destPort=%d\n", portRxTable[portIdx].index, portRxTable[portIdx].vlId, portRxTable[portIdx].destPort);
}
}
break;
}
}
}
}
}
}
}
printf("\n");
return rc;
}
/*******************************************************************************/
// Partition Base Initialisation - Termination
/*******************************************************************************/
void configureApplicationPartition(void)
{
A664_PORT60256_PDU port60256;
A664_PORT60257_PDU port60257;
memset(portTxTable, 0, sizeof(portTxTable));
memset(portRxTable, 0, sizeof(portRxTable));
// Set static info in Tx port table
(portTxTable[0]).index = 0;
(portTxTable[0]).status = STATE_ENABLE;
(portTxTable[0]).vlId = VL_33569;
(portTxTable[0]).destPort = UDP_PORT_60256;
(portTxTable[0]).buffer.bufferPtr = &port60256;
(portTxTable[0]).txUpdateDatarecPDU = &txUpdateParmsVL33569Port60256;
(portTxTable[1]).index = 1;
(portTxTable[1]).status = STATE_ENABLE;
(portTxTable[1]).vlId = VL_33569;
(portTxTable[1]).destPort = UDP_PORT_60257;
(portTxTable[1]).buffer.bufferPtr = &port60257;
(portTxTable[1]).txUpdateDatarecPDU = &txUpdateParmsVL33569Port60257;
(portTxTable[2]).index = 2;
(portTxTable[2]).status = STATE_DISABLE;
(portTxTable[2]).vlId = VL_33570;
(portTxTable[2]).destPort = UDP_PORT_60262;
(portTxTable[2]).buffer.bufferPtr = NULL;
(portTxTable[2]).txUpdateDatarecPDU = NULL;
(portTxTable[3]).index = 3;
(portTxTable[3]).status = STATE_DISABLE;
(portTxTable[3]).vlId = VL_33571;
(portTxTable[3]).destPort = UDP_PORT_60265;
(portTxTable[3]).buffer.bufferPtr = NULL;
(portTxTable[3]).txUpdateDatarecPDU = NULL;
// Set static info in Rx port table
(portRxTable[0]).index = 0;
(portRxTable[0]).status = STATE_ENABLE;
(portRxTable[0]).vlId = VL_33569;
(portRxTable[0]).destPort = UDP_PORT_60256;
(portRxTable[0]).buffer.bufferPtr = NULL;
(portRxTable[0]).rxProcessRequest = &showPort60256Status;
(portRxTable[1]).index = 1;
(portRxTable[1]).status = STATE_ENABLE;
(portRxTable[1]).vlId = VL_33569;
(portRxTable[1]).destPort = UDP_PORT_60257;
(portRxTable[1]).buffer.bufferPtr = NULL;
(portRxTable[1]).rxProcessRequest = &showPort60257Status;
(portRxTable[2]).index = 2;
(portRxTable[2]).status = STATE_DISABLE;
(portRxTable[2]).vlId = VL_33570;
(portRxTable[2]).destPort = UDP_PORT_60262;
(portRxTable[2]).buffer.bufferPtr = NULL;
(portRxTable[2]).rxProcessRequest = NULL;
(portRxTable[3]).index = 3;
(portRxTable[3]).status = STATE_DISABLE;
(portRxTable[3]).vlId = VL_33571;
(portRxTable[3]).destPort = UDP_PORT_60265;
(portRxTable[3]).buffer.bufferPtr = NULL;
(portRxTable[3]).rxProcessRequest = NULL;
}
void FreeAllAllocatedResources(void)
{
uint32 rc = 0;
HMXF_BUFFER bufferHandle;
void* bufferPtr;
uint64 status;
uint32 index;
// Free the Resources Allocated
for (index = 0; index < A664_ES_PORT_RX_TABLE_SIZE; index++)
{
bufferHandle = portRxTable[index].buffer.bufferHandle;
bufferPtr = portRxTable[index].buffer.bufferPtr;
if (bufferPtr)
free(bufferPtr);
rc = mxfRxAcqStop(bufferHandle);
// Make sure the acquisition if stopped
while (!rc)
{
rc = mxfRxAcqBufferStatusGet(bufferHandle, &status, NULL, NULL, NULL);
if (status & MXF_RXACQ_STATUS_STOPPED)
break;
}
mxfRxAcqBufferFree(bufferHandle);
mxfA664PortRelease(portRxTable[index].port);
mxfA664VlRelease(portRxTable[index].vl);
}
for (index = 0; index < A664_ES_PORT_RX_TABLE_SIZE; index++)
{
bufferHandle = portTxTable[index].buffer.bufferHandle;
bufferPtr = portTxTable[index].buffer.bufferPtr;
if (bufferPtr)
free(bufferPtr);
mxfA664PortRelease(portTxTable[index].port);
mxfA664VlRelease(portTxTable[index].vl);
}
}
/*******************************************************************************/
// Main
/*******************************************************************************/
int main(void)
{
HMXF_SERVER server = 0;
HMXF_DEVICE device = 0;
HMXF_MODULE module = 0;
HMXF_CHANNEL phyChn = 0;
uint32 rc;
uint64 count = 0;
int loop=0;
#ifndef LOCAL
char szAddress[20];
#endif
printf("\nARINC664 End System (ES) Simulation Demo\n\n");
// Connect to server
#ifdef LOCAL
rc = mxfServerConnect("0.0.0.0", "", "", FALSE, &server);
#else
printf("Enter address of remote MXF4 server (IP or USB)\n\n");
printf(" xxx.xxx.xxx.xxx or usb\n\n");
fgets(szAddress, sizeof(szAddress), stdin);
szAddress[strcspn(szAddress, "\n")] = '\0';
if (!strcmp(szAddress, "usb"))
{
rc = mxfSystemUSBDetect(&count);
if (!rc && count)
rc = mxfSystemUSBServerConnect(0, &server);
// If device not found, return an error
if (!rc && !count)
rc = MAXT_ERROR_NOT_FOUND;
if (rc)
printf("No USB device detected; rc=0x%08x\n", rc);
}
else
{
rc = mxfServerConnect(szAddress, "admin", "admin", FALSE, &server);
if (rc)
printf("Error connecting to %s; rc=0x%08x\n", szAddress, rc);
}
#endif
if (rc)
{
printf("Failed to connect; rc=0x%08x\n", rc);
printf("\nPress a key to terminate\n");
getchar();
return 0;
}
// Initialize server, allocate base resources
rc = mxfSystemInit(server);
// Set Timebase
if (!rc)
rc = mxfSystemTimeBaseSet(server, MXF_TIMEBASE_DEVICE_NSEC);
// Get the first device handle
if (!rc)
rc = mxfSystemDeviceGet(server, 0, &device);
// Get the first A664 module
if (!rc)
rc = mxfDeviceModuleAllGet(device, MXF_MODULE_A664, 1, &count, &module);
// Obtain the first ARINC 664 Phy channel (Phy logical #0)
if (!rc && count)
rc = mxfModuleChannelAllGet(module, MXF_CLASS_A664, MXF_SCLASS_RX_CHANNEL, 1, &count, &phyChn);
// If module or channel not found, return an error
if (!rc && !count)
rc = MAXT_ERROR_NOT_FOUND;
#ifdef LOOPBACK
if (!rc)
rc = mxfAttributeUint64Set(phyChn, KMXF_A664_PHY_LOOPBACK, VMXF_A664_PHY_LOOPBACK_EXTERNAL);
if (!rc)
mxfSleep(500);
#endif
// Define the number of endpoints
configureApplicationPartition();
// Create the VL and COM ports (TX/RX) from the tables
if (!rc)
{
// Create the transmission (TX) virtual link
rc = allocateTxCOMChannelsResources(phyChn);
// Create the transmission (RX) virtual link
if (!rc)
rc = allocateRxCOMChannelResources(phyChn);
}
// Mainloop Check for requests for the Sessions
if (!rc)
{
while (!rc && loop++<1)
{
rc = processPartitionOutboundTraffic();
rc = processPartitionInboundTraffic();
}
// Free allocated Vl, PORT(s), buffers
FreeAllAllocatedResources();
}
// Close the server
if (server)
{
}
printf("\n\nPress a key to terminate rc=0x%08x\n", rc);
getchar();
return rc;
}
Updated 10/23/2023