diff options
Diffstat (limited to 'drivers/staging/epl/EplSdoAsySequ.c')
-rw-r--r-- | drivers/staging/epl/EplSdoAsySequ.c | 2522 |
1 files changed, 2522 insertions, 0 deletions
diff --git a/drivers/staging/epl/EplSdoAsySequ.c b/drivers/staging/epl/EplSdoAsySequ.c new file mode 100644 index 00000000000..6b6a9975d78 --- /dev/null +++ b/drivers/staging/epl/EplSdoAsySequ.c @@ -0,0 +1,2522 @@ +/**************************************************************************** + + (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 <EPL asychronus SDO Sequence layer> */ +/* */ +/* */ +/***************************************************************************/ +// +// 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", + __func__, + 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 |