nxdrvlinux/examples/tcpserver/Marshaller/HilMarshaller.c

1274 lines
49 KiB
C
Raw Permalink Normal View History

/**************************************************************************************
Copyright (c) Hilscher Gesellschaft fuer Systemautomation mbH. All Rights Reserved.
***************************************************************************************
$Id: HilMarshaller.c 14530 2022-06-27 12:01:46Z AMinor $:
Description:
Hilscher Transport marshalling main module
Changes:
Date Description
-----------------------------------------------------------------------------------
2022-06-27 Fix handling in HilMarshallerSetMode() to change mode of a single connector
2020-11-12 Moved OS functions to separate implementation module
2019-01-23 Bugfix:
- Fixed wrong deinitialization order in HilMarshallerStop()
2018-08-13 Change:
- Removed pclint warnings
- Updated header to new version
2015-07-16 Change:
- Adapted to new APIHeader directory and MarshallerFrame.h
2013-05-06 Bugfix:
- ACK's or zero length packets, may be send with a checksum (!=0)
2010-06-07 Change:
- Re-Added Tx buffers, which were never unused in Packet Transport (on rcX)
- Added ulTxBufferSize / ulTxBufferSize on connector registration to setup
Tx Buffer usage (if needed)
2009-09-23 Change:
- Removed unused Tx buffers and doubled number of Rx buffers to avoid resource errors without increasing memory footprint.
2009-09-22 Addon:
- Added HilMarshallerSetMode(), mode evaluation in HilMarshallerConnRxData().
2009-09-04 Bugfix:
- Do not discard "superfluous" data on reception of a transport ACK from the host. Instead, start a new receive cycle.
2009-09-02 Change:
- HilMarshallerMain() returns TLR_E_FAIL if no message can be retrieved from the pending requests list.
2009-09-01 Bugfix:
- Removed redundant calls to OS_FREE() following call to HilMarshallerStop() after failure in HilMarshallerStart().
2009-08-26 Change:
- Use HilMarshallerGetBuffer() and HilMarshallerFreeBuffer() in SendAcknowledge() instead of STAILQ_xxx macros.
2009-08-25 Bugfix:
- No need to perform buffer handling in case of incoming Tx Ack.
2009-08-19 Bugfixes:
- Corrected calculation of the used buffer length for a QUERYSERVER response.
- Zero ulActualSendOffset when allocating buffer.
2009-08-13 Bugfix:
- Set fAnswer flag to trigger response transmission also for regular Keep Alive message.
2009-08-06 Bugfix:
- Changed creation of the QUERYSERVER response to be in line with the specification.
2009-08-04 Bugfix:
- Keep Alive response: Prevent buffer from being freed by ResetRxStateMachine() while not transmitted completely.
2009-07-28 Change:
- Moved Marshaller version constants to MarshallerVersion.h
2009-07-21 Bugfix:
- Need to initialize Connectors before Transports because
Transport initialization uses Connector data
2009-06-02 Bugfix:
- Buffer handling for Connectors with Idx > 0 did not work
(Connectors will run out of buffers)
2009-05-25 initial version
**************************************************************************************/
/*****************************************************************************/
/*! \file HilMarshaller.c
* netX Marshaller implementation */
/*****************************************************************************/
#include "OS_Dependent.h"
#include "MarshallerConfig.h"
#include "MarshallerInternal.h"
#include "MarshallerFrame.h"
#include "MarshallerVersion.h"
#ifndef min
#define min(a,b) ((a > b)? b : a)
#endif
/*****************************************************************************/
/*! \addtogroup NETX_MARSHALLER_MAIN
* \{ */
/*****************************************************************************/
/*****************************************************************************/
/*! Calculate CCITT/ITU CRC-16 checksum.
* Polynomial : x^16 + x^12 + x^5 + 1 (0x1021)
* Start value : 0xFFFF
* Result : XORed with 0xFFFF
* \param pbData Buffer to calculate CRC for
* \param ulDataLength Length of buffer
* \return CRC-16 checksum */
/*****************************************************************************/
static uint16_t CalculateCRC16 (const uint8_t* pbData, uint32_t ulDataLength)
{
uint16_t usCRC;
uint32_t ulOffset;
usCRC = 0xFFFF;
if (pbData != NULL && ulDataLength > 0)
{ /* Buffer address and data length are valid. */
for (ulOffset = 0; ulOffset < ulDataLength; ++ulOffset)
{ /* Update CRC value for each byte in the buffer. */
usCRC = (uint16_t)((usCRC >> 8) | (usCRC << 8));
usCRC = (uint16_t)(usCRC ^ pbData[ulOffset]);
usCRC ^= (uint16_t)((usCRC & 0xFF) >> 4);
usCRC ^= (uint16_t)((usCRC << 8) << 4);
usCRC ^= (uint16_t)(((usCRC & 0xFF) << 4) << 1);
}
usCRC = (uint16_t) (~usCRC);
}
return (usCRC);
}
/*****************************************************************************/
/*! Allocates the requested data buffers and inserts them in free list
* of connector
* \param pvMarshaller Marshaller handle
* \param ptConnector Connector to allocate buffers for
* \param ulRxBufferCnt Number of buffers to allocate (equals number of parallel services)
* \param ulRxBufferSize Size of the buffers in bytes
* \param ulTxBufferCnt Number of transmit buffers to allocate (for unsolicited/indication data)
* \param ulTxBufferSize Size of the transmit buffers in bytes
* \return true on success */
/*****************************************************************************/
static bool AllocateBuffers(void* pvMarshaller, CONNECTOR_DATA_T* ptConnector, uint32_t ulRxBufferCnt, uint32_t ulRxBufferSize, uint32_t ulTxBufferCnt, uint32_t ulTxBufferSize)
{
uint32_t ulIdx;
bool fRet = true;
STAILQ_INIT(&ptConnector->tRxBuffer);
STAILQ_INIT(&ptConnector->tTxBuffer);
STAILQ_INIT(&ptConnector->tAckBuffer);
STAILQ_INIT(&ptConnector->tKeepAliveBuffer);
/* Use twice the number of requested data buffers for Rx data,
to make sure we have some reserve in case a buffer has not yet been released after the confirmation has been sent */
for(ulIdx = 0; ulIdx < ulRxBufferCnt; ++ulIdx)
{
HIL_MARSHALLER_BUFFER_T* ptBuffer;
if(NULL == (ptBuffer = OS_Malloc((uint32_t)sizeof(*ptBuffer) + ulRxBufferSize)))
{
fRet = false;
break;
} else
{
ptBuffer->tMgmt.ulConnectorIdx = ptConnector->ulConnectorIdx;
ptBuffer->tMgmt.pvMarshaller = pvMarshaller;
ptBuffer->tMgmt.ulDataBufferLen = ulRxBufferSize;
ptBuffer->tMgmt.eType = eMARSHALLER_RX_BUFFER;
ptBuffer->tMgmt.ulUsedDataBufferLen = 0;
/* Enqueue in linked list */
STAILQ_INSERT_TAIL(&ptConnector->tRxBuffer, ptBuffer, tList);
}
}
for(ulIdx = 0; ulIdx < ulTxBufferCnt; ++ulIdx)
{
HIL_MARSHALLER_BUFFER_T* ptBuffer;
if(NULL == (ptBuffer = OS_Malloc((uint32_t)sizeof(*ptBuffer) + ulTxBufferSize)))
{
fRet = false;
break;
} else
{
ptBuffer->tMgmt.ulConnectorIdx = ptConnector->ulConnectorIdx;
ptBuffer->tMgmt.pvMarshaller = pvMarshaller;
ptBuffer->tMgmt.ulDataBufferLen = ulTxBufferSize;
ptBuffer->tMgmt.eType = eMARSHALLER_TX_BUFFER;
ptBuffer->tMgmt.ulUsedDataBufferLen = 0;
/* Enqueue in linked list */
STAILQ_INSERT_TAIL(&ptConnector->tTxBuffer, ptBuffer, tList);
}
}
/* Use one additional Buffer per direction for acknowledgement,
to make sure we can answer while we don't have databuffers
ready (number of parallel services exceeded) */
for(ulIdx = 0; ulIdx < ulRxBufferCnt + ulTxBufferCnt + 2; ++ulIdx)
{
HIL_MARSHALLER_BUFFER_T* ptBuffer;
if(NULL == (ptBuffer = OS_Malloc(sizeof(*ptBuffer))))
{
fRet = false;
break;
} else
{
ptBuffer->tMgmt.ulConnectorIdx = ptConnector->ulConnectorIdx;
ptBuffer->tMgmt.pvMarshaller = pvMarshaller;
ptBuffer->tMgmt.ulDataBufferLen = 0;
ptBuffer->tMgmt.eType = eMARSHALLER_ACK_BUFFER;
ptBuffer->tMgmt.ulUsedDataBufferLen = 0;
/* Enqueue in linked list */
STAILQ_INSERT_TAIL(&ptConnector->tAckBuffer, ptBuffer, tList);
}
}
if(fRet)
{
HIL_MARSHALLER_BUFFER_T* ptBuffer;
if(NULL == (ptBuffer = OS_Malloc(sizeof(*ptBuffer) + sizeof(HIL_TRANSPORT_KEEPALIVE_DATA_T))))
{
fRet = false;
} else
{
ptBuffer->tMgmt.ulConnectorIdx = ptConnector->ulConnectorIdx;
ptBuffer->tMgmt.pvMarshaller = pvMarshaller;
ptBuffer->tMgmt.ulDataBufferLen = sizeof(HIL_TRANSPORT_KEEPALIVE_DATA_T);
ptBuffer->tMgmt.eType = eMARSHALLER_KEEPALIVE_BUFFER;
ptBuffer->tMgmt.ulUsedDataBufferLen = 0;
/* Enqueue in linked list */
STAILQ_INSERT_TAIL(&ptConnector->tKeepAliveBuffer, ptBuffer, tList);
}
}
return fRet;
}
/*****************************************************************************/
/*! Deallocates all data buffers from a connector
* \param pvMarshaller Marshaller handle
* \param ptConnector Connector to free buffers for */
/*****************************************************************************/
static void DeAllocateBuffers(void* pvMarshaller, CONNECTOR_DATA_T* ptConnector)
{
/* Deallocate all buffers in linked lists */
HIL_MARSHALLER_BUFFER_T* ptBuffer;
while(NULL != (ptBuffer = STAILQ_FIRST(&ptConnector->tAckBuffer)))
{
STAILQ_REMOVE(&ptConnector->tAckBuffer, ptBuffer, HIL_MARSHALLER_BUFFER_Ttag, tList);
OS_Free(ptBuffer);
}
while(NULL != (ptBuffer = STAILQ_FIRST(&ptConnector->tRxBuffer)))
{
STAILQ_REMOVE(&ptConnector->tRxBuffer, ptBuffer, HIL_MARSHALLER_BUFFER_Ttag, tList);
OS_Free(ptBuffer);
}
while(NULL != (ptBuffer = STAILQ_FIRST(&ptConnector->tTxBuffer)))
{
STAILQ_REMOVE(&ptConnector->tTxBuffer, ptBuffer, HIL_MARSHALLER_BUFFER_Ttag, tList);
OS_Free(ptBuffer);
}
while(NULL != (ptBuffer = STAILQ_FIRST(&ptConnector->tKeepAliveBuffer)))
{
STAILQ_REMOVE(&ptConnector->tKeepAliveBuffer, ptBuffer, HIL_MARSHALLER_BUFFER_Ttag, tList);
OS_Free(ptBuffer);
}
}
/*****************************************************************************/
/*! Free a buffer
* \param ptBuffer Buffer to free */
/*****************************************************************************/
void HilMarshallerFreeBuffer(HIL_MARSHALLER_BUFFER_T* ptBuffer)
{
HIL_MARSHALLER_DATA_T* ptMarshaller = (HIL_MARSHALLER_DATA_T*)ptBuffer->tMgmt.pvMarshaller;
CONNECTOR_DATA_T* ptConn = &ptMarshaller->atConnectors[ptBuffer->tMgmt.ulConnectorIdx];
int iLock;
ptBuffer->tMgmt.ulUsedDataBufferLen = 0;
iLock = OS_Lock();
switch(ptBuffer->tMgmt.eType)
{
case eMARSHALLER_KEEPALIVE_BUFFER:
STAILQ_INSERT_TAIL(&ptConn->tKeepAliveBuffer, ptBuffer, tList);
break;
case eMARSHALLER_ACK_BUFFER:
STAILQ_INSERT_TAIL(&ptConn->tAckBuffer, ptBuffer, tList);
break;
case eMARSHALLER_RX_BUFFER:
STAILQ_INSERT_TAIL(&ptConn->tRxBuffer, ptBuffer, tList);
break;
case eMARSHALLER_TX_BUFFER:
STAILQ_INSERT_TAIL(&ptConn->tTxBuffer, ptBuffer, tList);
break;
default:
/* NOTE: This should never happen, only if someone free's a wrong buffer,
or destroyed the buffer management area (programming error). */
ptConn = ptConn;
break;
}
OS_Unlock(iLock);
} /*lint !e438 : Last value assigned to variable 'ptConn' (defined at line 276) not used */
/*****************************************************************************/
/*! Get a buffer for incoming data from connector
* \param pvMarshaller Marshaller handle
* \param eType Type of buffer to acquire
* \param ulConnector Connector index
* \return NULL if no buffer is available, valid buffer otherwise */
/*****************************************************************************/
HIL_MARSHALLER_BUFFER_T* HilMarshallerGetBuffer(void* pvMarshaller, MARSHALLER_BUFFER_TYPE_E eType, uint32_t ulConnector)
{
HIL_MARSHALLER_DATA_T* ptMarshaller = (HIL_MARSHALLER_DATA_T*)pvMarshaller;
CONNECTOR_DATA_T* ptConn = &ptMarshaller->atConnectors[ulConnector];
HIL_MARSHALLER_BUFFER_T* ptBuffer = NULL;
struct MARSHALLER_BUFFER_HEAD* ptListHead = NULL;
int iLock;
switch(eType)
{
case eMARSHALLER_RX_BUFFER:
ptListHead = &ptConn->tRxBuffer;
break;
case eMARSHALLER_TX_BUFFER:
ptListHead = &ptConn->tTxBuffer;
break;
case eMARSHALLER_ACK_BUFFER:
ptListHead = &ptConn->tAckBuffer;
break;
case eMARSHALLER_KEEPALIVE_BUFFER:
ptListHead = &ptConn->tKeepAliveBuffer;
break;
default:
/* NOTE: This should never happen, only if someone free's a wrong buffer,
or destroyed the buffer management area (programming error). */
break;
}
iLock = OS_Lock();
if( (NULL != ptListHead) &&
(NULL != (ptBuffer = STAILQ_FIRST(ptListHead))) )
{
STAILQ_REMOVE(ptListHead, ptBuffer, HIL_MARSHALLER_BUFFER_Ttag, tList);
ptBuffer->tMgmt.ulActualSendOffset = 0;
ptBuffer->tMgmt.ulUsedDataBufferLen = 0;
}
OS_Unlock(iLock);
return ptBuffer;
}
/*****************************************************************************/
/*! Find a transport layer which can handle the requested data type
* \param ptMarshaller Marshaller handle
* \param usDataType Datatype the transport layer is requested for
* \return NULL if no transport is available, valid transport otherwise */
/*****************************************************************************/
static TRANSPORT_LAYER_DATA_T* FindTransportLayer(const HIL_MARSHALLER_DATA_T* ptMarshaller, const uint16_t usDataType)
{
TRANSPORT_LAYER_DATA_T* ptRet = NULL;
uint32_t ulIdx;
for(ulIdx = 0; ulIdx < ptMarshaller->ulTransports; ++ulIdx)
{
if(usDataType == ptMarshaller->ptTransports[ulIdx].usDataType)
{
ptRet = &ptMarshaller->ptTransports[ulIdx];
break;
}
}
return ptRet;
}
/*****************************************************************************/
/*! Send an HIL Transport acknowledge
* \param ptMarshaller Marshaller handle
* \param ulConnector Connector to send ACK to
* \param ptHeader Header of incoming packet
* \param bState State to set in acknowledge */
/*****************************************************************************/
static void SendAcknowledge(HIL_MARSHALLER_DATA_T* ptMarshaller, uint32_t ulConnector, HIL_TRANSPORT_HEADER* ptHeader, unsigned char bState)
{
HIL_MARSHALLER_BUFFER_T* ptBuffer;
/* If we don't get a buffer, the number of parallel services is exceeded.
This is a host error, as it is sending data too fast and we are not able to do any acknowledge */
ptBuffer = HilMarshallerGetBuffer(ptMarshaller, eMARSHALLER_ACK_BUFFER, ulConnector);
if(NULL != ptBuffer)
{
ptBuffer->tTransport = *ptHeader;
ptBuffer->tTransport.bState = bState;
ptBuffer->tTransport.usDataType = HIL_TRANSPORT_TYPE_ACKNOWLEDGE;
ptBuffer->tMgmt.ulUsedDataBufferLen = 0;
if(HIL_MARSHALLER_E_SUCCESS != HilMarshallerConnTxData(ptMarshaller, ulConnector, ptBuffer))
{
/* Internal error, this should never happen, but if it happens, we need to free the Ack buffer again */
HilMarshallerFreeBuffer(ptBuffer);
}
}
}
/*****************************************************************************/
/*! Reset internal connector receive state machine
* \param ptConnector Connector to reset */
/*****************************************************************************/
static void ResetRxStateMachine(CONNECTOR_DATA_T* ptConnector)
{
if((ptConnector->eScanState != HIL_SEARCH_TELEGRAM_COOKIE) &&
(ptConnector->eScanState != HIL_SCAN_DONE) )
{
ptConnector->eScanState = ptConnector->eScanState;
}
ptConnector->fMonitorTimeout = false;
ptConnector->ulElapsedTime = 0;
ptConnector->tRxHeader.ulCookie = 0;
ptConnector->ulRxOffset = 0;
if(NULL != ptConnector->ptCurrentRxBuffer)
{
HilMarshallerFreeBuffer(ptConnector->ptCurrentRxBuffer);
}
ptConnector->ptCurrentRxBuffer = NULL;
ptConnector->eScanState = HIL_SEARCH_TELEGRAM_COOKIE;
}
/*****************************************************************************/
/*! Startup marshaller
* \param ptParams Marshaller parameters
* \param ppvMarshHandle Returned Marshaller handle
* \param pfnRequest Function to call, when MarshallerMain should be called
* \param pvUser User parameter to pass on pfnRequest call
* \return HIL_MARSHALLER_E_SUCCESS on success */
/*****************************************************************************/
uint32_t HilMarshallerStart(const HIL_MARSHALLER_PARAMS_T* ptParams, void** ppvMarshHandle, PFN_MARSHALLER_REQUEST pfnRequest, void* pvUser)
{
uint32_t eRet = HIL_MARSHALLER_E_SUCCESS;
HIL_MARSHALLER_DATA_T* ptMarshaller = NULL;
uint32_t ulIdx = 0;
const TRANSPORT_LAYER_CONFIG_T* ptTransport = NULL;
const HIL_MARSHALLER_CONNECTOR_PARAMS_T* ptConnParams = NULL;
if(NULL == ppvMarshHandle)
eRet = HIL_MARSHALLER_E_INVALIDPARAMETER;
else
{
*ppvMarshHandle = NULL;
if (NULL == (ptMarshaller = OS_Malloc(sizeof(*ptMarshaller))))
eRet = HIL_MARSHALLER_E_OUTOFMEMORY;
else
{
OS_Memset( ptMarshaller, 0, sizeof(*ptMarshaller));
STAILQ_INIT(&ptMarshaller->tPendingRequests);
ptMarshaller->pfnRequest = pfnRequest;
ptMarshaller->pvUser = pvUser;
ptMarshaller->ulMaxConnectors = ptParams->ulMaxConnectors;
ptMarshaller->ulTransports = ptParams->ulTransportCnt;
OS_Memcpy(ptMarshaller->szServerName, (void*)ptParams->szServerName, sizeof(ptMarshaller->szServerName));
if(NULL == (ptMarshaller->atConnectors = OS_Malloc(ptParams->ulMaxConnectors * (uint32_t)sizeof(CONNECTOR_DATA_T))))
eRet = HIL_MARSHALLER_E_OUTOFMEMORY;
else
{
OS_Memset(ptMarshaller->atConnectors, 0, ptParams->ulMaxConnectors * sizeof(CONNECTOR_DATA_T));
if(NULL == (ptMarshaller->ptTransports = OS_Malloc(ptParams->ulTransportCnt * (uint32_t)sizeof(TRANSPORT_LAYER_DATA_T))))
eRet = HIL_MARSHALLER_E_OUTOFMEMORY;
else
{
OS_Memset(ptMarshaller->ptTransports, 0, ptParams->ulTransportCnt * sizeof(TRANSPORT_LAYER_DATA_T));
for(ulIdx = 0; eRet == HIL_MARSHALLER_E_SUCCESS && ulIdx < ptParams->ulConnectorCnt; ++ulIdx)
{
ptConnParams = &ptParams->ptConnectors[ulIdx];
if(ptConnParams->pfnConnectorInit)
eRet = ptConnParams->pfnConnectorInit(ptConnParams, ptMarshaller);
}
for(ulIdx = 0; eRet == HIL_MARSHALLER_E_SUCCESS && ulIdx < ptParams->ulTransportCnt; ++ulIdx)
{
ptTransport = &ptParams->atTransports[ulIdx];
if(ptTransport->pfnInit)
eRet = ptTransport->pfnInit(ptMarshaller, ptTransport->pvConfig);
}
}
}
}
if(HIL_MARSHALLER_E_SUCCESS == eRet)
*ppvMarshHandle = ptMarshaller;
else
HilMarshallerStop(ptMarshaller);
}
return eRet; /*lint !e593 : 'ptMarshaller' possibly not freed or returned */
}
/*****************************************************************************/
/*! Stop marshaller
* \param pvMarshHandle Marshaller handle */
/*****************************************************************************/
void HilMarshallerStop(void* pvMarshHandle)
{
HIL_MARSHALLER_DATA_T* ptMarshaller = (HIL_MARSHALLER_DATA_T*)pvMarshHandle;
if(NULL != ptMarshaller)
{
if(NULL != ptMarshaller->ptTransports)
{
uint32_t ulTrans;
for(ulTrans = 0; ulTrans < ptMarshaller->ulTransports; ++ulTrans)
{
TRANSPORT_LAYER_DATA_T* ptTransport = &ptMarshaller->ptTransports[ulTrans];
if(ptTransport->pfnDeinit)
{
ptTransport->pfnDeinit(ptTransport->pvUser);
}
}
OS_Free(ptMarshaller->ptTransports);
ptMarshaller->ptTransports = NULL;
}
if(NULL != ptMarshaller->atConnectors)
{
uint32_t ulConn;
for(ulConn = 0; ulConn < ptMarshaller->ulMaxConnectors; ++ulConn)
{
CONNECTOR_DATA_T* ptConn = &ptMarshaller->atConnectors[ulConn];
if(ptConn->fInUse)
{
ptConn->tConn.pfnDeinit(ptConn->tConn.pvUser);
}
}
OS_Free(ptMarshaller->atConnectors);
ptMarshaller->atConnectors = NULL;
}
OS_Free(ptMarshaller);
}
}
/*****************************************************************************/
/*! Register a connector at marshaller
* \param pvMarshaller Marshaller handle
* \param pulConnectorIdx Returned connector number
* \param ptConn Connector data
* \return HIL_MARSHALLER_E_SUCCESS on success */
/*****************************************************************************/
uint32_t HilMarshallerRegisterConnector(void* pvMarshaller, uint32_t* pulConnectorIdx, HIL_MARSHALLER_CONNECTOR_T* ptConn)
{
HIL_MARSHALLER_DATA_T* ptMarshaller = (HIL_MARSHALLER_DATA_T*)pvMarshaller;
uint32_t eRet = HIL_MARSHALLER_E_SUCCESS;
CONNECTOR_DATA_T* ptConnectorData = NULL;
uint32_t ulConnIdx;
/* Search free connector space */
for(ulConnIdx = 0; ulConnIdx < ptMarshaller->ulMaxConnectors; ++ulConnIdx)
{
if(!ptMarshaller->atConnectors[ulConnIdx].fInUse)
{
ptConnectorData = &ptMarshaller->atConnectors[ulConnIdx];
ptConnectorData->ulConnectorIdx = ulConnIdx;
break;
}
}
if(NULL == ptConnectorData)
{
/* No more connectors allowed */
eRet = HIL_MARSHALLER_E_OUTOFRESOURCES;
} else if(!AllocateBuffers(pvMarshaller,
ptConnectorData,
ptConn->ulDataBufferCnt,
ptConn->ulDataBufferSize,
ptConn->ulTxBufferCnt,
ptConn->ulTxBufferSize))
{
/* Out of memory */
eRet = HIL_MARSHALLER_E_OUTOFMEMORY;
} else
{
/* Initialize RX state machine */
ResetRxStateMachine(ptConnectorData);
/* Initialize conector data */
ptConnectorData->fInUse = true;
ptConnectorData->tConn = *ptConn;
*pulConnectorIdx = ulConnIdx;
}
return eRet;
}
/*****************************************************************************/
/*! Unregister a connector at marshaller
* \param pvMarshaller Marshaller handle
* \param ulConnectorIdx Connector number */
/*****************************************************************************/
void HilMarshallerUnregisterConnector(void* pvMarshaller, uint32_t ulConnectorIdx)
{
HIL_MARSHALLER_DATA_T* ptMarshaller = (HIL_MARSHALLER_DATA_T*)pvMarshaller;
if(ulConnectorIdx < ptMarshaller->ulMaxConnectors)
{
CONNECTOR_DATA_T* ptConnectorData = &ptMarshaller->atConnectors[ulConnectorIdx];
DeAllocateBuffers(pvMarshaller,
ptConnectorData);
ptConnectorData->fInUse = false;
OS_Memset(&ptConnectorData->tConn, 0, sizeof(ptConnectorData->tConn));
}
}
/*****************************************************************************/
/*! Called by connector when new data has arrived
* \param pvMarshaller Marshaller handle
* \param ulConnector Connector number
* \param pbData Incoming data
* \param ulDataCnt Number of bytes in incoming data buffer
* \return HIL_MARSHALLER_E_SUCCESS on success */
/*****************************************************************************/
uint32_t HilMarshallerConnRxData(void* pvMarshaller, uint32_t ulConnector, uint8_t* pbData, uint32_t ulDataCnt)
{
HIL_MARSHALLER_DATA_T* ptMarshaller = (HIL_MARSHALLER_DATA_T*)pvMarshaller;
uint32_t eRet = HIL_MARSHALLER_E_INVALIDPARAMETER;
if (ulConnector < ptMarshaller->ulMaxConnectors
&& ptMarshaller->atConnectors[ulConnector].ulMode != HIL_MARSHALLER_MODE_DISABLED)
{
CONNECTOR_DATA_T* ptConnector = &ptMarshaller->atConnectors[ulConnector];
int fDone = 0; /* Leave handler */
uint32_t ulRxDataIdx = 0;
eRet = HIL_MARSHALLER_E_SUCCESS;
ptConnector->ulElapsedTime = 0; /* Reschedule timeout handling */
/*-----------------------------------------*/
/* Start scanning of the input data */
/*-----------------------------------------*/
do
{
switch(ptConnector->eScanState)
{
case HIL_SEARCH_TELEGRAM_COOKIE:
{
/* Parse input buffer */
unsigned char* pabCookie = (unsigned char*)&ptConnector->tRxHeader.ulCookie;
for ( ulRxDataIdx = 0; ulRxDataIdx < ulDataCnt; ulRxDataIdx++)
{
pabCookie[ptConnector->ulRxOffset] = pbData[ulRxDataIdx];
if( ++ptConnector->ulRxOffset >= sizeof(ptConnector->tRxHeader.ulCookie))
{
/* Check if we have a complete cookie */
if( HIL_TRANSPORT_COOKIE == ptConnector->tRxHeader.ulCookie)
{
/* Yes, store the cookie in the header */
ulDataCnt = ulDataCnt - (ulRxDataIdx + 1);
pbData = &pbData[ulRxDataIdx + 1];
/* Set next state */
ptConnector->eScanState = HIL_SEARCH_TELEGRAM_HEADER;
ptConnector->fMonitorTimeout = true;
break;
}else
{
/* Still no cookie, move the data and insert next character. */
/* Set cookie buffer index to next insertable character. */
memmove(pabCookie, &pabCookie[1], 3);
ptConnector->ulRxOffset = 3;
}
}
}
if( HIL_SEARCH_TELEGRAM_COOKIE == ptConnector->eScanState)
fDone = 1;
break;
}
case HIL_SEARCH_TELEGRAM_HEADER:
{
/* We searching a telegram header, cookie is already available */
/* Check if we have more date */
if ( 0 == ulDataCnt)
{
fDone = 1;
} else
{
/* Append at least the header length if available */
uint32_t ulCopyLength = 0;
unsigned char* pbHeader = (unsigned char*)&ptConnector->tRxHeader;
ulCopyLength = min(ulDataCnt,
(sizeof(HIL_TRANSPORT_HEADER) - ptConnector->ulRxOffset));
OS_Memcpy( &pbHeader[ptConnector->ulRxOffset],
pbData,
ulCopyLength);
ptConnector->ulRxOffset += ulCopyLength;
/* Check if we have more data */
if(ptConnector->ulRxOffset < sizeof(HIL_TRANSPORT_HEADER))
{
/* We need more data */
fDone = 1;
} else if (HIL_TRANSPORT_TYPE_ACKNOWLEDGE == ptConnector->tRxHeader.usDataType)
{
/* Update the Rx data count and Rx data pointer for handling the remaining bytes */
ulDataCnt -= ulCopyLength;
pbData = &pbData[ulCopyLength];
ptConnector->ptCurrentRxBuffer = NULL;
ResetRxStateMachine(ptConnector);
/* If there are bytes left, start a new cookie search using these bytes. Otherwise terminate the receive cycle. */
if (ulDataCnt == 0)
fDone = 1;
break;
} else
{
/* We need a buffer */
HIL_MARSHALLER_BUFFER_T* ptBuffer;
if(HIL_TRANSPORT_TYPE_KEEP_ALIVE == ptConnector->tRxHeader.usDataType)
{
ptBuffer = HilMarshallerGetBuffer(ptMarshaller, eMARSHALLER_KEEPALIVE_BUFFER, ulConnector);
} else
{
ptBuffer = HilMarshallerGetBuffer(ptMarshaller, eMARSHALLER_RX_BUFFER, ulConnector);
}
if(NULL == ptBuffer)
{
/* Send negative Ack */
SendAcknowledge(ptMarshaller, ulConnector, &ptConnector->tRxHeader, HIL_TSTATE_RESOURCE_ERROR);
ResetRxStateMachine(ptConnector);
} else if(ptBuffer->tMgmt.ulDataBufferLen < ptConnector->tRxHeader.ulLength)
{
/* Send negative ACK (telegram too long for buffer) */
SendAcknowledge(ptMarshaller, ulConnector, &ptConnector->tRxHeader, HIL_TSTATE_BUFFEROVERFLOW_ERROR);
/* Release Buffer */
HilMarshallerFreeBuffer(ptBuffer);
ResetRxStateMachine(ptConnector);
} else
{
/* We have a complete Header, wait for packet data complete */
ulDataCnt -= ulCopyLength;
pbData = &pbData[ulCopyLength];
/* Store header */
ptBuffer->tTransport = ptConnector->tRxHeader;
ptBuffer->tMgmt.ulUsedDataBufferLen = 0; /* Set actual telegram data length */
/* Set next scanner state */
ptConnector->ptCurrentRxBuffer = ptBuffer;
ptConnector->eScanState = HIL_WAIT_TELEGRAM_DATA;
}
}
}
}
break;
case HIL_WAIT_TELEGRAM_DATA:
{
/* We waiting for telegram data, wait until all data are available */
uint32_t ulCopyLen = 0;
HIL_TRANSPORT_HEADER* ptHeader = &ptConnector->ptCurrentRxBuffer->tTransport;
uint32_t ulDataOffset = ptConnector->ulRxOffset - (uint32_t)sizeof(HIL_TRANSPORT_HEADER);
if(0 == ptHeader->ulLength)
{
/* We have all data */
ptConnector->eScanState = HIL_CHECK_TELEGRAM;
/* We have packet data, wait until all data are available */
} else if(0 != ulDataCnt)
{
HIL_MARSHALLER_BUFFER_T* ptBuffer = ptConnector->ptCurrentRxBuffer;
/* Check if all data must be copied or if we have more data than necessary */
ulCopyLen = ulDataCnt;
if( (ulDataCnt + ulDataOffset) > ptHeader->ulLength)
{
/* Just copy the necessary data and keep the rest for a new cookie ssearch */
ulCopyLen = ptHeader->ulLength - ulDataOffset;
}
OS_Memcpy(&ptBuffer->abData[ulDataOffset], pbData, ulCopyLen);
ptConnector->ulRxOffset += ulCopyLen;
ptBuffer->tMgmt.ulUsedDataBufferLen += ulCopyLen;
}
if(ptConnector->ulRxOffset < (ptHeader->ulLength + sizeof(*ptHeader)))
{
/* We have to wait for more data */
fDone = 1;
} else
{
/* We have a complete telegram */
/* Check if we have data left */
ulDataCnt -= ulCopyLen;
pbData = &pbData[ulCopyLen];
/* We have all data */
ptConnector->eScanState = HIL_CHECK_TELEGRAM;
}
}
break;
case HIL_CHECK_TELEGRAM:
{
HIL_TRANSPORT_HEADER* ptHeader = &ptConnector->ptCurrentRxBuffer->tTransport;
HIL_MARSHALLER_BUFFER_T* ptBuffer = ptConnector->ptCurrentRxBuffer;
if( (ptHeader->ulLength > 0) &&
(ptHeader->usChecksum != 0) &&
(ptHeader->usChecksum != CalculateCRC16(ptBuffer->abData,
ptConnector->tRxHeader.ulLength)) )
{
SendAcknowledge(ptMarshaller, ulConnector, &ptConnector->tRxHeader, HIL_TSTATE_CHECKSUM_ERROR);
} else
{
/* We have a complete telegram */
/* Check for Acknowledge */
switch(ptHeader->usDataType)
{
case HIL_TRANSPORT_TYPE_ACKNOWLEDGE:
break;
case HIL_TRANSPORT_TYPE_QUERYSERVER:
{
if(NULL == ptBuffer)
ptBuffer = HilMarshallerGetBuffer(pvMarshaller, eMARSHALLER_TX_BUFFER, ulConnector);
if(NULL == ptBuffer)
{
SendAcknowledge(ptMarshaller, ulConnector, &ptConnector->tRxHeader, HIL_TSTATE_RESOURCE_ERROR);
} else
{
PHIL_TRANSPORT_ADMIN_QUERYSERVER_DATA_T ptServerData = (PHIL_TRANSPORT_ADMIN_QUERYSERVER_DATA_T)ptBuffer->abData;
uint32_t ulIdx;
SendAcknowledge(ptMarshaller, ulConnector, &ptConnector->tRxHeader, HIL_TRANSPORT_STATE_OK);
/* Fill in data */
ptBuffer->tTransport = ptConnector->ptCurrentRxBuffer->tTransport;
ptServerData->ulStructVersion = 1;
OS_Memcpy(ptServerData->szServerName, ptMarshaller->szServerName, sizeof(ptServerData->szServerName));
ptServerData->ulVersionMajor = MARSHALLER_VERSION_MAJOR;
ptServerData->ulVersionMinor = MARSHALLER_VERSION_MINOR;
ptServerData->ulVersionBuild = MARSHALLER_VERSION_BUILD;
ptServerData->ulVersionRevision = MARSHALLER_VERSION_REVISION;
#if defined(HIL_MARSHALLER_PERMANENT_CONNECTION)
ptServerData->ulFeatures = HIL_TRANSPORT_FEATURES_KEEPALIVE |
HIL_TRANSPORT_FEATURES_PERMANENT_CONNECTION;
#else
ptServerData->ulFeatures = HIL_TRANSPORT_FEATURES_KEEPALIVE;
#endif
ptServerData->ulParallelServices = ptConnector->tConn.ulDataBufferCnt;
ptServerData->ulBufferSize = ptConnector->tConn.ulDataBufferSize;
ptServerData->ulDatatypeCnt = ptMarshaller->ulTransports;
for(ulIdx = 0; ulIdx < ptMarshaller->ulTransports; ++ulIdx)
ptServerData->ausDataTypes[ulIdx] = ptMarshaller->ptTransports[ulIdx].usDataType;
/* Add the Keep Alive transport type to the list. */
ptServerData->ausDataTypes[ulIdx] = HIL_TRANSPORT_TYPE_KEEP_ALIVE; /*lint !e661 : see declaration of ptServerData */
ptServerData->ulDatatypeCnt++;
/* Calculate the actual response data length. */
ptBuffer->tMgmt.ulUsedDataBufferLen = (uint32_t)((uint8_t*) ptServerData->ausDataTypes - (uint8_t*) ptServerData
+ (ptServerData->ulDatatypeCnt) * sizeof (ptServerData->ausDataTypes[0]));
if(HIL_MARSHALLER_E_SUCCESS != HilMarshallerConnTxData(pvMarshaller,
ulConnector,
ptBuffer))
{
HilMarshallerFreeBuffer(ptBuffer);
ptConnector->ptCurrentRxBuffer = NULL;
} else
{
/* Prevent buffer from being freed by ResetRxStateMachine() while not transmitted completely. */
ptConnector->ptCurrentRxBuffer = NULL;
}
}
}
break;
/*TODO: Implement Administration commands (QUERY_DEVICE) */
case HIL_TRANSPORT_TYPE_KEEP_ALIVE:
{
PHIL_TRANSPORT_KEEPALIVE_DATA_T ptKeepAlive = (PHIL_TRANSPORT_KEEPALIVE_DATA_T)ptConnector->ptCurrentRxBuffer->abData;
unsigned char bState = HIL_TRANSPORT_STATE_OK;
bool fSendAnswer = false;
if(ptHeader->ulLength != sizeof(*ptKeepAlive))
{
/* Illegal length of keepalive packet */
bState = HIL_TSTATE_LENGTH_INCOMPLETE;
} else if(0 == ptKeepAlive->ulComID)
{
/* New Keepalive ID requested */
uint32_t ulNewId = OS_GetTickCount();
if(0 == ulNewId)
++ptConnector->ulKeepaliveID;
if(ulNewId == ptConnector->ulKeepaliveID)
{
ptConnector->ulKeepaliveID = ~ulNewId;
} else
{
ptConnector->ulKeepaliveID = ulNewId;
}
ptKeepAlive->ulComID = ptConnector->ulKeepaliveID;
fSendAnswer = true;
} else if(ptKeepAlive->ulComID != ptConnector->ulKeepaliveID)
{
/* ComID does not match, so just return a negative Acknowledge */
bState = HIL_TSTATE_KEEP_ALIVE_ERROR;
} else
{
/* Everything is fine */
ptKeepAlive->ulComID = ptConnector->ulKeepaliveID;
fSendAnswer = true;
bState = HIL_TRANSPORT_STATE_OK;
}
SendAcknowledge(ptMarshaller, ulConnector, &ptConnector->tRxHeader, bState);
if(!fSendAnswer)
{
HilMarshallerFreeBuffer(ptConnector->ptCurrentRxBuffer);
ptConnector->ptCurrentRxBuffer = NULL;
} else if(HIL_MARSHALLER_E_SUCCESS != HilMarshallerConnTxData(pvMarshaller,
ulConnector,
ptConnector->ptCurrentRxBuffer))
{
HilMarshallerFreeBuffer(ptConnector->ptCurrentRxBuffer);
ptConnector->ptCurrentRxBuffer = NULL;
} else
{
/* Prevent buffer from being freed by ResetRxStateMachine() while not transmitted completely. */
ptConnector->ptCurrentRxBuffer = NULL;
}
}
break;
default:
{
TRANSPORT_LAYER_DATA_T* ptTransport = FindTransportLayer(ptMarshaller, ptHeader->usDataType);
if(NULL == ptTransport)
{
SendAcknowledge(ptMarshaller, ulConnector, &ptConnector->tRxHeader, HIL_TSTATE_DATA_TYPE_UNKNOWN);
HilMarshallerFreeBuffer(ptConnector->ptCurrentRxBuffer);
ptConnector->ptCurrentRxBuffer = NULL;
} else
{
int iLock;
SendAcknowledge(ptMarshaller, ulConnector, &ptConnector->tRxHeader, HIL_TRANSPORT_STATE_OK);
/* Enqueue this request into list, and let user handle it in it's own task
We need to set the current Rx Buffer to NULL, so that ResetRxStateMachine won't
free it. */
ptConnector->ptCurrentRxBuffer = NULL;
iLock = OS_Lock();
STAILQ_INSERT_TAIL(&ptMarshaller->tPendingRequests, ptBuffer, tList);
OS_Unlock(iLock);
ptMarshaller->pfnRequest(ptMarshaller, ptMarshaller->pvUser);
}
}
break;
}
}
/* Reset state machine */
ResetRxStateMachine(ptConnector);
/* Check if we have processed all incoming data */
if( 0 == ulDataCnt)
{
/* Start with scan for cookie */
fDone = 1;
}
}
break;
default:
;
break;
} /* end switch state */
} while (0 == fDone);
}
return eRet;
}
/*****************************************************************************/
/*! Called by transport when new data should be send to line
* \param pvMarshaller Marshaller handle
* \param ulConnector Connector number
* \param ptBuffer Outgoing data
* \return HIL_MARSHALLER_E_SUCCESS on success */
/*****************************************************************************/
uint32_t HilMarshallerConnTxData(void* pvMarshaller, uint32_t ulConnector, HIL_MARSHALLER_BUFFER_T* ptBuffer)
{
HIL_MARSHALLER_DATA_T* ptMarshaller = (HIL_MARSHALLER_DATA_T*)pvMarshaller;
CONNECTOR_DATA_T* ptConn = &ptMarshaller->atConnectors[ulConnector];
ptBuffer->tTransport.ulLength = ptBuffer->tMgmt.ulUsedDataBufferLen;
if(ptBuffer->tTransport.ulLength > 0)
{
ptBuffer->tTransport.usChecksum = CalculateCRC16(ptBuffer->abData,
ptBuffer->tTransport.ulLength);
} else
{
ptBuffer->tTransport.usChecksum = 0;
}
return ptConn->tConn.pfnTransmit(ptBuffer, ptConn->tConn.pvUser);
}
/*****************************************************************************/
/*! Called by connector data has been sent
* \param pvMarshaller Marshaller handle
* \param ulConnector Connector number
* \param ptBuffer Outgoing data buffer
* \return HIL_MARSHALLER_E_SUCCESS on success */
/*****************************************************************************/
uint32_t HilMarshallerConnTxComplete(void* pvMarshaller, uint32_t ulConnector, HIL_MARSHALLER_BUFFER_T* ptBuffer)
{
HilMarshallerFreeBuffer(ptBuffer);
return HIL_MARSHALLER_E_SUCCESS;
}
/*****************************************************************************/
/*! Called by transport layer, during initialization.
* \param pvMarshaller Marshaller handle
* \param ptLayerData Layer registration data
* \return HIL_MARSHALLER_E_SUCCESS on success */
/*****************************************************************************/
uint32_t HilMarshallerRegisterTransport(void* pvMarshaller, const TRANSPORT_LAYER_DATA_T* ptLayerData)
{
HIL_MARSHALLER_DATA_T* ptMarshaller = (HIL_MARSHALLER_DATA_T*)pvMarshaller;
uint32_t eRet;
if(0 == ptLayerData->usDataType)
{
eRet = HIL_MARSHALLER_E_INVALIDPARAMETER;
} else if(NULL != FindTransportLayer(ptMarshaller, ptLayerData->usDataType))
{
/* Another Transport layer is already registered for this datatype (configuration error) */
eRet = HIL_MARSHALLER_E_ALREADYREGISTERED;
} else
{
uint32_t ulIdx;
eRet = HIL_MARSHALLER_E_OUTOFRESOURCES;
/* Search first free array element */
for(ulIdx = 0; ulIdx < ptMarshaller->ulTransports; ++ulIdx)
{
TRANSPORT_LAYER_DATA_T* ptLayer = &ptMarshaller->ptTransports[ulIdx];
if(0 == ptLayer->usDataType)
{
*ptLayer = *ptLayerData;
eRet = HIL_MARSHALLER_E_SUCCESS;
break;
}
}
}
return eRet;
}
/*****************************************************************************/
/*! Called by transport layer, during uninitialization.
* \param pvMarshaller Marshaller handle
* \param usDataType Datatype the layer was registered at */
/*****************************************************************************/
void HilMarshallerUnregisterTransport(void* pvMarshaller, uint16_t usDataType)
{
HIL_MARSHALLER_DATA_T* ptMarshaller = (HIL_MARSHALLER_DATA_T*)pvMarshaller;
TRANSPORT_LAYER_DATA_T* ptLayer = FindTransportLayer(ptMarshaller, usDataType);
if(ptLayer != NULL)
{
OS_Memset(ptLayer, 0, sizeof(*ptLayer));
}
}
/*****************************************************************************/
/*! Cyclic timer event, which needs to be called by user for timeout management
* \param pvMarshaller Marshaller handle */
/*****************************************************************************/
void HilMarshallerTimer(void* pvMarshaller)
{
uint32_t ulIdx;
HIL_MARSHALLER_DATA_T* ptMarshaller = (HIL_MARSHALLER_DATA_T*)pvMarshaller;
/* Check all transports for polling functions */
for(ulIdx = 0; ulIdx < ptMarshaller->ulTransports; ++ulIdx)
{
TRANSPORT_LAYER_DATA_T* ptLayer = &ptMarshaller->ptTransports[ulIdx];
if(ptLayer->pfnPoll)
ptLayer->pfnPoll(ptLayer->pvUser);
}
/* Check all connectors for polling functions */
for(ulIdx = 0; ulIdx < ptMarshaller->ulMaxConnectors; ++ulIdx)
{
CONNECTOR_DATA_T* ptConn = &ptMarshaller->atConnectors[ulIdx];
/* Timeout management for all connector Rx state machines */
/* Check if the RX state machine is active */
if(ptConn->fMonitorTimeout)
{
/* Incremet the elapsed time */
ptConn->ulElapsedTime += 10;
if( ptConn->tConn.ulTimeout < ptConn->ulElapsedTime)
{
ResetRxStateMachine( ptConn);
}
}
if(ptConn->fInUse && ptConn->tConn.pfnPoll)
ptConn->tConn.pfnPoll(ptConn->tConn.pvUser);
}
}
/*****************************************************************************/
/*! Main marshaller module. This must be called by user, every time it receives
* the pfnRequest callback.
* \param pvMarshaller Marshaller handle
* \return HIL_MARSHALLER_E_SUCCESS on success
* \and HIL_MARSHALLER_E_FAIL if no message retrieved from the pending requests list */
/*****************************************************************************/
uint32_t HilMarshallerMain(void* pvMarshaller)
{
uint32_t eRet = HIL_MARSHALLER_E_SUCCESS;
HIL_MARSHALLER_DATA_T* ptMarshaller = (HIL_MARSHALLER_DATA_T*) pvMarshaller;
int iLock = 0;
HIL_MARSHALLER_BUFFER_T* ptBuffer = NULL;
TRANSPORT_LAYER_DATA_T* ptTransport = NULL;
CONNECTOR_DATA_T* ptConn = NULL;
if (ptMarshaller == NULL)
eRet = HIL_MARSHALLER_E_FAIL;
else
{
iLock = OS_Lock();
ptBuffer = STAILQ_FIRST(&ptMarshaller->tPendingRequests);
OS_Unlock(iLock);
if (ptBuffer == NULL)
eRet = HIL_MARSHALLER_E_FAIL;
else
{
ptTransport = FindTransportLayer(ptMarshaller, ptBuffer->tTransport.usDataType);
ptConn = &ptMarshaller->atConnectors[ptBuffer->tMgmt.ulConnectorIdx];
if (ptTransport == NULL || ptConn == NULL)
eRet = HIL_MARSHALLER_E_FAIL;
else
{
iLock = OS_Lock();
STAILQ_REMOVE(&ptMarshaller->tPendingRequests, ptBuffer, HIL_MARSHALLER_BUFFER_Ttag, tList);
OS_Unlock(iLock);
ptTransport->pfnHandler(ptMarshaller, ptBuffer, ptTransport->pvUser);
}
}
}
return eRet;
}
/*****************************************************************************/
/*! HilMarshallerSetMode() sets the mode (unrestricted / restricted / disabled)
* either of a single connector or of all connectors.
* \param pvMarshaller Marshaller handle
* \param ulMode see MARSHALLER_MODE_xxx constants above
* \param ulConnectorID connector index or MARSHALLER_CONNECTORS_ALL
* \return HIL_MARSHALLER_E_SUCCESS on success
* \ HIL_MARSHALLER_E_INVALIDPARAMETER if mode invalid
* \ HIL_MARSHALLER_E_OUTOFRESOURCES if connector reference invalid */
/*****************************************************************************/
uint32_t HilMarshallerSetMode(void* pvMarshaller,
uint32_t ulMode,
uint32_t ulConnectorID)
{
uint32_t eRet = HIL_MARSHALLER_E_SUCCESS;
HIL_MARSHALLER_DATA_T* ptMarshaller = (HIL_MARSHALLER_DATA_T*)pvMarshaller;
uint32_t ulIndex;
uint32_t ulMinConnectorID = ulConnectorID;
uint32_t ulMaxConnectorID = ulConnectorID + 1;
/* check the scope of the command (single connector / all connectors) */
if (ulConnectorID == HIL_MARSHALLER_CONNECTORS_ALL)
{ /* change mode of all connectors */
ulMinConnectorID = 0;
ulMaxConnectorID = ptMarshaller->ulMaxConnectors;
}
else
{ /* check the given connector index */
if (ulConnectorID > ptMarshaller->ulMaxConnectors)
eRet = HIL_MARSHALLER_E_OUTOFRESOURCES;
}
if (eRet == HIL_MARSHALLER_E_SUCCESS)
{
switch (ulMode)
{
case HIL_MARSHALLER_MODE_ENABLED:
{ /* set mode for a single connector or for all connectors */
for (ulIndex = ulMinConnectorID; ulIndex < ulMaxConnectorID; ulIndex++)
ptMarshaller->atConnectors[ulIndex].ulMode = ulMode;
break;
}
case HIL_MARSHALLER_MODE_DISABLED:
{ /* set mode for a single connector or for all connectors */
for (ulIndex = ulMinConnectorID; ulIndex < ulMaxConnectorID; ulIndex++)
ptMarshaller->atConnectors[ulIndex].ulMode = ulMode;
break;
}
default:
{ /* invalid mode parameter */
eRet = HIL_MARSHALLER_E_INVALIDPARAMETER;
}
}
}
return (eRet);
}
/*****************************************************************************/
/*! \} */
/*****************************************************************************/