- toolkit V2.8.0.1@14806 - BSL V1.8.0.0@14590 - tcpserver: V1.4.3.0@14676 (marshaller V2.4.0.1@14551)
1274 lines
49 KiB
C
1274 lines
49 KiB
C
/**************************************************************************************
|
|
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);
|
|
}
|
|
|
|
|
|
/*****************************************************************************/
|
|
/*! \} */
|
|
/*****************************************************************************/
|