From 9d7164cfdb611c2f864d535ae5794f23db3d84f7 Mon Sep 17 00:00:00 2001 From: Daniel Krueger Date: Fri, 19 Dec 2008 11:41:57 -0800 Subject: Staging: add epl stack This is the openPOWERLINK network stack from systec electronic. It's a bit messed up as there is a driver mixed into the middle of it, lots of work needs to be done to unwind the different portions to make it sane. Cc: Daniel Krueger Cc: Ronald Sieber Signed-off-by: Greg Kroah-Hartman --- drivers/staging/epl/EplSdoAsySequ.c | 2401 +++++++++++++++++++++++++++++++++++ 1 file changed, 2401 insertions(+) create mode 100644 drivers/staging/epl/EplSdoAsySequ.c (limited to 'drivers/staging/epl/EplSdoAsySequ.c') diff --git a/drivers/staging/epl/EplSdoAsySequ.c b/drivers/staging/epl/EplSdoAsySequ.c new file mode 100644 index 00000000000..8a4e1e29b58 --- /dev/null +++ b/drivers/staging/epl/EplSdoAsySequ.c @@ -0,0 +1,2401 @@ +/**************************************************************************** + + (c) SYSTEC electronic GmbH, D-07973 Greiz, August-Bebel-Str. 29 + www.systec-electronic.com + + Project: openPOWERLINK + + Description: source file for asychronous SDO Sequence Layer module + + License: + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + 3. Neither the name of SYSTEC electronic GmbH nor the names of its + contributors may be used to endorse or promote products derived + from this software without prior written permission. For written + permission, please contact info@systec-electronic.com. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + + Severability Clause: + + If a provision of this License is or becomes illegal, invalid or + unenforceable in any jurisdiction, that shall not affect: + 1. the validity or enforceability in that jurisdiction of any other + provision of this License; or + 2. the validity or enforceability in other jurisdictions of that or + any other provision of this License. + + ------------------------------------------------------------------------- + + $RCSfile: EplSdoAsySequ.c,v $ + + $Author: D.Krueger $ + + $Revision: 1.10 $ $Date: 2008/11/13 17:13:09 $ + + $State: Exp $ + + Build Environment: + GCC V3.4 + + ------------------------------------------------------------------------- + + Revision History: + + 2006/06/26 k.t.: start of the implementation + +****************************************************************************/ + +#include "user/EplSdoAsySequ.h" + + +#if ((((EPL_MODULE_INTEGRATION) & (EPL_MODULE_SDO_UDP)) == 0) &&\ + (((EPL_MODULE_INTEGRATION) & (EPL_MODULE_SDO_ASND)) == 0) ) + + #error 'ERROR: At least UDP or Asnd module needed!' + +#endif +/***************************************************************************/ +/* */ +/* */ +/* G L O B A L D E F I N I T I O N S */ +/* */ +/* */ +/***************************************************************************/ + +//--------------------------------------------------------------------------- +// const defines +//--------------------------------------------------------------------------- + +#define EPL_SDO_HISTORY_SIZE 5 + +#ifndef EPL_MAX_SDO_SEQ_CON +#define EPL_MAX_SDO_SEQ_CON 10 +#endif + +#define EPL_SEQ_DEFAULT_TIMEOUT 5000 // in [ms] => 5 sec + +#define EPL_SEQ_RETRY_COUNT 5 // => max. Timeout 30 sec + +#define EPL_SEQ_NUM_THRESHOLD 100 // threshold which distinguishes between old and new sequence numbers + +// define frame with size of Asnd-Header-, SDO Sequenze Header size, SDO Command header +// and Ethernet-Header size +#define EPL_SEQ_FRAME_SIZE 24 +// size of the header of the asynchronus SDO Sequence layer +#define EPL_SEQ_HEADER_SIZE 4 + +// buffersize for one frame in history +#define EPL_SEQ_HISTROY_FRAME_SIZE EPL_MAX_SDO_FRAME_SIZE + +// mask to get scon and rcon +#define EPL_ASY_SDO_CON_MASK 0x03 + +//--------------------------------------------------------------------------- +// local types +//--------------------------------------------------------------------------- + +// events for processfunction +typedef enum +{ + kAsySdoSeqEventNoEvent = 0x00, // no Event + kAsySdoSeqEventInitCon = 0x01, // init connection + kAsySdoSeqEventFrameRec = 0x02, // frame received + kAsySdoSeqEventFrameSend= 0x03, // frame to send + kAsySdoSeqEventTimeout = 0x04, // Timeout for connection + kAsySdoSeqEventCloseCon = 0x05 // higher layer close connection + +}tEplAsySdoSeqEvent; + +// structure for History-Buffer +typedef struct +{ + BYTE m_bFreeEntries; + BYTE m_bWrite; // index of the next free buffer entry + BYTE m_bAck; // index of the next message which should become acknowledged + BYTE m_bRead; // index between m_bAck and m_bWrite to the next message for retransmission + BYTE m_aabHistoryFrame[EPL_SDO_HISTORY_SIZE][EPL_SEQ_HISTROY_FRAME_SIZE]; + unsigned int m_auiFrameSize[EPL_SDO_HISTORY_SIZE]; + +}tEplAsySdoConHistory; + +// state of the statemaschine +typedef enum +{ + kEplAsySdoStateIdle = 0x00, + kEplAsySdoStateInit1 = 0x01, + kEplAsySdoStateInit2 = 0x02, + kEplAsySdoStateInit3 = 0x03, + kEplAsySdoStateConnected = 0x04, + kEplAsySdoStateWaitAck = 0x05 + +}tEplAsySdoState; + +// connection control structure +typedef struct +{ + tEplSdoConHdl m_ConHandle; + tEplAsySdoState m_SdoState; + BYTE m_bRecSeqNum; // name from view of the communication partner + BYTE m_bSendSeqNum; // name from view of the communication partner + tEplAsySdoConHistory m_SdoConHistory; + tEplTimerHdl m_EplTimerHdl; + unsigned int m_uiRetryCount; // retry counter + unsigned int m_uiUseCount; // one sequence layer connection may be used by + // multiple command layer connections + +}tEplAsySdoSeqCon; + +// instance structure +typedef struct +{ + tEplAsySdoSeqCon m_AsySdoConnection[EPL_MAX_SDO_SEQ_CON]; + tEplSdoComReceiveCb m_fpSdoComReceiveCb; + tEplSdoComConCb m_fpSdoComConCb; + +#if defined(WIN32) || defined(_WIN32) + LPCRITICAL_SECTION m_pCriticalSection; + CRITICAL_SECTION m_CriticalSection; + + LPCRITICAL_SECTION m_pCriticalSectionReceive; + CRITICAL_SECTION m_CriticalSectionReceive; +#endif + +}tEplAsySdoSequInstance; + +//--------------------------------------------------------------------------- +// modul globale vars +//--------------------------------------------------------------------------- + +static tEplAsySdoSequInstance AsySdoSequInstance_g; + +//--------------------------------------------------------------------------- +// local function prototypes +//--------------------------------------------------------------------------- + +static tEplKernel EplSdoAsySeqProcess(unsigned int uiHandle_p, + unsigned int uiDataSize_p, + tEplFrame* pData_p, + tEplAsySdoSeq* pRecFrame_p, + tEplAsySdoSeqEvent Event_p); + +static tEplKernel EplSdoAsySeqSendIntern(tEplAsySdoSeqCon* pAsySdoSeqCon_p, + unsigned int uiDataSize_p, + tEplFrame* pData_p, + BOOL fFrameInHistory); + +static tEplKernel EplSdoAsySeqSendLowerLayer(tEplAsySdoSeqCon* pAsySdoSeqCon_p, + unsigned int uiDataSize_p, + tEplFrame* pEplFrame_p); + +tEplKernel PUBLIC EplSdoAsyReceiveCb (tEplSdoConHdl ConHdl_p, + tEplAsySdoSeq* pSdoSeqData_p, + unsigned int uiDataSize_p); + +static tEplKernel EplSdoAsyInitHistory(void); + +static tEplKernel EplSdoAsyAddFrameToHistory(tEplAsySdoSeqCon* pAsySdoSeqCon_p, + tEplFrame* pFrame_p, + unsigned int uiSize_p); + +static tEplKernel EplSdoAsyAckFrameToHistory(tEplAsySdoSeqCon* pAsySdoSeqCon_p, + BYTE bRecSeqNumber_p); + +static tEplKernel EplSdoAsyReadFromHistory(tEplAsySdoSeqCon* pAsySdoSeqCon_p, + tEplFrame** ppFrame_p, + unsigned int* puiSize_p, + BOOL fInitRead); + +static unsigned int EplSdoAsyGetFreeEntriesFromHistory(tEplAsySdoSeqCon* pAsySdoSeqCon_p); + +static tEplKernel EplSdoAsySeqSetTimer(tEplAsySdoSeqCon* pAsySdoSeqCon_p, + unsigned long ulTimeout); + +/***************************************************************************/ +/* */ +/* */ +/* C L A S S */ +/* */ +/* */ +/***************************************************************************/ +// +// Description: this module contains the asynchronus SDO Sequence Layer for +// the EPL SDO service +// +// +/***************************************************************************/ + +//=========================================================================// +// // +// P U B L I C F U N C T I O N S // +// // +//=========================================================================// + +//--------------------------------------------------------------------------- +// +// Function: EplSdoAsySeqInit +// +// Description: init first instance +// +// +// +// Parameters: fpSdoComCb_p = callback function to inform Command layer +// about new frames +// fpSdoComConCb_p = callback function to inform command layer +// about connection state +// +// +// Returns: tEplKernel = errorcode +// +// +// State: +// +//--------------------------------------------------------------------------- +tEplKernel PUBLIC EplSdoAsySeqInit(tEplSdoComReceiveCb fpSdoComCb_p, + tEplSdoComConCb fpSdoComConCb_p) +{ +tEplKernel Ret; + + + Ret = EplSdoAsySeqAddInstance(fpSdoComCb_p, fpSdoComConCb_p); + + return Ret; + +} + +//--------------------------------------------------------------------------- +// +// Function: EplSdoAsySeqAddInstance +// +// Description: init following instances +// +// +// +// Parameters: fpSdoComCb_p = callback function to inform Command layer +// about new frames +// fpSdoComConCb_p = callback function to inform command layer +// about connection state +// +// Returns: tEplKernel = errorcode +// +// +// State: +// +//--------------------------------------------------------------------------- +tEplKernel PUBLIC EplSdoAsySeqAddInstance (tEplSdoComReceiveCb fpSdoComCb_p, + tEplSdoComConCb fpSdoComConCb_p) +{ +tEplKernel Ret; + + Ret = kEplSuccessful; + + // check functionpointer + if(fpSdoComCb_p == NULL) + { + Ret = kEplSdoSeqMissCb; + goto Exit; + } + else + { + AsySdoSequInstance_g.m_fpSdoComReceiveCb = fpSdoComCb_p; + } + + // check functionpointer + if(fpSdoComConCb_p == NULL) + { + Ret = kEplSdoSeqMissCb; + goto Exit; + } + else + { + AsySdoSequInstance_g.m_fpSdoComConCb = fpSdoComConCb_p; + } + + // set controllstructure to 0 + EPL_MEMSET(&AsySdoSequInstance_g.m_AsySdoConnection[0], 0x00, sizeof(AsySdoSequInstance_g.m_AsySdoConnection)); + + // init History + Ret = EplSdoAsyInitHistory(); + if(Ret != kEplSuccessful) + { + goto Exit; + } + +#if defined(WIN32) || defined(_WIN32) + // create critical section for process function + AsySdoSequInstance_g.m_pCriticalSection = &AsySdoSequInstance_g.m_CriticalSection; + InitializeCriticalSection(AsySdoSequInstance_g.m_pCriticalSection); + + // init critical section for receive cb function + AsySdoSequInstance_g.m_pCriticalSectionReceive = &AsySdoSequInstance_g.m_CriticalSectionReceive; + InitializeCriticalSection(AsySdoSequInstance_g.m_pCriticalSectionReceive); +#endif + + +#if(((EPL_MODULE_INTEGRATION) & (EPL_MODULE_SDO_UDP)) != 0) + // init lower layer + Ret = EplSdoUdpuAddInstance(EplSdoAsyReceiveCb); + if(Ret != kEplSuccessful) + { + goto Exit; + } +#endif + +#if(((EPL_MODULE_INTEGRATION) & (EPL_MODULE_SDO_ASND)) != 0) + // init lower layer + Ret = EplSdoAsnduAddInstance(EplSdoAsyReceiveCb); + if(Ret != kEplSuccessful) + { + goto Exit; + } +#endif + + + +Exit: + return Ret; + +} + +//--------------------------------------------------------------------------- +// +// Function: EplSdoAsySeqDelInstance +// +// Description: delete instances +// +// +// +// Parameters: +// +// +// Returns: tEplKernel = errorcode +// +// +// State: +// +//--------------------------------------------------------------------------- +tEplKernel PUBLIC EplSdoAsySeqDelInstance() +{ +tEplKernel Ret; +unsigned int uiCount; +tEplAsySdoSeqCon* pAsySdoSeqCon; + + Ret = kEplSuccessful; + + // delete timer of open connections + uiCount = 0; + pAsySdoSeqCon = &AsySdoSequInstance_g.m_AsySdoConnection[0]; + while(uiCount < EPL_MAX_SDO_SEQ_CON) + { + if (pAsySdoSeqCon->m_ConHandle != 0) + { + EplTimeruDeleteTimer(&pAsySdoSeqCon->m_EplTimerHdl); + } + uiCount++; + pAsySdoSeqCon++; + } + + +#if defined(WIN32) || defined(_WIN32) + // delete critical section for process function + DeleteCriticalSection(AsySdoSequInstance_g.m_pCriticalSection); +#endif + + // set instance-table to 0 + EPL_MEMSET(&AsySdoSequInstance_g, 0x00, sizeof(AsySdoSequInstance_g)); + +#if(((EPL_MODULE_INTEGRATION) & (EPL_MODULE_SDO_UDP)) != 0) + // delete lower layer + Ret = EplSdoUdpuDelInstance(); +#endif + +#if(((EPL_MODULE_INTEGRATION) & (EPL_MODULE_SDO_ASND)) != 0) + // delete lower layer + Ret = EplSdoAsnduDelInstance(); +#endif + + return Ret; +} + +//--------------------------------------------------------------------------- +// +// Function: EplSdoAsySeqInitCon +// +// Description: start initialization of a sequence layer connection. +// It tries to reuse an existing connection to the same node. +// +// +// Parameters: pSdoSeqConHdl_p = pointer to the variable for the connection handle +// uiNodeId_p = Node Id of the target +// SdoType = Type of the SDO connection +// +// +// Returns: tEplKernel = errorcode +// +// +// State: +// +//--------------------------------------------------------------------------- +tEplKernel PUBLIC EplSdoAsySeqInitCon(tEplSdoSeqConHdl* pSdoSeqConHdl_p, + unsigned int uiNodeId_p, + tEplSdoType SdoType) +{ +tEplKernel Ret; +unsigned int uiCount; +unsigned int uiFreeCon; +tEplSdoConHdl ConHandle; +tEplAsySdoSeqCon* pAsySdoSeqCon; + Ret = kEplSuccessful; + + // check SdoType + // call init function of the protcol abstraction layer + // which tries to find an existing connection to the same node + switch (SdoType) + { + // SDO over UDP + case kEplSdoTypeUdp: + { +#if(((EPL_MODULE_INTEGRATION) & (EPL_MODULE_SDO_UDP)) != 0) + Ret = EplSdoUdpuInitCon(&ConHandle, + uiNodeId_p); + if(Ret != kEplSuccessful) + { + goto Exit; + } +#else + Ret = kEplSdoSeqUnsupportedProt; +#endif + break; + } + + // SDO over Asnd + case kEplSdoTypeAsnd: + { +#if(((EPL_MODULE_INTEGRATION) & (EPL_MODULE_SDO_ASND)) != 0) + Ret = EplSdoAsnduInitCon(&ConHandle, + uiNodeId_p); + if(Ret != kEplSuccessful) + { + goto Exit; + } +#else + Ret = kEplSdoSeqUnsupportedProt; +#endif + break; + } + + // unsupported protocols + // -> auto should be replaced by command layer + case kEplSdoTypeAuto: + case kEplSdoTypePdo: + default: + { + Ret = kEplSdoSeqUnsupportedProt; + goto Exit; + } + + }// end of switch(SdoType) + + + // find existing connection to the same node or find empty entry for connection + uiCount = 0; + uiFreeCon = EPL_MAX_SDO_SEQ_CON; + pAsySdoSeqCon = &AsySdoSequInstance_g.m_AsySdoConnection[0]; + + while (uiCount < EPL_MAX_SDO_SEQ_CON) + { + if (pAsySdoSeqCon->m_ConHandle == ConHandle) + { // existing connection found + break; + } + if (pAsySdoSeqCon->m_ConHandle == 0) + { + uiFreeCon = uiCount; + } + uiCount++; + pAsySdoSeqCon++; + } + + if (uiCount == EPL_MAX_SDO_SEQ_CON) + { + if (uiFreeCon == EPL_MAX_SDO_SEQ_CON) + { // no free entry found + switch (SdoType) + { + // SDO over UDP + case kEplSdoTypeUdp: + { +#if(((EPL_MODULE_INTEGRATION) & (EPL_MODULE_SDO_UDP)) != 0) + Ret = EplSdoUdpuDelCon(ConHandle); + if(Ret != kEplSuccessful) + { + goto Exit; + } +#endif + break; + } + + // SDO over Asnd + case kEplSdoTypeAsnd: + { +#if(((EPL_MODULE_INTEGRATION) & (EPL_MODULE_SDO_ASND)) != 0) + Ret = EplSdoAsnduDelCon(ConHandle); + if(Ret != kEplSuccessful) + { + goto Exit; + } +#endif + break; + } + + // unsupported protocols + // -> auto should be replaced by command layer + case kEplSdoTypeAuto: + case kEplSdoTypePdo: + default: + { + Ret = kEplSdoSeqUnsupportedProt; + goto Exit; + } + + }// end of switch(SdoType) + + Ret = kEplSdoSeqNoFreeHandle; + goto Exit; + } + else + { // free entry found + pAsySdoSeqCon = &AsySdoSequInstance_g.m_AsySdoConnection[uiFreeCon]; + pAsySdoSeqCon->m_ConHandle = ConHandle; + uiCount = uiFreeCon; + } + } + + // set handle + *pSdoSeqConHdl_p = (uiCount | EPL_SDO_ASY_HANDLE); + + // increment use counter + pAsySdoSeqCon->m_uiUseCount++; + + // call intern process function + Ret = EplSdoAsySeqProcess(uiCount, + 0, + NULL, + NULL, + kAsySdoSeqEventInitCon); + +Exit: + return Ret; +} + + +//--------------------------------------------------------------------------- +// +// Function: EplSdoAsySeqSendData +// +// Description: send sata unsing a established connection +// +// +// +// Parameters: pSdoSeqConHdl_p = connection handle +// uiDataSize_p = Size of Frame to send +// -> wihtout SDO sequence layer header, Asnd header +// and ethernetnet +// ==> SDO Sequence layer payload +// SdoType = Type of the SDO connection +// +// +// Returns: tEplKernel = errorcode +// +// +// State: +// +//--------------------------------------------------------------------------- +tEplKernel PUBLIC EplSdoAsySeqSendData(tEplSdoSeqConHdl SdoSeqConHdl_p, + unsigned int uiDataSize_p, + tEplFrame* pabData_p ) +{ +tEplKernel Ret; +unsigned int uiHandle; + + + + uiHandle = (SdoSeqConHdl_p & ~EPL_SDO_SEQ_HANDLE_MASK); + + // check if connection ready + if(AsySdoSequInstance_g.m_AsySdoConnection[uiHandle].m_SdoState == kEplAsySdoStateIdle ) + { + // no connection with this handle + Ret = kEplSdoSeqInvalidHdl; + goto Exit; + } + else if(AsySdoSequInstance_g.m_AsySdoConnection[uiHandle].m_SdoState != kEplAsySdoStateConnected) + { + Ret = kEplSdoSeqConnectionBusy; + goto Exit; + } + + Ret = EplSdoAsySeqProcess(uiHandle, + uiDataSize_p, + pabData_p, + NULL, + kAsySdoSeqEventFrameSend); +Exit: + return Ret; +} + + +//--------------------------------------------------------------------------- +// +// Function: EplSdoAsySeqProcessEvent +// +// Description: function processes extern events +// -> later needed for timeout controll with timer-module +// +// +// +// Parameters: pEvent_p = pointer to event +// +// +// Returns: tEplKernel = errorcode +// +// +// State: +// +//--------------------------------------------------------------------------- +tEplKernel PUBLIC EplSdoAsySeqProcessEvent(tEplEvent* pEvent_p) +{ +tEplKernel Ret; +tEplTimerEventArg* pTimerEventArg; +tEplAsySdoSeqCon* pAsySdoSeqCon; +tEplTimerHdl EplTimerHdl; +unsigned int uiCount; + + Ret = kEplSuccessful; + // check parameter + if(pEvent_p == NULL) + { + Ret = kEplSdoSeqInvalidEvent; + goto Exit; + } + + if(pEvent_p->m_EventType != kEplEventTypeTimer) + { + Ret = kEplSdoSeqInvalidEvent; + goto Exit; + } + + // get timerhdl + pTimerEventArg = (tEplTimerEventArg*)pEvent_p->m_pArg; + EplTimerHdl = pTimerEventArg->m_TimerHdl; + + // get pointer to intern control structure of connection + if(pTimerEventArg->m_ulArg == 0) + { + goto Exit; + } + pAsySdoSeqCon = (tEplAsySdoSeqCon*)pTimerEventArg->m_ulArg; + + // check if time is current + if(EplTimerHdl != pAsySdoSeqCon->m_EplTimerHdl) + { + // delete timer + EplTimeruDeleteTimer(&EplTimerHdl); + goto Exit; + } + + // delete timer + EplTimeruDeleteTimer(&pAsySdoSeqCon->m_EplTimerHdl); + + // get indexnumber of control structure + uiCount = 0; + while((&AsySdoSequInstance_g.m_AsySdoConnection[uiCount]) != pAsySdoSeqCon) + { + uiCount++; + if(uiCount > EPL_MAX_SDO_SEQ_CON) + { + goto Exit; + } + } + + + // process event and call processfunction if needed + Ret = EplSdoAsySeqProcess(uiCount, + 0, + NULL, + NULL, + kAsySdoSeqEventTimeout); + +Exit: + return Ret; + +} + +//--------------------------------------------------------------------------- +// +// Function: EplSdoAsySeqDelCon +// +// Description: del and close one connection +// +// +// +// Parameters: SdoSeqConHdl_p = handle of connection +// +// +// Returns: tEplKernel = errorcode +// +// +// State: +// +//--------------------------------------------------------------------------- +tEplKernel PUBLIC EplSdoAsySeqDelCon(tEplSdoSeqConHdl SdoSeqConHdl_p) +{ +tEplKernel Ret = kEplSuccessful; +unsigned int uiHandle; +tEplAsySdoSeqCon* pAsySdoSeqCon; + + uiHandle = (SdoSeqConHdl_p & ~EPL_SDO_SEQ_HANDLE_MASK); + + // check if handle invalid + if(uiHandle >= EPL_MAX_SDO_SEQ_CON) + { + Ret = kEplSdoSeqInvalidHdl; + goto Exit; + } + + // get pointer to connection + pAsySdoSeqCon = &AsySdoSequInstance_g.m_AsySdoConnection[uiHandle]; + + // decrement use counter + pAsySdoSeqCon->m_uiUseCount--; + + if (pAsySdoSeqCon->m_uiUseCount == 0) + { + // process close in processfunction + Ret = EplSdoAsySeqProcess(uiHandle, + 0, + NULL, + NULL, + kAsySdoSeqEventCloseCon); + + //check protocol + if((pAsySdoSeqCon->m_ConHandle & EPL_SDO_ASY_HANDLE_MASK) == EPL_SDO_UDP_HANDLE) + { + #if(((EPL_MODULE_INTEGRATION) & (EPL_MODULE_SDO_UDP)) != 0) + // call close function of lower layer + EplSdoUdpuDelCon(pAsySdoSeqCon->m_ConHandle); + #endif// end of #if(((EPL_MODULE_INTEGRATION) & (EPL_MODULE_SDO_UDP)) != 0) + } + else + { + #if(((EPL_MODULE_INTEGRATION) & (EPL_MODULE_SDO_ASND)) != 0) + // call close function of lower layer + EplSdoAsnduDelCon(pAsySdoSeqCon->m_ConHandle); + #endif// end of #if(((EPL_MODULE_INTEGRATION) & (EPL_MODULE_SDO_ASND)) != 0) + } + + // delete timer + EplTimeruDeleteTimer(&pAsySdoSeqCon->m_EplTimerHdl); + + // clean controllstructure + EPL_MEMSET(pAsySdoSeqCon, 0x00, sizeof(tEplAsySdoSeqCon)); + pAsySdoSeqCon->m_SdoConHistory.m_bFreeEntries = EPL_SDO_HISTORY_SIZE; + } + +Exit: + return Ret; + +} + +//=========================================================================// +// // +// P R I V A T E F U N C T I O N S // +// // +//=========================================================================// + +//--------------------------------------------------------------------------- +// +// Function: EplEplSdoAsySeqProcess +// +// Description: intern function to process the asynchronus SDO Sequence Layer +// state maschine +// +// +// +// Parameters: uiHandle_p = index of the control structure of the connection +// uiDataSize_p = size of data frame to process (can be 0) +// -> without size of sequence header and Asnd header!!! +// +// pData_p = pointer to frame to send (can be NULL) +// pRecFrame_p = pointer to received frame (can be NULL) +// Event_p = Event to process +// +// +// +// Returns: tEplKernel = errorcode +// +// +// State: +// +//--------------------------------------------------------------------------- +static tEplKernel EplSdoAsySeqProcess(unsigned int uiHandle_p, + unsigned int uiDataSize_p, + tEplFrame* pData_p, + tEplAsySdoSeq* pRecFrame_p, + tEplAsySdoSeqEvent Event_p) + +{ +tEplKernel Ret; +unsigned int uiFrameSize; +tEplFrame* pEplFrame; +tEplAsySdoSeqCon* pAsySdoSeqCon; +tEplSdoSeqConHdl SdoSeqConHdl; +unsigned int uiFreeEntries; + +#if defined(WIN32) || defined(_WIN32) + // enter critical section for process function + EnterCriticalSection(AsySdoSequInstance_g.m_pCriticalSection); +#endif + + Ret = kEplSuccessful; + + // get handle for hinger layer + SdoSeqConHdl = uiHandle_p | EPL_SDO_ASY_HANDLE; + + // check if handle invalid + if((SdoSeqConHdl & ~EPL_SDO_SEQ_HANDLE_MASK) == EPL_SDO_SEQ_INVALID_HDL) + { + Ret = kEplSdoSeqInvalidHdl; + goto Exit; + } + + // get pointer to connection + pAsySdoSeqCon = &AsySdoSequInstance_g.m_AsySdoConnection[uiHandle_p]; + + // check size + if((pData_p == NULL)&& (pRecFrame_p == NULL) && (uiDataSize_p != 0)) + { + Ret = kEplSdoSeqInvalidFrame; + goto Exit; + } + + // check state + switch(pAsySdoSeqCon->m_SdoState) + { + // idle state + case kEplAsySdoStateIdle: + { + // check event + switch(Event_p) + { + // new connection + // -> send init frame and change to + // kEplAsySdoStateInit1 + case kAsySdoSeqEventInitCon: + { + // set sending scon to 1 + pAsySdoSeqCon->m_bRecSeqNum = 0x01; + // set set send rcon to 0 + pAsySdoSeqCon->m_bSendSeqNum = 0x00; + Ret = EplSdoAsySeqSendIntern(pAsySdoSeqCon, + 0, + NULL, + FALSE); + if(Ret != kEplSuccessful) + { + goto Exit; + } + + // change state + pAsySdoSeqCon->m_SdoState = kEplAsySdoStateInit1; + + // set timer + Ret = EplSdoAsySeqSetTimer(pAsySdoSeqCon, + EPL_SEQ_DEFAULT_TIMEOUT); + + break; + } + + // init con from extern + // check rcon and scon + // -> send answer + case kAsySdoSeqEventFrameRec: + { +/* + PRINTF3("%s scon=%u rcon=%u\n", + __FUNCTION__, + pRecFrame_p->m_le_bSendSeqNumCon, + pRecFrame_p->m_le_bRecSeqNumCon); +*/ + // check if scon == 1 and rcon == 0 + if(((pRecFrame_p->m_le_bRecSeqNumCon & EPL_ASY_SDO_CON_MASK) == 0x00) + &&((pRecFrame_p->m_le_bSendSeqNumCon & EPL_ASY_SDO_CON_MASK) == 0x01)) + { + // save sequence numbers + pAsySdoSeqCon->m_bRecSeqNum = AmiGetByteFromLe(&pRecFrame_p->m_le_bRecSeqNumCon); + pAsySdoSeqCon->m_bSendSeqNum = AmiGetByteFromLe(&pRecFrame_p->m_le_bSendSeqNumCon); + // create answer and send answer + // set rcon to 1 (in send direction own scon) + pAsySdoSeqCon->m_bRecSeqNum++; + Ret = EplSdoAsySeqSendIntern(pAsySdoSeqCon, + 0, + NULL, + FALSE); + if(Ret != kEplSuccessful) + { + goto Exit; + } + // change state to kEplAsySdoStateInit2 + pAsySdoSeqCon->m_SdoState = kEplAsySdoStateInit2; + + // set timer + Ret = EplSdoAsySeqSetTimer(pAsySdoSeqCon, + EPL_SEQ_DEFAULT_TIMEOUT); + } + else + { // error -> close + // delete timer + EplTimeruDeleteTimer(&pAsySdoSeqCon->m_EplTimerHdl); + if (((pRecFrame_p->m_le_bRecSeqNumCon & EPL_ASY_SDO_CON_MASK) != 0x00) + || ((pRecFrame_p->m_le_bSendSeqNumCon & EPL_ASY_SDO_CON_MASK) != 0x00)) + { // d.k. only answer with close message if the message sent was not a close message + // save sequence numbers + pAsySdoSeqCon->m_bRecSeqNum = AmiGetByteFromLe(&pRecFrame_p->m_le_bRecSeqNumCon); + pAsySdoSeqCon->m_bSendSeqNum = AmiGetByteFromLe(&pRecFrame_p->m_le_bSendSeqNumCon); + // set rcon and scon to 0 + pAsySdoSeqCon->m_bSendSeqNum &= EPL_SEQ_NUM_MASK; + pAsySdoSeqCon->m_bRecSeqNum &= EPL_SEQ_NUM_MASK; + // send frame + EplSdoAsySeqSendIntern(pAsySdoSeqCon, + 0, + NULL, + FALSE); + } + + // call Command Layer Cb + AsySdoSequInstance_g.m_fpSdoComConCb(SdoSeqConHdl, + kAsySdoConStateInitError); + } + break; + } + + default: + // d.k. do nothing + break; + + }// end of switch(Event_p) + break; + } + + // init connection step 1 + // wait for frame with scon = 1 + // and rcon = 1 + case kEplAsySdoStateInit1: + { +// PRINTF0("EplSdoAsySequ: StateInit1\n"); + + // check event + switch(Event_p) + { + // frame received + case kAsySdoSeqEventFrameRec: + { + // check scon == 1 and rcon == 1 + if(((pRecFrame_p->m_le_bRecSeqNumCon & EPL_ASY_SDO_CON_MASK) == 0x01) + &&((pRecFrame_p->m_le_bSendSeqNumCon & EPL_ASY_SDO_CON_MASK) == 0x01)) + { // create answer own scon = 2 + // save sequence numbers + pAsySdoSeqCon->m_bRecSeqNum = AmiGetByteFromLe(&pRecFrame_p->m_le_bRecSeqNumCon); + pAsySdoSeqCon->m_bSendSeqNum = AmiGetByteFromLe(&pRecFrame_p->m_le_bSendSeqNumCon); + + pAsySdoSeqCon->m_bRecSeqNum++; + Ret = EplSdoAsySeqSendIntern(pAsySdoSeqCon, + 0, + NULL, + FALSE); + if(Ret != kEplSuccessful) + { + goto Exit; + } + // change state to kEplAsySdoStateInit3 + pAsySdoSeqCon->m_SdoState = kEplAsySdoStateInit3; + + // set timer + Ret = EplSdoAsySeqSetTimer(pAsySdoSeqCon, + EPL_SEQ_DEFAULT_TIMEOUT); + + } + // check if scon == 1 and rcon == 0, i.e. other side wants me to be server + else if(((pRecFrame_p->m_le_bRecSeqNumCon & EPL_ASY_SDO_CON_MASK) == 0x00) + &&((pRecFrame_p->m_le_bSendSeqNumCon & EPL_ASY_SDO_CON_MASK) == 0x01)) + { + // save sequence numbers + pAsySdoSeqCon->m_bRecSeqNum = AmiGetByteFromLe(&pRecFrame_p->m_le_bRecSeqNumCon); + pAsySdoSeqCon->m_bSendSeqNum = AmiGetByteFromLe(&pRecFrame_p->m_le_bSendSeqNumCon); + // create answer and send answer + // set rcon to 1 (in send direction own scon) + pAsySdoSeqCon->m_bRecSeqNum++; + Ret = EplSdoAsySeqSendIntern(pAsySdoSeqCon, + 0, + NULL, + FALSE); + if(Ret != kEplSuccessful) + { + goto Exit; + } + // change state to kEplAsySdoStateInit2 + pAsySdoSeqCon->m_SdoState = kEplAsySdoStateInit2; + + // set timer + Ret = EplSdoAsySeqSetTimer(pAsySdoSeqCon, + EPL_SEQ_DEFAULT_TIMEOUT); + } + else + { // error -> Close + pAsySdoSeqCon->m_SdoState = kEplAsySdoStateIdle; + // delete timer + EplTimeruDeleteTimer(&pAsySdoSeqCon->m_EplTimerHdl); + if (((pRecFrame_p->m_le_bRecSeqNumCon & EPL_ASY_SDO_CON_MASK) != 0x00) + || ((pRecFrame_p->m_le_bSendSeqNumCon & EPL_ASY_SDO_CON_MASK) != 0x00)) + { // d.k. only answer with close message if the message sent was not a close message + // save sequence numbers + pAsySdoSeqCon->m_bRecSeqNum = AmiGetByteFromLe(&pRecFrame_p->m_le_bRecSeqNumCon); + pAsySdoSeqCon->m_bSendSeqNum = AmiGetByteFromLe(&pRecFrame_p->m_le_bSendSeqNumCon); + + // set rcon and scon to 0 + pAsySdoSeqCon->m_bSendSeqNum &= EPL_SEQ_NUM_MASK; + pAsySdoSeqCon->m_bRecSeqNum &= EPL_SEQ_NUM_MASK; + // send frame + EplSdoAsySeqSendIntern(pAsySdoSeqCon, + 0, + NULL, + FALSE); + } + // call Command Layer Cb + AsySdoSequInstance_g.m_fpSdoComConCb(SdoSeqConHdl, + kAsySdoConStateInitError); + } + break; + } + + // timeout + case kAsySdoSeqEventTimeout: + { // error -> Close + pAsySdoSeqCon->m_SdoState = kEplAsySdoStateIdle; + + // set rcon and scon to 0 + pAsySdoSeqCon->m_bSendSeqNum &= EPL_SEQ_NUM_MASK; + pAsySdoSeqCon->m_bRecSeqNum &= EPL_SEQ_NUM_MASK; + // send frame + EplSdoAsySeqSendIntern(pAsySdoSeqCon, + 0, + NULL, + FALSE); + // call Command Layer Cb + AsySdoSequInstance_g.m_fpSdoComConCb(SdoSeqConHdl, + kAsySdoConStateInitError); + break; + } + + default: + // d.k. do nothing + break; + + }// end of switch(Event_p) + break; + } + + // init connection step 2 + case kEplAsySdoStateInit2: + { +// PRINTF0("EplSdoAsySequ: StateInit2\n"); + + // check event + switch(Event_p) + { + // frame received + case kAsySdoSeqEventFrameRec: + { + // check scon == 2 and rcon == 1 + if(((pRecFrame_p->m_le_bRecSeqNumCon & EPL_ASY_SDO_CON_MASK) == 0x01) + &&((pRecFrame_p->m_le_bSendSeqNumCon & EPL_ASY_SDO_CON_MASK) == 0x02)) + { // create answer own rcon = 2 + // save sequence numbers + pAsySdoSeqCon->m_bRecSeqNum = AmiGetByteFromLe(&pRecFrame_p->m_le_bRecSeqNumCon); + pAsySdoSeqCon->m_bSendSeqNum = AmiGetByteFromLe(&pRecFrame_p->m_le_bSendSeqNumCon); + + pAsySdoSeqCon->m_bRecSeqNum++; + Ret = EplSdoAsySeqSendIntern(pAsySdoSeqCon, + 0, + NULL, + FALSE); + if(Ret != kEplSuccessful) + { + goto Exit; + } + // change state to kEplAsySdoStateConnected + pAsySdoSeqCon->m_SdoState = kEplAsySdoStateConnected; + + // set timer + Ret = EplSdoAsySeqSetTimer(pAsySdoSeqCon, + EPL_SEQ_DEFAULT_TIMEOUT); + + // call Command Layer Cb + AsySdoSequInstance_g.m_fpSdoComConCb(SdoSeqConHdl, + kAsySdoConStateConnected); + + } + // check scon == 1 and rcon == 1, i.e. other side wants me to initiate the connection + else if(((pRecFrame_p->m_le_bRecSeqNumCon & EPL_ASY_SDO_CON_MASK) == 0x01) + &&((pRecFrame_p->m_le_bSendSeqNumCon & EPL_ASY_SDO_CON_MASK) == 0x01)) + { + // save sequence numbers + pAsySdoSeqCon->m_bRecSeqNum = AmiGetByteFromLe(&pRecFrame_p->m_le_bRecSeqNumCon); + pAsySdoSeqCon->m_bSendSeqNum = AmiGetByteFromLe(&pRecFrame_p->m_le_bSendSeqNumCon); + // create answer and send answer + // set rcon to 1 (in send direction own scon) + pAsySdoSeqCon->m_bRecSeqNum++; + Ret = EplSdoAsySeqSendIntern(pAsySdoSeqCon, + 0, + NULL, + FALSE); + if(Ret != kEplSuccessful) + { + goto Exit; + } + // set timer + Ret = EplSdoAsySeqSetTimer(pAsySdoSeqCon, + EPL_SEQ_DEFAULT_TIMEOUT); + // change state to kEplAsySdoStateInit3 + pAsySdoSeqCon->m_SdoState = kEplAsySdoStateInit3; + + } + else + { // error -> Close + pAsySdoSeqCon->m_SdoState = kEplAsySdoStateIdle; + // delete timer + EplTimeruDeleteTimer(&pAsySdoSeqCon->m_EplTimerHdl); + if (((pRecFrame_p->m_le_bRecSeqNumCon & EPL_ASY_SDO_CON_MASK) != 0x00) + || ((pRecFrame_p->m_le_bSendSeqNumCon & EPL_ASY_SDO_CON_MASK) != 0x00)) + { // d.k. only answer with close message if the message sent was not a close message + // save sequence numbers + pAsySdoSeqCon->m_bRecSeqNum = AmiGetByteFromLe(&pRecFrame_p->m_le_bRecSeqNumCon); + pAsySdoSeqCon->m_bSendSeqNum = AmiGetByteFromLe(&pRecFrame_p->m_le_bSendSeqNumCon); + // set rcon and scon to 0 + pAsySdoSeqCon->m_bSendSeqNum &= EPL_SEQ_NUM_MASK; + pAsySdoSeqCon->m_bRecSeqNum &= EPL_SEQ_NUM_MASK; + // send frame + EplSdoAsySeqSendIntern(pAsySdoSeqCon, + 0, + NULL, + FALSE); + } + // call Command Layer Cb + AsySdoSequInstance_g.m_fpSdoComConCb(SdoSeqConHdl, + kAsySdoConStateInitError); + } + break; + } + + // timeout + case kAsySdoSeqEventTimeout: + { // error -> Close + pAsySdoSeqCon->m_SdoState = kEplAsySdoStateIdle; + // set rcon and scon to 0 + pAsySdoSeqCon->m_bSendSeqNum &= EPL_SEQ_NUM_MASK; + pAsySdoSeqCon->m_bRecSeqNum &= EPL_SEQ_NUM_MASK; + // send frame + EplSdoAsySeqSendIntern(pAsySdoSeqCon, + 0, + NULL, + FALSE); + + // call Command Layer Cb + AsySdoSequInstance_g.m_fpSdoComConCb(SdoSeqConHdl, + kAsySdoConStateInitError); + break; + } + + default: + // d.k. do nothing + break; + + }// end of switch(Event_p) + break; + } + + // init connection step 3 + case kEplAsySdoStateInit3: + { + // check event + switch(Event_p) + { + // frame received + case kAsySdoSeqEventFrameRec: + { + // check scon == 2 and rcon == 2 + if(((pRecFrame_p->m_le_bRecSeqNumCon & EPL_ASY_SDO_CON_MASK) == 0x02) + &&((pRecFrame_p->m_le_bSendSeqNumCon & EPL_ASY_SDO_CON_MASK) == 0x02)) + { + // save sequence numbers + pAsySdoSeqCon->m_bRecSeqNum = AmiGetByteFromLe(&pRecFrame_p->m_le_bRecSeqNumCon); + pAsySdoSeqCon->m_bSendSeqNum = AmiGetByteFromLe(&pRecFrame_p->m_le_bSendSeqNumCon); + // change state to kEplAsySdoStateConnected + pAsySdoSeqCon->m_SdoState = kEplAsySdoStateConnected; + + // set timer + Ret = EplSdoAsySeqSetTimer(pAsySdoSeqCon, + EPL_SEQ_DEFAULT_TIMEOUT); + // call Command Layer Cb + AsySdoSequInstance_g.m_fpSdoComConCb(SdoSeqConHdl, + kAsySdoConStateConnected); + + } + // check scon == 2 and rcon == 1 + else if(((pRecFrame_p->m_le_bRecSeqNumCon & EPL_ASY_SDO_CON_MASK) == 0x01) + &&((pRecFrame_p->m_le_bSendSeqNumCon & EPL_ASY_SDO_CON_MASK) == 0x02)) + { // create answer own rcon = 2 + // save sequence numbers + pAsySdoSeqCon->m_bRecSeqNum = AmiGetByteFromLe(&pRecFrame_p->m_le_bRecSeqNumCon); + pAsySdoSeqCon->m_bSendSeqNum = AmiGetByteFromLe(&pRecFrame_p->m_le_bSendSeqNumCon); + + pAsySdoSeqCon->m_bRecSeqNum++; + Ret = EplSdoAsySeqSendIntern(pAsySdoSeqCon, + 0, + NULL, + FALSE); + if(Ret != kEplSuccessful) + { + goto Exit; + } + // change state to kEplAsySdoStateConnected + pAsySdoSeqCon->m_SdoState = kEplAsySdoStateConnected; + + // set timer + Ret = EplSdoAsySeqSetTimer(pAsySdoSeqCon, + EPL_SEQ_DEFAULT_TIMEOUT); + + // call Command Layer Cb + AsySdoSequInstance_g.m_fpSdoComConCb(SdoSeqConHdl, + kAsySdoConStateConnected); + + } + else + { // error -> Close + pAsySdoSeqCon->m_SdoState = kEplAsySdoStateIdle; + // delete timer + EplTimeruDeleteTimer(&pAsySdoSeqCon->m_EplTimerHdl); + if (((pRecFrame_p->m_le_bRecSeqNumCon & EPL_ASY_SDO_CON_MASK) != 0x00) + || ((pRecFrame_p->m_le_bSendSeqNumCon & EPL_ASY_SDO_CON_MASK) != 0x00)) + { // d.k. only answer with close message if the message sent was not a close message + // save sequence numbers + pAsySdoSeqCon->m_bRecSeqNum = AmiGetByteFromLe(&pRecFrame_p->m_le_bRecSeqNumCon); + pAsySdoSeqCon->m_bSendSeqNum = AmiGetByteFromLe(&pRecFrame_p->m_le_bSendSeqNumCon); + // set rcon and scon to 0 + pAsySdoSeqCon->m_bSendSeqNum &= EPL_SEQ_NUM_MASK; + pAsySdoSeqCon->m_bRecSeqNum &= EPL_SEQ_NUM_MASK; + // send frame + EplSdoAsySeqSendIntern(pAsySdoSeqCon, + 0, + NULL, + FALSE); + } + // call Command Layer Cb + AsySdoSequInstance_g.m_fpSdoComConCb(SdoSeqConHdl, + kAsySdoConStateInitError); + } + break; + } + + // timeout + case kAsySdoSeqEventTimeout: + { // error -> Close + pAsySdoSeqCon->m_SdoState = kEplAsySdoStateIdle; + // set rcon and scon to 0 + pAsySdoSeqCon->m_bSendSeqNum &= EPL_SEQ_NUM_MASK; + pAsySdoSeqCon->m_bRecSeqNum &= EPL_SEQ_NUM_MASK; + // send frame + EplSdoAsySeqSendIntern(pAsySdoSeqCon, + 0, + NULL, + FALSE); + + // call Command Layer Cb + AsySdoSequInstance_g.m_fpSdoComConCb(SdoSeqConHdl, + kAsySdoConStateInitError); + break; + } + + default: + // d.k. do nothing + break; + + }// end of switch(Event_p) + break; + } + + // connection established + case kEplAsySdoStateConnected: + { + // check event + switch(Event_p) + { + + // frame to send + case kAsySdoSeqEventFrameSend: + { + // set timer + Ret = EplSdoAsySeqSetTimer(pAsySdoSeqCon, + EPL_SEQ_DEFAULT_TIMEOUT); + // check if data frame or ack + if(pData_p == NULL) + { // send ack + // inc scon + //pAsySdoSeqCon->m_bRecSeqNum += 4; + Ret = EplSdoAsySeqSendIntern(pAsySdoSeqCon, + 0, + NULL, + FALSE); + if(Ret != kEplSuccessful) + { + goto Exit; + } + } + else + { // send dataframe + // increment send sequence number + pAsySdoSeqCon->m_bRecSeqNum += 4; + Ret = EplSdoAsySeqSendIntern(pAsySdoSeqCon, + uiDataSize_p, + pData_p, + TRUE); + if(Ret == kEplSdoSeqRequestAckNeeded) + { // request ack + // change state to wait ack + pAsySdoSeqCon->m_SdoState = kEplAsySdoStateWaitAck; + // set Ret to kEplSuccessful, because no error + // for higher layer + Ret = kEplSuccessful; + + } + else if(Ret != kEplSuccessful) + { + goto Exit; + } + else + { + // call Command Layer Cb + AsySdoSequInstance_g.m_fpSdoComConCb(SdoSeqConHdl, + kAsySdoConStateFrameSended); + } + } + break; + }// end of case kAsySdoSeqEventFrameSend + + // frame received + case kAsySdoSeqEventFrameRec: + { + BYTE bSendSeqNumCon = AmiGetByteFromLe(&pRecFrame_p->m_le_bSendSeqNumCon); + + // set timer + Ret = EplSdoAsySeqSetTimer(pAsySdoSeqCon, + EPL_SEQ_DEFAULT_TIMEOUT); + // check scon + switch (bSendSeqNumCon & EPL_ASY_SDO_CON_MASK) + { + // close from other node + case 0: + case 1: + { + // return to idle + pAsySdoSeqCon->m_SdoState = kEplAsySdoStateIdle; + // delete timer + EplTimeruDeleteTimer(&pAsySdoSeqCon->m_EplTimerHdl); + // call Command Layer Cb + AsySdoSequInstance_g.m_fpSdoComConCb(SdoSeqConHdl, + kAsySdoConStateConClosed); + + break; + } + + // Request Ack or Error Ack + // possible contain data + case 3: + // normal frame + case 2: + { + if ((AmiGetByteFromLe(&pRecFrame_p->m_le_bRecSeqNumCon) & EPL_ASY_SDO_CON_MASK) == 3) + { +// PRINTF0("EplSdoAsySequ: error response received\n"); + + // error response (retransmission request) + // resend frames from history + + // read frame from history + Ret = EplSdoAsyReadFromHistory(pAsySdoSeqCon, + &pEplFrame, + &uiFrameSize, + TRUE); + if (Ret != kEplSuccessful) + { + goto Exit; + } + + while ((pEplFrame != NULL) + && (uiFrameSize != 0)) + { + // send frame + Ret = EplSdoAsySeqSendLowerLayer(pAsySdoSeqCon, + uiFrameSize, + pEplFrame); + if(Ret != kEplSuccessful) + { + goto Exit; + } + + // read next frame from history + Ret = EplSdoAsyReadFromHistory(pAsySdoSeqCon, + &pEplFrame, + &uiFrameSize, + FALSE); + if(Ret != kEplSuccessful) + { + goto Exit; + } + } // end of while((pabFrame != NULL) + } // end of if (error response) + + if (((pAsySdoSeqCon->m_bSendSeqNum + 4) & EPL_SEQ_NUM_MASK) == (bSendSeqNumCon & EPL_SEQ_NUM_MASK)) + { // next frame of sequence received + // save send sequence number (without ack request) + pAsySdoSeqCon->m_bSendSeqNum = bSendSeqNumCon & ~0x01; + + // check if ack or data-frame + //ignore ack -> already processed + if(uiDataSize_p > EPL_SEQ_HEADER_SIZE) + { + AsySdoSequInstance_g.m_fpSdoComReceiveCb( + SdoSeqConHdl, + ((tEplAsySdoCom*) &pRecFrame_p->m_le_abSdoSeqPayload), + (uiDataSize_p - EPL_SEQ_HEADER_SIZE)); + // call Command Layer Cb + AsySdoSequInstance_g.m_fpSdoComConCb(SdoSeqConHdl, + kAsySdoConStateFrameSended); + + + } + else + { + // call Command Layer Cb + AsySdoSequInstance_g.m_fpSdoComConCb(SdoSeqConHdl, + kAsySdoConStateAckReceived); + } + } + else if (((bSendSeqNumCon - pAsySdoSeqCon->m_bSendSeqNum - 4) & EPL_SEQ_NUM_MASK) < EPL_SEQ_NUM_THRESHOLD) + { // frame of sequence was lost, + // because difference of received and old value + // is less then halve of the values range. + + // send error frame with own rcon = 3 + pAsySdoSeqCon->m_bSendSeqNum |= 0x03; + Ret = EplSdoAsySeqSendIntern(pAsySdoSeqCon, + 0, + NULL, + FALSE); + // restore send sequence number + pAsySdoSeqCon->m_bSendSeqNum = (pAsySdoSeqCon->m_bSendSeqNum & EPL_SEQ_NUM_MASK) | 0x02; + if(Ret != kEplSuccessful) + { + goto Exit; + } + + // break here, because a requested acknowledge + // was sent implicitly above + break; + } + // else, ignore repeated frame + + if ((bSendSeqNumCon & EPL_ASY_SDO_CON_MASK) == 3) + { // ack request received + + // create ack with own scon = 2 + Ret = EplSdoAsySeqSendIntern(pAsySdoSeqCon, + 0, + NULL, + FALSE); + if(Ret != kEplSuccessful) + { + goto Exit; + } + } + + break; + } + + } // switch(pAsySdoSeqCon->m_bSendSeqNum & EPL_ASY_SDO_CON_MASK) + break; + } // end of case kAsySdoSeqEventFrameRec: + + + //close event from higher layer + case kAsySdoSeqEventCloseCon: + { + pAsySdoSeqCon->m_SdoState = kEplAsySdoStateIdle; + // set rcon and scon to 0 + pAsySdoSeqCon->m_bSendSeqNum &= EPL_SEQ_NUM_MASK; + pAsySdoSeqCon->m_bRecSeqNum &= EPL_SEQ_NUM_MASK; + // send frame + EplSdoAsySeqSendIntern(pAsySdoSeqCon, + 0, + NULL, + FALSE); + + // delete timer + EplTimeruDeleteTimer(&pAsySdoSeqCon->m_EplTimerHdl); + // call Command Layer Cb is not necessary, because the event came from there +// AsySdoSequInstance_g.m_fpSdoComConCb(SdoSeqConHdl, +// kAsySdoConStateInitError); + break; + } + + // timeout + case kAsySdoSeqEventTimeout: + { + + uiFreeEntries = EplSdoAsyGetFreeEntriesFromHistory(pAsySdoSeqCon); + if ((uiFreeEntries < EPL_SDO_HISTORY_SIZE) + && (pAsySdoSeqCon->m_uiRetryCount < EPL_SEQ_RETRY_COUNT)) + { // unacknowlegded frames in history + // and retry counter not exceeded + + // resend data with acknowledge request + + // increment retry counter + pAsySdoSeqCon->m_uiRetryCount++; + + // set timer + Ret = EplSdoAsySeqSetTimer(pAsySdoSeqCon, + EPL_SEQ_DEFAULT_TIMEOUT); + + // read first frame from history + Ret = EplSdoAsyReadFromHistory(pAsySdoSeqCon, + &pEplFrame, + &uiFrameSize, + TRUE); + if (Ret != kEplSuccessful) + { + goto Exit; + } + + if ((pEplFrame != NULL) + && (uiFrameSize != 0)) + { + + // set ack request in scon + AmiSetByteToLe( &pEplFrame->m_Data.m_Asnd.m_Payload.m_SdoSequenceFrame.m_le_bSendSeqNumCon, + AmiGetByteFromLe( &pEplFrame->m_Data.m_Asnd.m_Payload.m_SdoSequenceFrame.m_le_bSendSeqNumCon) | 0x03); + + // send frame + Ret = EplSdoAsySeqSendLowerLayer(pAsySdoSeqCon, + uiFrameSize, + pEplFrame); + if(Ret != kEplSuccessful) + { + goto Exit; + } + + } + } + else + { + // timeout, because of no traffic -> Close + pAsySdoSeqCon->m_SdoState = kEplAsySdoStateIdle; + // set rcon and scon to 0 + pAsySdoSeqCon->m_bSendSeqNum &= EPL_SEQ_NUM_MASK; + pAsySdoSeqCon->m_bRecSeqNum &= EPL_SEQ_NUM_MASK; + // send frame + EplSdoAsySeqSendIntern(pAsySdoSeqCon, + 0, + NULL, + FALSE); + + // call Command Layer Cb + AsySdoSequInstance_g.m_fpSdoComConCb(SdoSeqConHdl, + kAsySdoConStateTimeout); + } + + break; + } + + default: + // d.k. do nothing + break; + + }// end of switch(Event_p) + break; + } + + // wait for Acknowledge (history buffer full) + case kEplAsySdoStateWaitAck: + { + PRINTF0("EplSdoAsySequ: StateWaitAck\n"); + + // set timer + Ret = EplSdoAsySeqSetTimer(pAsySdoSeqCon, + EPL_SEQ_DEFAULT_TIMEOUT); + + //TODO: retry of acknowledge + if(Event_p == kAsySdoSeqEventFrameRec) + { + // check rcon + switch(pRecFrame_p->m_le_bRecSeqNumCon & EPL_ASY_SDO_CON_MASK) + { + // close-frome other node + case 0: + { + // return to idle + pAsySdoSeqCon->m_SdoState = kEplAsySdoStateIdle; + // delete timer + EplTimeruDeleteTimer(&pAsySdoSeqCon->m_EplTimerHdl); + // call Command Layer Cb + AsySdoSequInstance_g.m_fpSdoComConCb(SdoSeqConHdl, + kAsySdoConStateConClosed); + + break; + } + + // normal frame + case 2: + { + // should be ack + // -> change to state kEplAsySdoStateConnected + pAsySdoSeqCon->m_SdoState = kEplAsySdoStateConnected; + // call Command Layer Cb + AsySdoSequInstance_g.m_fpSdoComConCb(SdoSeqConHdl, + kAsySdoConStateAckReceived); + // send data to higher layer if needed + if(uiDataSize_p > EPL_SEQ_HEADER_SIZE) + { + AsySdoSequInstance_g.m_fpSdoComReceiveCb( + SdoSeqConHdl, + ((tEplAsySdoCom*) &pRecFrame_p->m_le_abSdoSeqPayload), + (uiDataSize_p - EPL_SEQ_HEADER_SIZE)); + } + break; + } + + // Request Ack or Error Ack + case 3: + { + // -> change to state kEplAsySdoStateConnected + pAsySdoSeqCon->m_SdoState = kEplAsySdoStateConnected; + + if(pRecFrame_p->m_le_bRecSeqNumCon == pAsySdoSeqCon->m_bRecSeqNum ) + { // ack request + // -> send ack + // save sequence numbers + pAsySdoSeqCon->m_bRecSeqNum = AmiGetByteFromLe(&pRecFrame_p->m_le_bRecSeqNumCon); + pAsySdoSeqCon->m_bSendSeqNum = AmiGetByteFromLe(&pRecFrame_p->m_le_bSendSeqNumCon); + + // create answer own rcon = 2 + pAsySdoSeqCon->m_bRecSeqNum--; + + // check if ack or data-frame + if(uiDataSize_p > EPL_SEQ_HEADER_SIZE) + { + AsySdoSequInstance_g.m_fpSdoComReceiveCb( + SdoSeqConHdl, + ((tEplAsySdoCom*) &pRecFrame_p->m_le_abSdoSeqPayload), + (uiDataSize_p - EPL_SEQ_HEADER_SIZE)); + // call Command Layer Cb + AsySdoSequInstance_g.m_fpSdoComConCb(SdoSeqConHdl, + kAsySdoConStateFrameSended); + + + } + else + { + Ret = EplSdoAsySeqSendIntern(pAsySdoSeqCon, + 0, + NULL, + FALSE); + if(Ret != kEplSuccessful) + { + goto Exit; + } + } + + } + else + { + // error ack + // resend frames from history + + // read frame from history + Ret = EplSdoAsyReadFromHistory(pAsySdoSeqCon, + &pEplFrame, + &uiFrameSize, + TRUE); + while ((pEplFrame != NULL) + && (uiFrameSize != 0)) + { + // send frame + Ret = EplSdoAsySeqSendLowerLayer(pAsySdoSeqCon, + uiFrameSize, + pEplFrame); + if(Ret != kEplSuccessful) + { + goto Exit; + } + // read next frame + + // read frame from history + Ret = EplSdoAsyReadFromHistory(pAsySdoSeqCon, + &pEplFrame, + &uiFrameSize, + FALSE); + } // end of while((pabFrame != NULL) + } + break; + } + }// end of switch(pRecFrame_p->m_le_bRecSeqNumCon & EPL_ASY_SDO_CON_MASK) + + } + else if(Event_p == kAsySdoSeqEventTimeout) + { // error -> Close + pAsySdoSeqCon->m_SdoState = kEplAsySdoStateIdle; + // set rcon and scon to 0 + pAsySdoSeqCon->m_bSendSeqNum &= EPL_SEQ_NUM_MASK; + pAsySdoSeqCon->m_bRecSeqNum &= EPL_SEQ_NUM_MASK; + // send frame + EplSdoAsySeqSendIntern(pAsySdoSeqCon, + 0, + NULL, + FALSE); + + // call Command Layer Cb + AsySdoSequInstance_g.m_fpSdoComConCb(SdoSeqConHdl, + kAsySdoConStateTimeout); + } + + break; + } + + // unknown state + default: + { + EPL_DBGLVL_SDO_TRACE0("Error: Unknown State in EplSdoAsySeqProcess\n"); + + } + }// end of switch(pAsySdoSeqCon->m_SdoState) + + + +Exit: + +#if defined(WIN32) || defined(_WIN32) + // leave critical section for process function + LeaveCriticalSection(AsySdoSequInstance_g.m_pCriticalSection); +#endif + return Ret; + +} + +//--------------------------------------------------------------------------- +// +// Function: EplSdoAsySeqSendIntern +// +// Description: intern function to create and send a frame +// -> if uiDataSize_p == 0 create a frame with infos from +// pAsySdoSeqCon_p +// +// +// +// Parameters: pAsySdoSeqCon_p = pointer to control structure of the connection +// uiDataSize_p = size of data frame to process (can be 0) +// -> without size of sequence header and Asnd header!!! +// pData_p = pointer to frame to process (can be NULL) +// fFrameInHistory = if TRUE frame is saved to history else not +// +// +// +// Returns: tEplKernel = errorcode +// +// +// State: +// +//--------------------------------------------------------------------------- +static tEplKernel EplSdoAsySeqSendIntern(tEplAsySdoSeqCon* pAsySdoSeqCon_p, + unsigned int uiDataSize_p, + tEplFrame* pData_p, + BOOL fFrameInHistory_p) +{ +tEplKernel Ret; +BYTE abFrame[EPL_SEQ_FRAME_SIZE]; +tEplFrame* pEplFrame; +unsigned int uiFreeEntries; + + if(pData_p == NULL) + { // set pointer to own frame + EPL_MEMSET(&abFrame[0], 0x00, sizeof(abFrame)); + pEplFrame = (tEplFrame*)&abFrame[0]; + } + else + { // set pointer to frame from calling function + pEplFrame = pData_p; + } + + if(fFrameInHistory_p != FALSE) + { + // check if only one free entry in history buffer + uiFreeEntries = EplSdoAsyGetFreeEntriesFromHistory(pAsySdoSeqCon_p); + if(uiFreeEntries == 1) + { // request an acknowledge in dataframe + // own scon = 3 + pAsySdoSeqCon_p->m_bRecSeqNum |= 0x03; + } + } + + // fillin header informations + // set service id sdo + AmiSetByteToLe( &pEplFrame->m_Data.m_Asnd.m_le_bServiceId, 0x05); + AmiSetByteToLe( &pEplFrame->m_Data.m_Asnd.m_Payload.m_SdoSequenceFrame.m_le_abReserved,0x00); + // set receive sequence number and rcon + AmiSetByteToLe( &pEplFrame->m_Data.m_Asnd.m_Payload.m_SdoSequenceFrame.m_le_bRecSeqNumCon, pAsySdoSeqCon_p->m_bSendSeqNum); + // set send sequence number and scon + AmiSetByteToLe( &pEplFrame->m_Data.m_Asnd.m_Payload.m_SdoSequenceFrame.m_le_bSendSeqNumCon, pAsySdoSeqCon_p->m_bRecSeqNum); + + // add size + uiDataSize_p += EPL_SEQ_HEADER_SIZE; + + + // forward frame to appropriate lower layer + Ret = EplSdoAsySeqSendLowerLayer(pAsySdoSeqCon_p, + uiDataSize_p, + pEplFrame); // pointer to frame + + // check if all allright + if ((Ret == kEplSuccessful) + && (fFrameInHistory_p != FALSE)) + { + // set own scon to 2 if needed + if((pAsySdoSeqCon_p->m_bRecSeqNum & 0x03) == 0x03) + { + pAsySdoSeqCon_p->m_bRecSeqNum--; + } + + // save frame to history + Ret = EplSdoAsyAddFrameToHistory(pAsySdoSeqCon_p, + pEplFrame, + uiDataSize_p); + if (Ret == kEplSdoSeqNoFreeHistory) + { // request Ack needed + Ret = kEplSdoSeqRequestAckNeeded; + } + + } + + return Ret; +} + +//--------------------------------------------------------------------------- +// +// Function: EplSdoAsySeqSendLowerLayer +// +// Description: intern function to send a previously created frame to lower layer +// +// Parameters: pAsySdoSeqCon_p = pointer to control structure of the connection +// uiDataSize_p = size of data frame to process (can be 0) +// -> without size of Asnd header!!! +// pData_p = pointer to frame to process (can be NULL) +// +// Returns: tEplKernel = errorcode +// +// +// State: +// +//--------------------------------------------------------------------------- +static tEplKernel EplSdoAsySeqSendLowerLayer(tEplAsySdoSeqCon* pAsySdoSeqCon_p, + unsigned int uiDataSize_p, + tEplFrame* pEplFrame_p) +{ +tEplKernel Ret; + + // call send-function + // check handle for UDP or Asnd + if ((pAsySdoSeqCon_p->m_ConHandle & EPL_SDO_ASY_HANDLE_MASK) == EPL_SDO_UDP_HANDLE) + { // send over UDP +#if(((EPL_MODULE_INTEGRATION) & (EPL_MODULE_SDO_UDP)) != 0) + Ret = EplSdoUdpuSendData(pAsySdoSeqCon_p->m_ConHandle, + pEplFrame_p, // pointer to frame + uiDataSize_p); +#else + Ret = kEplSdoSeqUnsupportedProt; +#endif + + } + else if ((pAsySdoSeqCon_p->m_ConHandle & EPL_SDO_ASY_HANDLE_MASK) == EPL_SDO_ASND_HANDLE) + { // ASND +#if(((EPL_MODULE_INTEGRATION) & (EPL_MODULE_SDO_ASND)) != 0) + Ret = EplSdoAsnduSendData(pAsySdoSeqCon_p->m_ConHandle, + pEplFrame_p, // pointer to frame + uiDataSize_p); +#else + Ret = kEplSdoSeqUnsupportedProt; +#endif + } + else + { // error + Ret = kEplSdoSeqInvalidHdl; + } + + return Ret; +} + +//--------------------------------------------------------------------------- +// +// Function: EplSdoAsyReceiveCb +// +// Description: callback-function for received frames from lower layer +// +// +// +// Parameters: ConHdl_p = handle of the connection +// pSdoSeqData_p = pointer to frame +// uiDataSize_p = size of frame +// +// +// Returns: tEplKernel = errorcode +// +// +// State: +// +//--------------------------------------------------------------------------- +tEplKernel PUBLIC EplSdoAsyReceiveCb ( + tEplSdoConHdl ConHdl_p, + tEplAsySdoSeq* pSdoSeqData_p, + unsigned int uiDataSize_p) +{ +tEplKernel Ret; +unsigned int uiCount = 0; +unsigned int uiFreeEntry = EPL_MAX_SDO_SEQ_CON; +tEplAsySdoSeqCon* pAsySdoSeqCon; + +#if defined(WIN32) || defined(_WIN32) + // enter critical section + EnterCriticalSection(AsySdoSequInstance_g.m_pCriticalSectionReceive); +#endif + + EPL_DBGLVL_SDO_TRACE2("Handle: 0x%x , First Databyte 0x%x\n", ConHdl_p,((BYTE*)pSdoSeqData_p)[0]); + + // search controll structure for this connection + pAsySdoSeqCon = &AsySdoSequInstance_g.m_AsySdoConnection[uiCount]; + while (uiCount < EPL_MAX_SDO_SEQ_CON) + { + if (pAsySdoSeqCon->m_ConHandle == ConHdl_p) + { + break; + } + else if ((pAsySdoSeqCon->m_ConHandle == 0) + && (uiFreeEntry == EPL_MAX_SDO_SEQ_CON)) + { + // free entry + uiFreeEntry = uiCount; + } + uiCount++; + pAsySdoSeqCon++; + } + + if (uiCount == EPL_MAX_SDO_SEQ_CON) + { // new connection + if (uiFreeEntry == EPL_MAX_SDO_SEQ_CON) + { + Ret = kEplSdoSeqNoFreeHandle; + goto Exit; + } + else + { + pAsySdoSeqCon = &AsySdoSequInstance_g.m_AsySdoConnection[uiFreeEntry]; + // save handle from lower layer + pAsySdoSeqCon->m_ConHandle = ConHdl_p; + // increment use counter + pAsySdoSeqCon->m_uiUseCount++; + uiCount = uiFreeEntry ; + } + } + + // call history ack function + Ret = EplSdoAsyAckFrameToHistory(pAsySdoSeqCon, + (AmiGetByteFromLe(&pSdoSeqData_p->m_le_bRecSeqNumCon)& EPL_SEQ_NUM_MASK)); + if (Ret != kEplSuccessful) + { + goto Exit; + } + +#if defined(WIN32) || defined(_WIN32) + // leave critical section + LeaveCriticalSection(AsySdoSequInstance_g.m_pCriticalSectionReceive); +#endif + + // call process function with pointer of frame and event kAsySdoSeqEventFrameRec + Ret = EplSdoAsySeqProcess(uiCount, + uiDataSize_p, + NULL, + pSdoSeqData_p, + kAsySdoSeqEventFrameRec); + + +Exit: + return Ret; +} + +//--------------------------------------------------------------------------- +// +// Function: EplSdoAsyInitHistory +// +// Description: inti function for history buffer +// +// +// +// Parameters: +// +// +// Returns: tEplKernel = errorcode +// +// +// State: +// +//--------------------------------------------------------------------------- +static tEplKernel EplSdoAsyInitHistory(void) +{ +tEplKernel Ret; +unsigned int uiCount; + + Ret = kEplSuccessful; + // init m_bFreeEntries in history-buffer + for(uiCount = 0; uiCount < EPL_MAX_SDO_SEQ_CON; uiCount++) + { + AsySdoSequInstance_g.m_AsySdoConnection[uiCount].m_SdoConHistory.m_bFreeEntries = EPL_SDO_HISTORY_SIZE; + } + + return Ret; +} + + +//--------------------------------------------------------------------------- +// +// Function: EplSdoAsyAddFrameToHistory +// +// Description: function to add a frame to the history buffer +// +// +// +// Parameters: pAsySdoSeqCon_p = pointer to control structure of this connection +// pFrame_p = pointer to frame +// uiSize_p = size of the frame +// -> without size of the ethernet header +// and the asnd header +// +// Returns: tEplKernel = errorcode +// +// +// State: +// +//--------------------------------------------------------------------------- +static tEplKernel EplSdoAsyAddFrameToHistory(tEplAsySdoSeqCon* pAsySdoSeqCon_p, + tEplFrame* pFrame_p, + unsigned int uiSize_p) +{ +tEplKernel Ret; +tEplAsySdoConHistory* pHistory; + + Ret = kEplSuccessful; + + // add frame to history buffer + + // check size + // $$$ d.k. EPL_SEQ_HISTORY_FRAME_SIZE includes the header size, but uiSize_p does not!!! + if(uiSize_p > EPL_SEQ_HISTROY_FRAME_SIZE) + { + Ret = kEplSdoSeqFrameSizeError; + goto Exit; + } + + // save pointer to history + pHistory = &pAsySdoSeqCon_p->m_SdoConHistory; + + + // check if a free entry is available + if(pHistory->m_bFreeEntries > 0) + { // write message in free entry + EPL_MEMCPY(&((tEplFrame*)pHistory->m_aabHistoryFrame[pHistory->m_bWrite])->m_le_bMessageType, + &pFrame_p->m_le_bMessageType, + uiSize_p + EPL_ASND_HEADER_SIZE); + // store size + pHistory->m_auiFrameSize[pHistory->m_bWrite] = uiSize_p; + + // decremend number of free bufferentries + pHistory->m_bFreeEntries--; + + // increment writeindex + pHistory->m_bWrite++; + + // check if write-index run over array-boarder + if(pHistory->m_bWrite == EPL_SDO_HISTORY_SIZE) + { + pHistory->m_bWrite = 0; + } + + } + else + { // no free entry + Ret = kEplSdoSeqNoFreeHistory; + } + +Exit: + return Ret; +} + + +//--------------------------------------------------------------------------- +// +// Function: EplSdoAsyAckFrameToHistory +// +// Description: function to delete acknowledged frames fron history buffer +// +// +// +// Parameters: pAsySdoSeqCon_p = pointer to control structure of this connection +// bRecSeqNumber_p = receive sequence number of the received frame +// +// +// Returns: tEplKernel = errorcode +// +// +// State: +// +//--------------------------------------------------------------------------- +static tEplKernel EplSdoAsyAckFrameToHistory(tEplAsySdoSeqCon* pAsySdoSeqCon_p, + BYTE bRecSeqNumber_p) +{ +tEplKernel Ret; +tEplAsySdoConHistory* pHistory; +BYTE bAckIndex; +BYTE bCurrentSeqNum; + + Ret = kEplSuccessful; + + // get pointer to history buffer + pHistory = &pAsySdoSeqCon_p->m_SdoConHistory; + + // release all acknowledged frames from history buffer + + // check if there are entries in history + if (pHistory->m_bFreeEntries < EPL_SDO_HISTORY_SIZE) + { + bAckIndex = pHistory->m_bAck; + do + { + bCurrentSeqNum = (((tEplFrame*)pHistory->m_aabHistoryFrame[bAckIndex])->m_Data.m_Asnd.m_Payload.m_SdoSequenceFrame.m_le_bSendSeqNumCon & EPL_SEQ_NUM_MASK); + if (((bRecSeqNumber_p - bCurrentSeqNum) & EPL_SEQ_NUM_MASK) + < EPL_SEQ_NUM_THRESHOLD) + { + pHistory->m_auiFrameSize[bAckIndex] = 0; + bAckIndex++; + pHistory->m_bFreeEntries++; + if (bAckIndex == EPL_SDO_HISTORY_SIZE) + { // read index run over array-boarder + bAckIndex = 0; + } + } + else + { // nothing to do anymore, + // because any further frame in history has larger sequence + // number than the acknowledge + goto Exit; + } + } + while ((((bRecSeqNumber_p - 1 - bCurrentSeqNum) & EPL_SEQ_NUM_MASK) + < EPL_SEQ_NUM_THRESHOLD) + && (pHistory->m_bWrite != bAckIndex)); + + // store local read-index to global var + pHistory->m_bAck = bAckIndex; + } + +Exit: + return Ret; +} + +//--------------------------------------------------------------------------- +// +// Function: EplSdoAsyReadFromHistory +// +// Description: function to one frame from history +// +// +// +// Parameters: pAsySdoSeqCon_p = pointer to control structure of this connection +// ppFrame_p = pointer to pointer to the buffer of the stored frame +// puiSize_p = OUT: size of the frame +// fInitRead = bool which indicate a start of retransmission +// -> return last not acknowledged message if TRUE +// +// +// Returns: tEplKernel = errorcode +// +// +// State: +// +//--------------------------------------------------------------------------- +static tEplKernel EplSdoAsyReadFromHistory(tEplAsySdoSeqCon* pAsySdoSeqCon_p, + tEplFrame** ppFrame_p, + unsigned int* puiSize_p, + BOOL fInitRead_p) +{ +tEplKernel Ret; +tEplAsySdoConHistory* pHistory; + + Ret = kEplSuccessful; + + // read one message from History + + // get pointer to history buffer + pHistory = &pAsySdoSeqCon_p->m_SdoConHistory; + + // check if init + if (fInitRead_p != FALSE) + { // initialize read index to the index which shall be acknowledged next + pHistory->m_bRead = pHistory->m_bAck; + } + + // check if entries are available for reading + if ((pHistory->m_bFreeEntries < EPL_SDO_HISTORY_SIZE) + && (pHistory->m_bWrite != pHistory->m_bRead)) + { +// PRINTF4("EplSdoAsyReadFromHistory(): init = %d, read = %u, write = %u, ack = %u", (int) fInitRead_p, (WORD)pHistory->m_bRead, (WORD)pHistory->m_bWrite, (WORD)pHistory->m_bAck); +// PRINTF2(", free entries = %u, next frame size = %u\n", (WORD)pHistory->m_bFreeEntries, pHistory->m_auiFrameSize[pHistory->m_bRead]); + + // return pointer to stored frame + *ppFrame_p = (tEplFrame*)pHistory->m_aabHistoryFrame[pHistory->m_bRead]; + + // save size + *puiSize_p = pHistory->m_auiFrameSize[pHistory->m_bRead]; + + pHistory->m_bRead++; + if(pHistory->m_bRead == EPL_SDO_HISTORY_SIZE) + { + pHistory->m_bRead = 0; + } + + } + else + { +// PRINTF3("EplSdoAsyReadFromHistory(): read = %u, ack = %u, free entries = %u, no frame\n", (WORD)pHistory->m_bRead, (WORD)pHistory->m_bAck, (WORD)pHistory->m_bFreeEntries); + + // no more frames to send + // return null pointer + *ppFrame_p = NULL; + + *puiSize_p = 0; + } + + return Ret; + +} + +//--------------------------------------------------------------------------- +// +// Function: EplSdoAsyGetFreeEntriesFromHistory +// +// Description: function returns the number of free histroy entries +// +// +// +// Parameters: pAsySdoSeqCon_p = pointer to control structure of this connection +// +// +// Returns: unsigned int = number of free entries +// +// +// State: +// +//--------------------------------------------------------------------------- +static unsigned int EplSdoAsyGetFreeEntriesFromHistory(tEplAsySdoSeqCon* pAsySdoSeqCon_p) +{ +unsigned int uiFreeEntries; + + uiFreeEntries = (unsigned int)pAsySdoSeqCon_p->m_SdoConHistory.m_bFreeEntries; + + return uiFreeEntries; +} + +//--------------------------------------------------------------------------- +// +// Function: EplSdoAsySeqSetTimer +// +// Description: function sets or modify timer in timermosule +// +// +// +// Parameters: pAsySdoSeqCon_p = pointer to control structure of this connection +// ulTimeout = timeout in ms +// +// +// Returns: unsigned int = number of free entries +// +// +// State: +// +//--------------------------------------------------------------------------- +static tEplKernel EplSdoAsySeqSetTimer(tEplAsySdoSeqCon* pAsySdoSeqCon_p, + unsigned long ulTimeout) +{ +tEplKernel Ret; +tEplTimerArg TimerArg; + + TimerArg.m_EventSink = kEplEventSinkSdoAsySeq; + TimerArg.m_ulArg = (unsigned long)pAsySdoSeqCon_p; + + if(pAsySdoSeqCon_p->m_EplTimerHdl == 0) + { // create new timer + Ret = EplTimeruSetTimerMs(&pAsySdoSeqCon_p->m_EplTimerHdl, + ulTimeout, + TimerArg); + } + else + { // modify exisiting timer + Ret = EplTimeruModifyTimerMs(&pAsySdoSeqCon_p->m_EplTimerHdl, + ulTimeout, + TimerArg); + + } + + + return Ret; +} + +// EOF + -- cgit v1.2.3