diff options
Diffstat (limited to 'drivers/staging/epl/EplSdoComu.c')
-rw-r--r-- | drivers/staging/epl/EplSdoComu.c | 3029 |
1 files changed, 3029 insertions, 0 deletions
diff --git a/drivers/staging/epl/EplSdoComu.c b/drivers/staging/epl/EplSdoComu.c new file mode 100644 index 00000000000..ce5af66bfed --- /dev/null +++ b/drivers/staging/epl/EplSdoComu.c @@ -0,0 +1,3029 @@ +/**************************************************************************** + + (c) SYSTEC electronic GmbH, D-07973 Greiz, August-Bebel-Str. 29 + www.systec-electronic.com + + Project: openPOWERLINK + + Description: source file for SDO Command 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: EplSdoComu.c,v $ + + $Author: D.Krueger $ + + $Revision: 1.14 $ $Date: 2008/10/17 15:32:32 $ + + $State: Exp $ + + Build Environment: + GCC V3.4 + + ------------------------------------------------------------------------- + + Revision History: + + 2006/06/26 k.t.: start of the implementation + +****************************************************************************/ + +#include "user/EplSdoComu.h" + +#if ((((EPL_MODULE_INTEGRATION) & (EPL_MODULE_SDOS)) == 0) &&\ + (((EPL_MODULE_INTEGRATION) & (EPL_MODULE_SDOC)) == 0) ) + + #error 'ERROR: At least SDO Server or SDO Client should be activate!' + +#endif + +#if (((EPL_MODULE_INTEGRATION) & (EPL_MODULE_SDOS)) != 0) + #if (((EPL_MODULE_INTEGRATION) & (EPL_MODULE_OBDU)) == 0) && (EPL_OBD_USE_KERNEL == FALSE) + + #error 'ERROR: SDO Server needs OBDu module!' + + #endif + +#endif + +/***************************************************************************/ +/* */ +/* */ +/* G L O B A L D E F I N I T I O N S */ +/* */ +/* */ +/***************************************************************************/ + +//--------------------------------------------------------------------------- +// const defines +//--------------------------------------------------------------------------- + +#ifndef EPL_MAX_SDO_COM_CON +#define EPL_MAX_SDO_COM_CON 5 +#endif + + +//--------------------------------------------------------------------------- +// local types +//--------------------------------------------------------------------------- + +// intern events +typedef enum +{ + kEplSdoComConEventSendFirst = 0x00, // first frame to send + kEplSdoComConEventRec = 0x01, // frame received + kEplSdoComConEventConEstablished= 0x02, // connection established + kEplSdoComConEventConClosed = 0x03, // connection closed + kEplSdoComConEventAckReceived = 0x04, // acknowledge received by lower layer + // -> continue sending + kEplSdoComConEventFrameSended = 0x05, // lower has send a frame + kEplSdoComConEventInitError = 0x06, // error duringinitialisiation + // of the connection + kEplSdoComConEventTimeout = 0x07 // timeout in lower layer +#if(((EPL_MODULE_INTEGRATION) & (EPL_MODULE_SDOC)) != 0) + + , + + kEplSdoComConEventInitCon = 0x08, // init connection (only client) + kEplSdoComConEventAbort = 0x09 // abort sdo transfer (only client) +#endif + + +}tEplSdoComConEvent; + +typedef enum +{ + kEplSdoComSendTypeReq = 0x00, // send a request + kEplSdoComSendTypeAckRes = 0x01, // send a resonse without data + kEplSdoComSendTypeRes = 0x02, // send response with data + kEplSdoComSendTypeAbort = 0x03 // send abort + +}tEplSdoComSendType; + +// state of the state maschine +typedef enum +{ + // General State + kEplSdoComStateIdle = 0x00, // idle state + +#if(((EPL_MODULE_INTEGRATION) & (EPL_MODULE_SDOS)) != 0) + // Server States + kEplSdoComStateServerSegmTrans = 0x01, // send following frames +#endif + + +#if(((EPL_MODULE_INTEGRATION) & (EPL_MODULE_SDOC)) != 0) + // Client States + kEplSdoComStateClientWaitInit = 0x10, // wait for init connection + // on lower layer + kEplSdoComStateClientConnected = 0x11, // connection established + kEplSdoComStateClientSegmTrans = 0x12 // send following frames +#endif + + + +} tEplSdoComState; + + +// control structure for transaction +typedef struct +{ + tEplSdoSeqConHdl m_SdoSeqConHdl; // if != 0 -> entry used + tEplSdoComState m_SdoComState; + BYTE m_bTransactionId; + unsigned int m_uiNodeId; // NodeId of the target + // -> needed to reinit connection + // after timeout + tEplSdoTransType m_SdoTransType; // Auto, Expedited, Segmented + tEplSdoServiceType m_SdoServiceType; // WriteByIndex, ReadByIndex + tEplSdoType m_SdoProtType; // protocol layer: Auto, Udp, Asnd, Pdo + BYTE* m_pData; // pointer to data + unsigned int m_uiTransSize; // number of bytes + // to transfer + unsigned int m_uiTransferredByte;// number of bytes + // already transferred + tEplSdoFinishedCb m_pfnTransferFinished;// callback function of the + // application + // -> called in the end of + // the SDO transfer + void* m_pUserArg; // user definable argument pointer + + DWORD m_dwLastAbortCode; // save the last abort code +#if(((EPL_MODULE_INTEGRATION) & (EPL_MODULE_SDOC)) != 0) + // only for client + unsigned int m_uiTargetIndex; // index to access + unsigned int m_uiTargetSubIndex; // subiondex to access + + // for future use + unsigned int m_uiTimeout; // timeout for this connection + +#endif + +} tEplSdoComCon; + +// instance table +typedef struct +{ + tEplSdoComCon m_SdoComCon[EPL_MAX_SDO_COM_CON]; + +#if defined(WIN32) || defined(_WIN32) + LPCRITICAL_SECTION m_pCriticalSection; + CRITICAL_SECTION m_CriticalSection; +#endif + +}tEplSdoComInstance; + +//--------------------------------------------------------------------------- +// modul globale vars +//--------------------------------------------------------------------------- +static tEplSdoComInstance SdoComInstance_g; +//--------------------------------------------------------------------------- +// local function prototypes +//--------------------------------------------------------------------------- +tEplKernel PUBLIC EplSdoComReceiveCb (tEplSdoSeqConHdl SdoSeqConHdl_p, + tEplAsySdoCom* pAsySdoCom_p, + unsigned int uiDataSize_p); + + +tEplKernel PUBLIC EplSdoComConCb (tEplSdoSeqConHdl SdoSeqConHdl_p, + tEplAsySdoConState AsySdoConState_p); + +static tEplKernel EplSdoComSearchConIntern(tEplSdoSeqConHdl SdoSeqConHdl_p, + tEplSdoComConEvent SdoComConEvent_p, + tEplAsySdoCom* pAsySdoCom_p); + +static tEplKernel EplSdoComProcessIntern(tEplSdoComConHdl SdoComCon_p, + tEplSdoComConEvent SdoComConEvent_p, + tEplAsySdoCom* pAsySdoCom_p); + +static tEplKernel EplSdoComTransferFinished(tEplSdoComConHdl SdoComCon_p, + tEplSdoComCon* pSdoComCon_p, + tEplSdoComConState SdoComConState_p); + +#if(((EPL_MODULE_INTEGRATION) & (EPL_MODULE_SDOS)) != 0) +static tEplKernel EplSdoComServerInitReadByIndex(tEplSdoComCon* pSdoComCon_p, + tEplAsySdoCom* pAsySdoCom_p); + +static tEplKernel EplSdoComServerSendFrameIntern(tEplSdoComCon* pSdoComCon_p, + unsigned int uiIndex_p, + unsigned int uiSubIndex_p, + tEplSdoComSendType SendType_p); + +static tEplKernel EplSdoComServerInitWriteByIndex(tEplSdoComCon* pSdoComCon_p, + tEplAsySdoCom* pAsySdoCom_p); +#endif + + +#if(((EPL_MODULE_INTEGRATION) & (EPL_MODULE_SDOC)) != 0) + +static tEplKernel EplSdoComClientSend(tEplSdoComCon* pSdoComCon_p); + +static tEplKernel EplSdoComClientProcessFrame(tEplSdoComConHdl SdoComCon_p, + tEplAsySdoCom* pAsySdoCom_p); + +static tEplKernel EplSdoComClientSendAbort(tEplSdoComCon* pSdoComCon_p, + DWORD dwAbortCode_p); +#endif + + + +/***************************************************************************/ +/* */ +/* */ +/* C L A S S <SDO Command Layer> */ +/* */ +/* */ +/***************************************************************************/ +// +// Description: SDO Command layer Modul +// +// +/***************************************************************************/ + +//=========================================================================// +// // +// P U B L I C F U N C T I O N S // +// // +//=========================================================================// + +//--------------------------------------------------------------------------- +// +// Function: EplSdoComInit +// +// Description: Init first instance of the module +// +// +// +// Parameters: +// +// +// Returns: tEplKernel = errorcode +// +// +// State: +// +//--------------------------------------------------------------------------- +tEplKernel PUBLIC EplSdoComInit(void) +{ +tEplKernel Ret; + + + Ret = EplSdoComAddInstance(); + +return Ret; + +} + +//--------------------------------------------------------------------------- +// +// Function: EplSdoComAddInstance +// +// Description: Init additional instance of the module +// +// +// +// Parameters: +// +// +// Returns: tEplKernel = errorcode +// +// +// State: +// +//--------------------------------------------------------------------------- +tEplKernel PUBLIC EplSdoComAddInstance(void) +{ +tEplKernel Ret; + + Ret = kEplSuccessful; + + // init controll structure + EPL_MEMSET(&SdoComInstance_g, 0x00, sizeof(SdoComInstance_g)); + + // init instance of lower layer + Ret = EplSdoAsySeqAddInstance(EplSdoComReceiveCb, EplSdoComConCb); + if(Ret != kEplSuccessful) + { + goto Exit; + } + +#if defined(WIN32) || defined(_WIN32) + // create critical section for process function + SdoComInstance_g.m_pCriticalSection = &SdoComInstance_g.m_CriticalSection; + InitializeCriticalSection(SdoComInstance_g.m_pCriticalSection); +#endif + +Exit: + return Ret; +} + +//--------------------------------------------------------------------------- +// +// Function: EplSdoComDelInstance +// +// Description: delete instance of the module +// +// +// +// Parameters: +// +// +// Returns: tEplKernel = errorcode +// +// +// State: +// +//--------------------------------------------------------------------------- +tEplKernel PUBLIC EplSdoComDelInstance(void) +{ +tEplKernel Ret; + + Ret = kEplSuccessful; + + +#if defined(WIN32) || defined(_WIN32) + // delete critical section for process function + DeleteCriticalSection(SdoComInstance_g.m_pCriticalSection); +#endif + + Ret = EplSdoAsySeqDelInstance(); + if(Ret != kEplSuccessful) + { + goto Exit; + } + + +Exit: + return Ret; +} + +//--------------------------------------------------------------------------- +// +// Function: EplSdoComDefineCon +// +// Description: function defines a SDO connection to another node +// -> init lower layer and returns a handle for the connection. +// Two client connections to the same node via the same protocol +// are not allowed. If this function detects such a situation +// it will return kEplSdoComHandleExists and the handle of +// the existing connection in pSdoComConHdl_p. +// Using of existing server connections is possible. +// +// Parameters: pSdoComConHdl_p = pointer to the buffer of the handle +// uiTargetNodeId_p = NodeId of the targetnode +// ProtType_p = type of protocol to use for connection +// +// +// Returns: tEplKernel = errorcode +// +// +// State: +// +//--------------------------------------------------------------------------- +#if(((EPL_MODULE_INTEGRATION) & (EPL_MODULE_SDOC)) != 0) +tEplKernel PUBLIC EplSdoComDefineCon(tEplSdoComConHdl* pSdoComConHdl_p, + unsigned int uiTargetNodeId_p, + tEplSdoType ProtType_p) +{ +tEplKernel Ret; +unsigned int uiCount; +unsigned int uiFreeHdl; +tEplSdoComCon* pSdoComCon; + + // check Parameter + ASSERT(pSdoComConHdl_p != NULL); + + // check NodeId + if((uiTargetNodeId_p == EPL_C_ADR_INVALID) + ||(uiTargetNodeId_p >= EPL_C_ADR_BROADCAST)) + { + Ret = kEplInvalidNodeId; + + } + + // search free control structure + pSdoComCon = &SdoComInstance_g.m_SdoComCon[0]; + uiCount = 0; + uiFreeHdl = EPL_MAX_SDO_COM_CON; + while (uiCount < EPL_MAX_SDO_COM_CON) + { + if (pSdoComCon->m_SdoSeqConHdl == 0) + { // free entry + uiFreeHdl = uiCount; + } + else if ((pSdoComCon->m_uiNodeId == uiTargetNodeId_p) + && (pSdoComCon->m_SdoProtType == ProtType_p)) + { // existing client connection with same node ID and same protocol type + *pSdoComConHdl_p = uiCount; + Ret = kEplSdoComHandleExists; + goto Exit; + } + uiCount++; + pSdoComCon++; + } + + if (uiFreeHdl == EPL_MAX_SDO_COM_CON) + { + Ret = kEplSdoComNoFreeHandle; + goto Exit; + } + + pSdoComCon = &SdoComInstance_g.m_SdoComCon[uiFreeHdl]; + // save handle for application + *pSdoComConHdl_p = uiFreeHdl; + // save parameters + pSdoComCon->m_SdoProtType = ProtType_p; + pSdoComCon->m_uiNodeId = uiTargetNodeId_p; + + // set Transaction Id + pSdoComCon->m_bTransactionId = 0; + + // check protocol + switch(ProtType_p) + { + // udp + case kEplSdoTypeUdp: + { + // call connection int function of lower layer + Ret = EplSdoAsySeqInitCon(&pSdoComCon->m_SdoSeqConHdl, + pSdoComCon->m_uiNodeId, + kEplSdoTypeUdp); + if(Ret != kEplSuccessful) + { + goto Exit; + } + break; + } + + // Asend + case kEplSdoTypeAsnd: + { + // call connection int function of lower layer + Ret = EplSdoAsySeqInitCon(&pSdoComCon->m_SdoSeqConHdl, + pSdoComCon->m_uiNodeId, + kEplSdoTypeAsnd); + if(Ret != kEplSuccessful) + { + goto Exit; + } + break; + } + + // Pdo -> not supported + case kEplSdoTypePdo: + default: + { + Ret = kEplSdoComUnsupportedProt; + goto Exit; + } + }// end of switch(m_ProtType_p) + + // call process function + Ret = EplSdoComProcessIntern(uiFreeHdl, + kEplSdoComConEventInitCon, + NULL); + +Exit: + return Ret; +} +#endif +//--------------------------------------------------------------------------- +// +// Function: EplSdoComInitTransferByIndex +// +// Description: function init SDO Transfer for a defined connection +// +// +// +// Parameters: SdoComTransParam_p = Structure with parameters for connection +// +// +// Returns: tEplKernel = errorcode +// +// +// State: +// +//--------------------------------------------------------------------------- +#if(((EPL_MODULE_INTEGRATION) & (EPL_MODULE_SDOC)) != 0) +tEplKernel PUBLIC EplSdoComInitTransferByIndex(tEplSdoComTransParamByIndex* pSdoComTransParam_p) +{ +tEplKernel Ret; +tEplSdoComCon* pSdoComCon; + + // check parameter + if ((pSdoComTransParam_p->m_uiSubindex >= 0xFF) + || (pSdoComTransParam_p->m_uiIndex == 0) + || (pSdoComTransParam_p->m_uiIndex > 0xFFFF) + || (pSdoComTransParam_p->m_pData == NULL) + || (pSdoComTransParam_p->m_uiDataSize == 0)) + { + Ret = kEplSdoComInvalidParam; + goto Exit; + } + + if(pSdoComTransParam_p->m_SdoComConHdl >= EPL_MAX_SDO_COM_CON) + { + Ret = kEplSdoComInvalidHandle; + goto Exit; + } + + // get pointer to control structure of connection + pSdoComCon = &SdoComInstance_g.m_SdoComCon[pSdoComTransParam_p->m_SdoComConHdl]; + + // check if handle ok + if(pSdoComCon->m_SdoSeqConHdl == 0) + { + Ret = kEplSdoComInvalidHandle; + goto Exit; + } + + // check if command layer is idle + if ((pSdoComCon->m_uiTransferredByte + pSdoComCon->m_uiTransSize) > 0) + { // handle is not idle + Ret = kEplSdoComHandleBusy; + goto Exit; + } + + // save parameter + // callback function for end of transfer + pSdoComCon->m_pfnTransferFinished = pSdoComTransParam_p->m_pfnSdoFinishedCb; + pSdoComCon->m_pUserArg = pSdoComTransParam_p->m_pUserArg; + + // set type of SDO command + if (pSdoComTransParam_p->m_SdoAccessType == kEplSdoAccessTypeRead) + { + pSdoComCon->m_SdoServiceType = kEplSdoServiceReadByIndex; + } + else + { + pSdoComCon->m_SdoServiceType = kEplSdoServiceWriteByIndex; + + } + // save pointer to data + pSdoComCon->m_pData = pSdoComTransParam_p->m_pData; + // maximal bytes to transfer + pSdoComCon->m_uiTransSize = pSdoComTransParam_p->m_uiDataSize; + // bytes already transfered + pSdoComCon->m_uiTransferredByte = 0; + + // reset parts of control structure + pSdoComCon->m_dwLastAbortCode = 0; + pSdoComCon->m_SdoTransType = kEplSdoTransAuto; + // save timeout + //pSdoComCon->m_uiTimeout = SdoComTransParam_p.m_uiTimeout; + + // save index and subindex + pSdoComCon->m_uiTargetIndex = pSdoComTransParam_p->m_uiIndex; + pSdoComCon->m_uiTargetSubIndex = pSdoComTransParam_p->m_uiSubindex; + + // call process function + Ret = EplSdoComProcessIntern(pSdoComTransParam_p->m_SdoComConHdl, + kEplSdoComConEventSendFirst, // event to start transfer + NULL); + +Exit: + return Ret; + +} +#endif + +//--------------------------------------------------------------------------- +// +// Function: EplSdoComUndefineCon +// +// Description: function undefine a SDO connection +// +// +// +// Parameters: SdoComConHdl_p = handle for the connection +// +// +// Returns: tEplKernel = errorcode +// +// +// State: +// +//--------------------------------------------------------------------------- +#if(((EPL_MODULE_INTEGRATION) & (EPL_MODULE_SDOC)) != 0) +tEplKernel PUBLIC EplSdoComUndefineCon(tEplSdoComConHdl SdoComConHdl_p) +{ +tEplKernel Ret; +tEplSdoComCon* pSdoComCon; + + Ret = kEplSuccessful; + + if(SdoComConHdl_p >= EPL_MAX_SDO_COM_CON) + { + Ret = kEplSdoComInvalidHandle; + goto Exit; + } + + // get pointer to control structure + pSdoComCon = &SdoComInstance_g.m_SdoComCon[SdoComConHdl_p]; + + // $$$ d.k. abort a running transfer before closing the sequence layer + + if(((pSdoComCon->m_SdoSeqConHdl & ~EPL_SDO_SEQ_HANDLE_MASK) != EPL_SDO_SEQ_INVALID_HDL) + && (pSdoComCon->m_SdoSeqConHdl != 0)) + { + // close connection in lower layer + switch(pSdoComCon->m_SdoProtType) + { + case kEplSdoTypeAsnd: + case kEplSdoTypeUdp: + { + Ret = EplSdoAsySeqDelCon(pSdoComCon->m_SdoSeqConHdl); + break; + } + + case kEplSdoTypePdo: + case kEplSdoTypeAuto: + default: + { + Ret = kEplSdoComUnsupportedProt; + goto Exit; + } + + }// end of switch(pSdoComCon->m_SdoProtType) + } + + + // clean controll structure + EPL_MEMSET(pSdoComCon, 0x00, sizeof(tEplSdoComCon)); +Exit: + return Ret; +} +#endif +//--------------------------------------------------------------------------- +// +// Function: EplSdoComGetState +// +// Description: function returns the state fo the connection +// +// +// +// Parameters: SdoComConHdl_p = handle for the connection +// pSdoComFinished_p = pointer to structur for sdo state +// +// +// Returns: tEplKernel = errorcode +// +// +// State: +// +//--------------------------------------------------------------------------- +#if(((EPL_MODULE_INTEGRATION) & (EPL_MODULE_SDOC)) != 0) +tEplKernel PUBLIC EplSdoComGetState(tEplSdoComConHdl SdoComConHdl_p, + tEplSdoComFinished* pSdoComFinished_p) +{ +tEplKernel Ret; +tEplSdoComCon* pSdoComCon; + + Ret = kEplSuccessful; + + if(SdoComConHdl_p >= EPL_MAX_SDO_COM_CON) + { + Ret = kEplSdoComInvalidHandle; + goto Exit; + } + + // get pointer to control structure + pSdoComCon = &SdoComInstance_g.m_SdoComCon[SdoComConHdl_p]; + + // check if handle ok + if(pSdoComCon->m_SdoSeqConHdl == 0) + { + Ret = kEplSdoComInvalidHandle; + goto Exit; + } + + pSdoComFinished_p->m_pUserArg = pSdoComCon->m_pUserArg; + pSdoComFinished_p->m_uiNodeId = pSdoComCon->m_uiNodeId; + pSdoComFinished_p->m_uiTargetIndex = pSdoComCon->m_uiTargetIndex; + pSdoComFinished_p->m_uiTargetSubIndex = pSdoComCon->m_uiTargetSubIndex; + pSdoComFinished_p->m_uiTransferredByte = pSdoComCon->m_uiTransferredByte; + pSdoComFinished_p->m_dwAbortCode = pSdoComCon->m_dwLastAbortCode; + pSdoComFinished_p->m_SdoComConHdl = SdoComConHdl_p; + if (pSdoComCon->m_SdoServiceType == kEplSdoServiceWriteByIndex) + { + pSdoComFinished_p->m_SdoAccessType = kEplSdoAccessTypeWrite; + } + else + { + pSdoComFinished_p->m_SdoAccessType = kEplSdoAccessTypeRead; + } + + if(pSdoComCon->m_dwLastAbortCode != 0) + { // sdo abort + pSdoComFinished_p->m_SdoComConState = kEplSdoComTransferRxAborted; + + // delete abort code + pSdoComCon->m_dwLastAbortCode = 0; + + } + else if((pSdoComCon->m_SdoSeqConHdl & ~EPL_SDO_SEQ_HANDLE_MASK)== EPL_SDO_SEQ_INVALID_HDL) + { // check state + pSdoComFinished_p->m_SdoComConState = kEplSdoComTransferLowerLayerAbort; + } + else if(pSdoComCon->m_SdoComState == kEplSdoComStateClientWaitInit) + { + // finished + pSdoComFinished_p->m_SdoComConState = kEplSdoComTransferNotActive; + } + else if(pSdoComCon->m_uiTransSize == 0) + { // finished + pSdoComFinished_p->m_SdoComConState = kEplSdoComTransferFinished; + } + +Exit: + return Ret; + +} +#endif +//--------------------------------------------------------------------------- +// +// Function: EplSdoComSdoAbort +// +// Description: function abort a sdo transfer +// +// +// +// Parameters: SdoComConHdl_p = handle for the connection +// dwAbortCode_p = abort code +// +// +// Returns: tEplKernel = errorcode +// +// +// State: +// +//--------------------------------------------------------------------------- +#if(((EPL_MODULE_INTEGRATION) & (EPL_MODULE_SDOC)) != 0) +tEplKernel PUBLIC EplSdoComSdoAbort(tEplSdoComConHdl SdoComConHdl_p, + DWORD dwAbortCode_p) +{ +tEplKernel Ret; +tEplSdoComCon* pSdoComCon; + + + if(SdoComConHdl_p >= EPL_MAX_SDO_COM_CON) + { + Ret = kEplSdoComInvalidHandle; + goto Exit; + } + + // get pointer to control structure of connection + pSdoComCon = &SdoComInstance_g.m_SdoComCon[SdoComConHdl_p]; + + // check if handle ok + if(pSdoComCon->m_SdoSeqConHdl == 0) + { + Ret = kEplSdoComInvalidHandle; + goto Exit; + } + + // save pointer to abort code + pSdoComCon->m_pData = (BYTE*)&dwAbortCode_p; + + Ret = EplSdoComProcessIntern(SdoComConHdl_p, + kEplSdoComConEventAbort, + (tEplAsySdoCom*)NULL); + +Exit: + return Ret; +} +#endif + +//=========================================================================// +// // +// P R I V A T E F U N C T I O N S // +// // +//=========================================================================// + +//--------------------------------------------------------------------------- +// +// Function: EplSdoComReceiveCb +// +// Description: callback function for SDO Sequence Layer +// -> indicates new data +// +// +// +// Parameters: SdoSeqConHdl_p = Handle for connection +// pAsySdoCom_p = pointer to data +// uiDataSize_p = size of data ($$$ not used yet, but it should) +// +// +// Returns: +// +// +// State: +// +//--------------------------------------------------------------------------- +tEplKernel PUBLIC EplSdoComReceiveCb (tEplSdoSeqConHdl SdoSeqConHdl_p, + tEplAsySdoCom* pAsySdoCom_p, + unsigned int uiDataSize_p) +{ +tEplKernel Ret; + + + // search connection internally + Ret = EplSdoComSearchConIntern(SdoSeqConHdl_p, + kEplSdoComConEventRec, + pAsySdoCom_p); + + EPL_DBGLVL_SDO_TRACE3("EplSdoComReceiveCb SdoSeqConHdl: 0x%X, First Byte of pAsySdoCom_p: 0x%02X, uiDataSize_p: 0x%04X\n", SdoSeqConHdl_p, (WORD)pAsySdoCom_p->m_le_abCommandData[0], uiDataSize_p); + + return Ret; +} + +//--------------------------------------------------------------------------- +// +// Function: EplSdoComConCb +// +// Description: callback function called by SDO Sequence Layer to inform +// command layer about state change of connection +// +// +// +// Parameters: SdoSeqConHdl_p = Handle of the connection +// AsySdoConState_p = Event of the connection +// +// +// Returns: tEplKernel = Errorcode +// +// +// State: +// +//--------------------------------------------------------------------------- +tEplKernel PUBLIC EplSdoComConCb (tEplSdoSeqConHdl SdoSeqConHdl_p, + tEplAsySdoConState AsySdoConState_p) +{ +tEplKernel Ret; +tEplSdoComConEvent SdoComConEvent = kEplSdoComConEventSendFirst; + + Ret = kEplSuccessful; + + // check state + switch(AsySdoConState_p) + { + case kAsySdoConStateConnected: + { + EPL_DBGLVL_SDO_TRACE0("Connection established\n"); + SdoComConEvent = kEplSdoComConEventConEstablished; + // start transmission if needed + break; + } + + case kAsySdoConStateInitError: + { + EPL_DBGLVL_SDO_TRACE0("Error during initialisation\n"); + SdoComConEvent = kEplSdoComConEventInitError; + // inform app about error and close sequence layer handle + break; + } + + case kAsySdoConStateConClosed: + { + EPL_DBGLVL_SDO_TRACE0("Connection closed\n"); + SdoComConEvent = kEplSdoComConEventConClosed; + // close sequence layer handle + break; + } + + case kAsySdoConStateAckReceived: + { + EPL_DBGLVL_SDO_TRACE0("Acknowlage received\n"); + SdoComConEvent = kEplSdoComConEventAckReceived; + // continue transmission + break; + } + + case kAsySdoConStateFrameSended: + { + EPL_DBGLVL_SDO_TRACE0("One Frame sent\n"); + SdoComConEvent = kEplSdoComConEventFrameSended; + // to continue transmission + break; + + } + + case kAsySdoConStateTimeout: + { + EPL_DBGLVL_SDO_TRACE0("Timeout\n"); + SdoComConEvent = kEplSdoComConEventTimeout; + // close sequence layer handle + break; + + } + }// end of switch(AsySdoConState_p) + + Ret = EplSdoComSearchConIntern(SdoSeqConHdl_p, + SdoComConEvent, + (tEplAsySdoCom*)NULL); + + return Ret; +} + +//--------------------------------------------------------------------------- +// +// Function: EplSdoComSearchConIntern +// +// Description: search a Sdo Sequence Layer connection handle in the +// control structure of the Command Layer +// +// Parameters: SdoSeqConHdl_p = Handle to search +// SdoComConEvent_p = event to process +// pAsySdoCom_p = pointer to received frame +// +// Returns: tEplKernel +// +// +// State: +// +//--------------------------------------------------------------------------- +static tEplKernel EplSdoComSearchConIntern(tEplSdoSeqConHdl SdoSeqConHdl_p, + tEplSdoComConEvent SdoComConEvent_p, + tEplAsySdoCom* pAsySdoCom_p) +{ +tEplKernel Ret; +tEplSdoComCon* pSdoComCon; +tEplSdoComConHdl HdlCount; +tEplSdoComConHdl HdlFree; + + Ret = kEplSdoComNotResponsible; + + // get pointer to first element of the array + pSdoComCon = &SdoComInstance_g.m_SdoComCon[0]; + HdlCount = 0; + HdlFree = 0xFFFF; + while (HdlCount < EPL_MAX_SDO_COM_CON) + { + if (pSdoComCon->m_SdoSeqConHdl == SdoSeqConHdl_p) + { // matching command layer handle found + Ret = EplSdoComProcessIntern(HdlCount, + SdoComConEvent_p, + pAsySdoCom_p); + } + else if ((pSdoComCon->m_SdoSeqConHdl == 0) + &&(HdlFree == 0xFFFF)) + { + HdlFree = HdlCount; + } + + pSdoComCon++; + HdlCount++; + } + + if (Ret == kEplSdoComNotResponsible) + { // no responsible command layer handle found + if (HdlFree == 0xFFFF) + { // no free handle + // delete connection immediately + // 2008/04/14 m.u./d.k. This connection actually does not exist. + // pSdoComCon is invalid. + // Ret = EplSdoAsySeqDelCon(pSdoComCon->m_SdoSeqConHdl); + Ret = kEplSdoComNoFreeHandle; + } + else + { // create new handle + HdlCount = HdlFree; + pSdoComCon = &SdoComInstance_g.m_SdoComCon[HdlCount]; + pSdoComCon->m_SdoSeqConHdl = SdoSeqConHdl_p; + Ret = EplSdoComProcessIntern(HdlCount, + SdoComConEvent_p, + pAsySdoCom_p); + } + } + + return Ret; + +} + +//--------------------------------------------------------------------------- +// +// Function: EplSdoComProcessIntern +// +// Description: search a Sdo Sequence Layer connection handle in the +// control structer of the Command Layer +// +// +// +// Parameters: SdoComCon_p = index of control structure of connection +// SdoComConEvent_p = event to process +// pAsySdoCom_p = pointer to received frame +// +// Returns: tEplKernel = errorcode +// +// +// State: +// +//--------------------------------------------------------------------------- +static tEplKernel EplSdoComProcessIntern(tEplSdoComConHdl SdoComCon_p, + tEplSdoComConEvent SdoComConEvent_p, + tEplAsySdoCom* pAsySdoCom_p) +{ +tEplKernel Ret; +tEplSdoComCon* pSdoComCon; +BYTE bFlag; + +#if(((EPL_MODULE_INTEGRATION) & (EPL_MODULE_SDOS)) != 0) +DWORD dwAbortCode; +unsigned int uiSize; +#endif + +#if defined(WIN32) || defined(_WIN32) + // enter critical section for process function + EnterCriticalSection(SdoComInstance_g.m_pCriticalSection); + EPL_DBGLVL_SDO_TRACE0("\n\tEnterCiticalSection EplSdoComProcessIntern\n\n"); +#endif + + Ret = kEplSuccessful; + + // get pointer to control structure + pSdoComCon = &SdoComInstance_g.m_SdoComCon[SdoComCon_p]; + + // process state maschine + switch(pSdoComCon->m_SdoComState) + { + // idle state + case kEplSdoComStateIdle: + { + // check events + switch(SdoComConEvent_p) + { +#if(((EPL_MODULE_INTEGRATION) & (EPL_MODULE_SDOC)) != 0) + // init con for client + case kEplSdoComConEventInitCon: + { + + // call of the init function already + // processed in EplSdoComDefineCon() + // only change state to kEplSdoComStateClientWaitInit + pSdoComCon->m_SdoComState = kEplSdoComStateClientWaitInit; + break; + } +#endif + + + // int con for server + case kEplSdoComConEventRec: + { +#if(((EPL_MODULE_INTEGRATION) & (EPL_MODULE_SDOS)) != 0) + // check if init of an transfer and no SDO abort + if ((pAsySdoCom_p->m_le_bFlags & 0x80) == 0) + { // SDO request + if ((pAsySdoCom_p->m_le_bFlags & 0x40) == 0) + { // no SDO abort + // save tansaction id + pSdoComCon->m_bTransactionId = AmiGetByteFromLe(&pAsySdoCom_p->m_le_bTransactionId); + // check command + switch(pAsySdoCom_p->m_le_bCommandId) + { + case kEplSdoServiceNIL: + { // simply acknowlegde NIL command on sequence layer + + Ret = EplSdoAsySeqSendData(pSdoComCon->m_SdoSeqConHdl, + 0, + (tEplFrame*)NULL); + + break; + } + + case kEplSdoServiceReadByIndex: + { // read by index + + // search entry an start transfer + EplSdoComServerInitReadByIndex(pSdoComCon, + pAsySdoCom_p); + // check next state + if(pSdoComCon->m_uiTransSize == 0) + { // ready -> stay idle + pSdoComCon->m_SdoComState = kEplSdoComStateIdle; + // reset abort code + pSdoComCon->m_dwLastAbortCode = 0; + } + else + { // segmented transfer + pSdoComCon->m_SdoComState = kEplSdoComStateServerSegmTrans; + } + + break; + } + + case kEplSdoServiceWriteByIndex: + { + + // search entry an start write + EplSdoComServerInitWriteByIndex(pSdoComCon, + pAsySdoCom_p); + // check next state + if(pSdoComCon->m_uiTransSize == 0) + { // already -> stay idle + pSdoComCon->m_SdoComState = kEplSdoComStateIdle; + // reset abort code + pSdoComCon->m_dwLastAbortCode = 0; + } + else + { // segmented transfer + pSdoComCon->m_SdoComState = kEplSdoComStateServerSegmTrans; + } + + break; + } + + default: + { + // unsupported command + // -> abort senden + dwAbortCode = EPL_SDOAC_UNKNOWN_COMMAND_SPECIFIER; + // send abort + pSdoComCon->m_pData = (BYTE*)&dwAbortCode; + Ret = EplSdoComServerSendFrameIntern(pSdoComCon, + 0, + 0, + kEplSdoComSendTypeAbort); + + } + + + }// end of switch(pAsySdoCom_p->m_le_bCommandId) + } + } + else + { // this command layer handle is not responsible + // (wrong direction or wrong transaction ID) + Ret = kEplSdoComNotResponsible; + goto Exit; + } +#endif // end of #if(((EPL_MODULE_INTEGRATION) & (EPL_MODULE_SDOS)) != 0) + + break; + } + + // connection closed + case kEplSdoComConEventInitError: + case kEplSdoComConEventTimeout: + case kEplSdoComConEventConClosed: + { + Ret = EplSdoAsySeqDelCon(pSdoComCon->m_SdoSeqConHdl); + // clean control structure + EPL_MEMSET(pSdoComCon, 0x00, sizeof(tEplSdoComCon)); + break; + } + + default: + // d.k. do nothing + break; + }// end of switch(SdoComConEvent_p) + break; + } + +#if(((EPL_MODULE_INTEGRATION) & (EPL_MODULE_SDOS)) != 0) + //------------------------------------------------------------------------- + // SDO Server part + // segmented transfer + case kEplSdoComStateServerSegmTrans: + { + // check events + switch(SdoComConEvent_p) + { + // send next frame + case kEplSdoComConEventAckReceived: + case kEplSdoComConEventFrameSended: + { + // check if it is a read + if(pSdoComCon->m_SdoServiceType == kEplSdoServiceReadByIndex) + { + // send next frame + EplSdoComServerSendFrameIntern(pSdoComCon, + 0, + 0, + kEplSdoComSendTypeRes); + // if all send -> back to idle + if(pSdoComCon->m_uiTransSize == 0) + { // back to idle + pSdoComCon->m_SdoComState = kEplSdoComStateIdle; + // reset abort code + pSdoComCon->m_dwLastAbortCode = 0; + } + + } + break; + } + + // process next frame + case kEplSdoComConEventRec: + { + // check if the frame is a SDO response and has the right transaction ID + bFlag = AmiGetByteFromLe(&pAsySdoCom_p->m_le_bFlags); + if (((bFlag & 0x80) != 0) && (AmiGetByteFromLe(&pAsySdoCom_p->m_le_bTransactionId) == pSdoComCon->m_bTransactionId)) + { + // check if it is a abort + if((bFlag & 0x40) != 0) + { // SDO abort + // clear control structure + pSdoComCon->m_uiTransSize = 0; + pSdoComCon->m_uiTransferredByte = 0; + // change state + pSdoComCon->m_SdoComState = kEplSdoComStateIdle; + // reset abort code + pSdoComCon->m_dwLastAbortCode = 0; + // d.k.: do not execute anything further on this command + break; + } + + // check if it is a write + if(pSdoComCon->m_SdoServiceType == kEplSdoServiceWriteByIndex) + { + // write data to OD + uiSize = AmiGetWordFromLe(&pAsySdoCom_p->m_le_wSegmentSize); + if(pSdoComCon->m_dwLastAbortCode == 0) + { + EPL_MEMCPY(pSdoComCon->m_pData, &pAsySdoCom_p->m_le_abCommandData[0],uiSize); + } + // update counter + pSdoComCon->m_uiTransferredByte += uiSize; + pSdoComCon->m_uiTransSize -= uiSize; + + // update pointer + if(pSdoComCon->m_dwLastAbortCode == 0) + { + (/*(BYTE*)*/pSdoComCon->m_pData) += uiSize; + } + + // check end of transfer + if((pAsySdoCom_p->m_le_bFlags & 0x30) == 0x30) + { // transfer ready + pSdoComCon->m_uiTransSize = 0; + + if(pSdoComCon->m_dwLastAbortCode == 0) + { + // send response + // send next frame + EplSdoComServerSendFrameIntern(pSdoComCon, + 0, + 0, + kEplSdoComSendTypeRes); + // if all send -> back to idle + if(pSdoComCon->m_uiTransSize == 0) + { // back to idle + pSdoComCon->m_SdoComState = kEplSdoComStateIdle; + // reset abort code + pSdoComCon->m_dwLastAbortCode = 0; + } + } + else + { // send dabort code + // send abort + pSdoComCon->m_pData = (BYTE*)&pSdoComCon->m_dwLastAbortCode; + Ret = EplSdoComServerSendFrameIntern(pSdoComCon, + 0, + 0, + kEplSdoComSendTypeAbort); + + // reset abort code + pSdoComCon->m_dwLastAbortCode = 0; + + } + } + else + { + // send acknowledge without any Command layer data + Ret = EplSdoAsySeqSendData(pSdoComCon->m_SdoSeqConHdl, + 0, + (tEplFrame*)NULL); + } + } + } + else + { // this command layer handle is not responsible + // (wrong direction or wrong transaction ID) + Ret = kEplSdoComNotResponsible; + goto Exit; + } + break; + } + + // connection closed + case kEplSdoComConEventInitError: + case kEplSdoComConEventTimeout: + case kEplSdoComConEventConClosed: + { + Ret = EplSdoAsySeqDelCon(pSdoComCon->m_SdoSeqConHdl); + // clean control structure + EPL_MEMSET(pSdoComCon, 0x00, sizeof(tEplSdoComCon)); + break; + } + + default: + // d.k. do nothing + break; + }// end of switch(SdoComConEvent_p) + + break; + } +#endif // endif of #if(((EPL_MODULE_INTEGRATION) & (EPL_MODULE_SDOS)) != 0) + + +#if(((EPL_MODULE_INTEGRATION) & (EPL_MODULE_SDOC)) != 0) + //------------------------------------------------------------------------- + // SDO Client part + // wait for finish of establishing connection + case kEplSdoComStateClientWaitInit: + { + + // if connection handle is invalid reinit connection + // d.k.: this will be done only on new events (i.e. InitTransfer) + if((pSdoComCon->m_SdoSeqConHdl & ~EPL_SDO_SEQ_HANDLE_MASK) == EPL_SDO_SEQ_INVALID_HDL) + { + // check kind of connection to reinit + // check protocol + switch(pSdoComCon->m_SdoProtType) + { + // udp + case kEplSdoTypeUdp: + { + // call connection int function of lower layer + Ret = EplSdoAsySeqInitCon(&pSdoComCon->m_SdoSeqConHdl, + pSdoComCon->m_uiNodeId, + kEplSdoTypeUdp); + if(Ret != kEplSuccessful) + { + goto Exit; + } + break; + } + + // Asend -> not supported + case kEplSdoTypeAsnd: + { + // call connection int function of lower layer + Ret = EplSdoAsySeqInitCon(&pSdoComCon->m_SdoSeqConHdl, + pSdoComCon->m_uiNodeId, + kEplSdoTypeAsnd); + if(Ret != kEplSuccessful) + { + goto Exit; + } + break; + } + + // Pdo -> not supported + case kEplSdoTypePdo: + default: + { + Ret = kEplSdoComUnsupportedProt; + goto Exit; + } + }// end of switch(m_ProtType_p) + // d.k.: reset transaction ID, because new sequence layer connection was initialized + // $$$ d.k. is this really necessary? + //pSdoComCon->m_bTransactionId = 0; + } + + // check events + switch(SdoComConEvent_p) + { + // connection established + case kEplSdoComConEventConEstablished: + { + //send first frame if needed + if((pSdoComCon->m_uiTransSize > 0) + &&(pSdoComCon->m_uiTargetIndex != 0)) + { // start SDO transfer + Ret = EplSdoComClientSend(pSdoComCon); + if(Ret != kEplSuccessful) + { + goto Exit; + } + + // check if segemted transfer + if(pSdoComCon->m_SdoTransType == kEplSdoTransSegmented) + { + pSdoComCon->m_SdoComState = kEplSdoComStateClientSegmTrans; + goto Exit; + } + } + // goto state kEplSdoComStateClientConnected + pSdoComCon->m_SdoComState = kEplSdoComStateClientConnected; + goto Exit; + } + + case kEplSdoComConEventSendFirst: + { + // infos for transfer already saved by function EplSdoComInitTransferByIndex + break; + } + + case kEplSdoComConEventConClosed: + case kEplSdoComConEventInitError: + case kEplSdoComConEventTimeout: + { + // close sequence layer handle + Ret = EplSdoAsySeqDelCon(pSdoComCon->m_SdoSeqConHdl); + pSdoComCon->m_SdoSeqConHdl |= EPL_SDO_SEQ_INVALID_HDL; + // call callback function + if (SdoComConEvent_p == kEplSdoComConEventTimeout) + { + pSdoComCon->m_dwLastAbortCode = EPL_SDOAC_TIME_OUT; + } + else + { + pSdoComCon->m_dwLastAbortCode = 0; + } + Ret = EplSdoComTransferFinished(SdoComCon_p, pSdoComCon, kEplSdoComTransferLowerLayerAbort); + // d.k.: do not clean control structure + break; + } + + default: + // d.k. do nothing + break; + + } // end of switch(SdoComConEvent_p) + break; + } + + // connected + case kEplSdoComStateClientConnected: + { + // check events + switch(SdoComConEvent_p) + { + // send a frame + case kEplSdoComConEventSendFirst: + case kEplSdoComConEventAckReceived: + case kEplSdoComConEventFrameSended: + { + Ret = EplSdoComClientSend(pSdoComCon); + if(Ret != kEplSuccessful) + { + goto Exit; + } + + // check if read transfer finished + if((pSdoComCon->m_uiTransSize == 0) + && (pSdoComCon->m_uiTransferredByte != 0) + && (pSdoComCon->m_SdoServiceType == kEplSdoServiceReadByIndex)) + { + // inc transaction id + pSdoComCon->m_bTransactionId++; + // call callback of application + pSdoComCon->m_dwLastAbortCode = 0; + Ret = EplSdoComTransferFinished(SdoComCon_p, pSdoComCon, kEplSdoComTransferFinished); + + goto Exit; + } + + // check if segemted transfer + if(pSdoComCon->m_SdoTransType == kEplSdoTransSegmented) + { + pSdoComCon->m_SdoComState = kEplSdoComStateClientSegmTrans; + goto Exit; + } + break; + } + + // frame received + case kEplSdoComConEventRec: + { + // check if the frame is a SDO response and has the right transaction ID + bFlag = AmiGetByteFromLe(&pAsySdoCom_p->m_le_bFlags); + if (((bFlag & 0x80) != 0) && (AmiGetByteFromLe(&pAsySdoCom_p->m_le_bTransactionId) == pSdoComCon->m_bTransactionId)) + { + // check if abort or not + if((bFlag & 0x40) != 0) + { + // send acknowledge without any Command layer data + Ret = EplSdoAsySeqSendData(pSdoComCon->m_SdoSeqConHdl, + 0, + (tEplFrame*)NULL); + // inc transaction id + pSdoComCon->m_bTransactionId++; + // save abort code + pSdoComCon->m_dwLastAbortCode = AmiGetDwordFromLe(&pAsySdoCom_p->m_le_abCommandData[0]); + // call callback of application + Ret = EplSdoComTransferFinished(SdoComCon_p, pSdoComCon, kEplSdoComTransferRxAborted); + + goto Exit; + } + else + { // normal frame received + // check frame + Ret = EplSdoComClientProcessFrame(SdoComCon_p, pAsySdoCom_p); + + // check if transfer ready + if(pSdoComCon->m_uiTransSize == 0) + { + // send acknowledge without any Command layer data + Ret = EplSdoAsySeqSendData(pSdoComCon->m_SdoSeqConHdl, + 0, + (tEplFrame*)NULL); + // inc transaction id + pSdoComCon->m_bTransactionId++; + // call callback of application + pSdoComCon->m_dwLastAbortCode = 0; + Ret = EplSdoComTransferFinished(SdoComCon_p, pSdoComCon, kEplSdoComTransferFinished); + + goto Exit; + } + + } + } + else + { // this command layer handle is not responsible + // (wrong direction or wrong transaction ID) + Ret = kEplSdoComNotResponsible; + goto Exit; + } + break; + } + + // connection closed event go back to kEplSdoComStateClientWaitInit + case kEplSdoComConEventConClosed: + { // connection closed by communication partner + // close sequence layer handle + Ret = EplSdoAsySeqDelCon(pSdoComCon->m_SdoSeqConHdl); + // set handle to invalid and enter kEplSdoComStateClientWaitInit + pSdoComCon->m_SdoSeqConHdl |= EPL_SDO_SEQ_INVALID_HDL; + // change state + pSdoComCon->m_SdoComState = kEplSdoComStateClientWaitInit; + + // call callback of application + pSdoComCon->m_dwLastAbortCode = 0; + Ret = EplSdoComTransferFinished(SdoComCon_p, pSdoComCon, kEplSdoComTransferLowerLayerAbort); + + goto Exit; + + break; + } + + // abort to send from higher layer + case kEplSdoComConEventAbort: + { + EplSdoComClientSendAbort(pSdoComCon,*((DWORD*)pSdoComCon->m_pData)); + + // inc transaction id + pSdoComCon->m_bTransactionId++; + // call callback of application + pSdoComCon->m_dwLastAbortCode = *((DWORD*)pSdoComCon->m_pData); + Ret = EplSdoComTransferFinished(SdoComCon_p, pSdoComCon, kEplSdoComTransferTxAborted); + + break; + } + + case kEplSdoComConEventInitError: + case kEplSdoComConEventTimeout: + { + // close sequence layer handle + Ret = EplSdoAsySeqDelCon(pSdoComCon->m_SdoSeqConHdl); + pSdoComCon->m_SdoSeqConHdl |= EPL_SDO_SEQ_INVALID_HDL; + // change state + pSdoComCon->m_SdoComState = kEplSdoComStateClientWaitInit; + // call callback of application + pSdoComCon->m_dwLastAbortCode = EPL_SDOAC_TIME_OUT; + Ret = EplSdoComTransferFinished(SdoComCon_p, pSdoComCon, kEplSdoComTransferLowerLayerAbort); + + } + + default: + // d.k. do nothing + break; + + } // end of switch(SdoComConEvent_p) + + break; + } + + // process segmented transfer + case kEplSdoComStateClientSegmTrans: + { + // check events + switch(SdoComConEvent_p) + { + // sned a frame + case kEplSdoComConEventSendFirst: + case kEplSdoComConEventAckReceived: + case kEplSdoComConEventFrameSended: + { + Ret = EplSdoComClientSend(pSdoComCon); + if(Ret != kEplSuccessful) + { + goto Exit; + } + + // check if read transfer finished + if((pSdoComCon->m_uiTransSize == 0) + && (pSdoComCon->m_SdoServiceType == kEplSdoServiceReadByIndex)) + { + // inc transaction id + pSdoComCon->m_bTransactionId++; + // change state + pSdoComCon->m_SdoComState = kEplSdoComStateClientConnected; + // call callback of application + pSdoComCon->m_dwLastAbortCode = 0; + Ret = EplSdoComTransferFinished(SdoComCon_p, pSdoComCon, kEplSdoComTransferFinished); + + goto Exit; + } + + break; + } + + // frame received + case kEplSdoComConEventRec: + { + // check if the frame is a response + bFlag = AmiGetByteFromLe(&pAsySdoCom_p->m_le_bFlags); + if (((bFlag & 0x80) != 0) && (AmiGetByteFromLe(&pAsySdoCom_p->m_le_bTransactionId) == pSdoComCon->m_bTransactionId)) + { + // check if abort or not + if((bFlag & 0x40) != 0) + { + // send acknowledge without any Command layer data + Ret = EplSdoAsySeqSendData(pSdoComCon->m_SdoSeqConHdl, + 0, + (tEplFrame*)NULL); + // inc transaction id + pSdoComCon->m_bTransactionId++; + // change state + pSdoComCon->m_SdoComState = kEplSdoComStateClientConnected; + // save abort code + pSdoComCon->m_dwLastAbortCode = AmiGetDwordFromLe(&pAsySdoCom_p->m_le_abCommandData[0]); + // call callback of application + Ret = EplSdoComTransferFinished(SdoComCon_p, pSdoComCon, kEplSdoComTransferRxAborted); + + goto Exit; + } + else + { // normal frame received + // check frame + Ret = EplSdoComClientProcessFrame(SdoComCon_p, pAsySdoCom_p); + + // check if transfer ready + if(pSdoComCon->m_uiTransSize == 0) + { + // send acknowledge without any Command layer data + Ret = EplSdoAsySeqSendData(pSdoComCon->m_SdoSeqConHdl, + 0, + (tEplFrame*)NULL); + // inc transaction id + pSdoComCon->m_bTransactionId++; + // change state + pSdoComCon->m_SdoComState = kEplSdoComStateClientConnected; + // call callback of application + pSdoComCon->m_dwLastAbortCode = 0; + Ret = EplSdoComTransferFinished(SdoComCon_p, pSdoComCon, kEplSdoComTransferFinished); + + } + + } + } + break; + } + + // connection closed event go back to kEplSdoComStateClientWaitInit + case kEplSdoComConEventConClosed: + { // connection closed by communication partner + // close sequence layer handle + Ret = EplSdoAsySeqDelCon(pSdoComCon->m_SdoSeqConHdl); + // set handle to invalid and enter kEplSdoComStateClientWaitInit + pSdoComCon->m_SdoSeqConHdl |= EPL_SDO_SEQ_INVALID_HDL; + // change state + pSdoComCon->m_SdoComState = kEplSdoComStateClientWaitInit; + // inc transaction id + pSdoComCon->m_bTransactionId++; + // call callback of application + pSdoComCon->m_dwLastAbortCode = 0; + Ret = EplSdoComTransferFinished(SdoComCon_p, pSdoComCon, kEplSdoComTransferFinished); + + break; + } + + // abort to send from higher layer + case kEplSdoComConEventAbort: + { + EplSdoComClientSendAbort(pSdoComCon,*((DWORD*)pSdoComCon->m_pData)); + + // inc transaction id + pSdoComCon->m_bTransactionId++; + // change state + pSdoComCon->m_SdoComState = kEplSdoComStateClientConnected; + // call callback of application + pSdoComCon->m_dwLastAbortCode = *((DWORD*)pSdoComCon->m_pData); + Ret = EplSdoComTransferFinished(SdoComCon_p, pSdoComCon, kEplSdoComTransferTxAborted); + + break; + } + + case kEplSdoComConEventInitError: + case kEplSdoComConEventTimeout: + { + // close sequence layer handle + Ret = EplSdoAsySeqDelCon(pSdoComCon->m_SdoSeqConHdl); + pSdoComCon->m_SdoSeqConHdl |= EPL_SDO_SEQ_INVALID_HDL; + // change state + pSdoComCon->m_SdoComState = kEplSdoComStateClientWaitInit; + // call callback of application + pSdoComCon->m_dwLastAbortCode = EPL_SDOAC_TIME_OUT; + Ret = EplSdoComTransferFinished(SdoComCon_p, pSdoComCon, kEplSdoComTransferLowerLayerAbort); + + } + + default: + // d.k. do nothing + break; + + } // end of switch(SdoComConEvent_p) + + break; + } +#endif // endo of #if(((EPL_MODULE_INTEGRATION) & (EPL_MODULE_SDOC)) != 0) + + }// end of switch(pSdoComCon->m_SdoComState) + + + +#if(((EPL_MODULE_INTEGRATION) & (EPL_MODULE_SDOC)) != 0) +Exit: +#endif + +#if defined(WIN32) || defined(_WIN32) + // leave critical section for process function + EPL_DBGLVL_SDO_TRACE0("\n\tLeaveCriticalSection EplSdoComProcessIntern\n\n"); + LeaveCriticalSection(SdoComInstance_g.m_pCriticalSection); + +#endif + + return Ret; + +} + + +//--------------------------------------------------------------------------- +// +// Function: EplSdoComServerInitReadByIndex +// +// Description: function start the processing of an read by index command +// +// +// +// Parameters: pSdoComCon_p = pointer to control structure of connection +// pAsySdoCom_p = pointer to received frame +// +// Returns: tEplKernel = errorcode +// +// +// State: +// +//--------------------------------------------------------------------------- +#if(((EPL_MODULE_INTEGRATION) & (EPL_MODULE_SDOS)) != 0) +static tEplKernel EplSdoComServerInitReadByIndex(tEplSdoComCon* pSdoComCon_p, + tEplAsySdoCom* pAsySdoCom_p) +{ +tEplKernel Ret; +unsigned int uiIndex; +unsigned int uiSubindex; +tEplObdSize EntrySize; +tEplObdAccess AccessType; +DWORD dwAbortCode; + + dwAbortCode = 0; + + // a init of a read could not be a segmented transfer + // -> no variable part of header + + // get index and subindex + uiIndex = AmiGetWordFromLe(&pAsySdoCom_p->m_le_abCommandData[0]); + uiSubindex = AmiGetByteFromLe(&pAsySdoCom_p->m_le_abCommandData[2]); + + // check accesstype of entry + // existens of entry +//#if(((EPL_MODULE_INTEGRATION) & (EPL_MODULE_OBDU)) != 0) + Ret = EplObduGetAccessType(uiIndex, uiSubindex, &AccessType); +/*#else + Ret = kEplObdSubindexNotExist; + AccessType = 0; +#endif*/ + if(Ret == kEplObdSubindexNotExist) + { // subentry doesn't exist + dwAbortCode = EPL_SDOAC_SUB_INDEX_NOT_EXIST; + // send abort + pSdoComCon_p->m_pData = (BYTE*)&dwAbortCode; + Ret = EplSdoComServerSendFrameIntern(pSdoComCon_p, + uiIndex, + uiSubindex, + kEplSdoComSendTypeAbort); + goto Exit; + } + else if(Ret != kEplSuccessful) + { // entry doesn't exist + dwAbortCode = EPL_SDOAC_OBJECT_NOT_EXIST; + // send abort + pSdoComCon_p->m_pData = (BYTE*)&dwAbortCode; + Ret = EplSdoComServerSendFrameIntern(pSdoComCon_p, + uiIndex, + uiSubindex, + kEplSdoComSendTypeAbort); + goto Exit; + } + + // compare accesstype must be read or const + if(((AccessType & kEplObdAccRead) == 0) + && ((AccessType & kEplObdAccConst) == 0)) + { + + if((AccessType & kEplObdAccWrite) != 0) + { + // entry read a write only object + dwAbortCode = EPL_SDOAC_READ_TO_WRITE_ONLY_OBJ; + } + else + { + dwAbortCode = EPL_SDOAC_UNSUPPORTED_ACCESS; + } + // send abort + pSdoComCon_p->m_pData = (BYTE*)&dwAbortCode; + Ret = EplSdoComServerSendFrameIntern(pSdoComCon_p, + uiIndex, + uiSubindex, + kEplSdoComSendTypeAbort); + goto Exit; + } + + // save service + pSdoComCon_p->m_SdoServiceType = kEplSdoServiceReadByIndex; + + // get size of object to see iof segmented or expedited transfer +//#if(((EPL_MODULE_INTEGRATION) & (EPL_MODULE_OBDU)) != 0) + EntrySize = EplObduGetDataSize(uiIndex, uiSubindex); +/*#else + EntrySize = 0; +#endif*/ + if(EntrySize > EPL_SDO_MAX_PAYLOAD) + { // segmented transfer + pSdoComCon_p->m_SdoTransType = kEplSdoTransSegmented; + // get pointer to object-entry data +//#if(((EPL_MODULE_INTEGRATION) & (EPL_MODULE_OBDU)) != 0) + pSdoComCon_p->m_pData = EplObduGetObjectDataPtr(uiIndex, uiSubindex); +//#endif + } + else + { // expedited transfer + pSdoComCon_p->m_SdoTransType = kEplSdoTransExpedited; + } + + pSdoComCon_p->m_uiTransSize = EntrySize; + pSdoComCon_p->m_uiTransferredByte = 0; + + Ret = EplSdoComServerSendFrameIntern(pSdoComCon_p, + uiIndex, + uiSubindex, + kEplSdoComSendTypeRes); + if(Ret != kEplSuccessful) + { + // error -> abort + dwAbortCode = EPL_SDOAC_GENERAL_ERROR; + // send abort + pSdoComCon_p->m_pData = (BYTE*)&dwAbortCode; + Ret = EplSdoComServerSendFrameIntern(pSdoComCon_p, + uiIndex, + uiSubindex, + kEplSdoComSendTypeAbort); + goto Exit; + } + +Exit: + return Ret; +} +#endif + +//--------------------------------------------------------------------------- +// +// Function: EplSdoComServerSendFrameIntern(); +// +// Description: function creats and send a frame for server +// +// +// +// Parameters: pSdoComCon_p = pointer to control structure of connection +// uiIndex_p = index to send if expedited transfer else 0 +// uiSubIndex_p = subindex to send if expedited transfer else 0 +// SendType_p = to of frame to send +// +// Returns: tEplKernel = errorcode +// +// +// State: +// +//--------------------------------------------------------------------------- +#if(((EPL_MODULE_INTEGRATION) & (EPL_MODULE_SDOS)) != 0) +static tEplKernel EplSdoComServerSendFrameIntern(tEplSdoComCon* pSdoComCon_p, + unsigned int uiIndex_p, + unsigned int uiSubIndex_p, + tEplSdoComSendType SendType_p) +{ +tEplKernel Ret; +BYTE abFrame[EPL_MAX_SDO_FRAME_SIZE]; +tEplFrame* pFrame; +tEplAsySdoCom* pCommandFrame; +unsigned int uiSizeOfFrame; +BYTE bFlag; + + Ret = kEplSuccessful; + + pFrame = (tEplFrame*)&abFrame[0]; + + EPL_MEMSET(&abFrame[0], 0x00, sizeof(abFrame)); + + // build generic part of frame + // get pointer to command layerpart of frame + pCommandFrame = &pFrame->m_Data.m_Asnd.m_Payload.m_SdoSequenceFrame.m_le_abSdoSeqPayload; + AmiSetByteToLe(&pCommandFrame->m_le_bCommandId, pSdoComCon_p->m_SdoServiceType); + AmiSetByteToLe(&pCommandFrame->m_le_bTransactionId, pSdoComCon_p->m_bTransactionId); + + // set size to header size + uiSizeOfFrame = 8; + + // check SendType + switch(SendType_p) + { + // requestframe to send + case kEplSdoComSendTypeReq: + { + // nothing to do for server + //-> error + Ret = kEplSdoComInvalidSendType; + break; + } + + // response without data to send + case kEplSdoComSendTypeAckRes: + { + // set response flag + AmiSetByteToLe(&pCommandFrame->m_le_bFlags, 0x80); + + // send frame + Ret = EplSdoAsySeqSendData(pSdoComCon_p->m_SdoSeqConHdl, + uiSizeOfFrame, + pFrame); + + break; + } + + // responsframe to send + case kEplSdoComSendTypeRes: + { + // set response flag + bFlag = AmiGetByteFromLe( &pCommandFrame->m_le_bFlags); + bFlag |= 0x80; + AmiSetByteToLe(&pCommandFrame->m_le_bFlags, bFlag); + + // check type of resonse + if(pSdoComCon_p->m_SdoTransType == kEplSdoTransExpedited) + { // Expedited transfer + // copy data in frame +//#if(((EPL_MODULE_INTEGRATION) & (EPL_MODULE_OBDU)) != 0) + Ret = EplObduReadEntryToLe(uiIndex_p, + uiSubIndex_p, + &pCommandFrame->m_le_abCommandData[0], + (tEplObdSize*)&pSdoComCon_p->m_uiTransSize); + if(Ret != kEplSuccessful) + { + goto Exit; + } +//#endif + + // set size of frame + AmiSetWordToLe(&pCommandFrame->m_le_wSegmentSize, (WORD) pSdoComCon_p->m_uiTransSize); + + // correct byte-counter + uiSizeOfFrame += pSdoComCon_p->m_uiTransSize; + pSdoComCon_p->m_uiTransferredByte += pSdoComCon_p->m_uiTransSize; + pSdoComCon_p->m_uiTransSize = 0; + + + // send frame + uiSizeOfFrame += pSdoComCon_p->m_uiTransSize; + Ret = EplSdoAsySeqSendData(pSdoComCon_p->m_SdoSeqConHdl, + uiSizeOfFrame, + pFrame); + } + else if(pSdoComCon_p->m_SdoTransType == kEplSdoTransSegmented) + { // segmented transfer + // distinguish between init, segment and complete + if(pSdoComCon_p->m_uiTransferredByte == 0) + { // init + // set init flag + bFlag = AmiGetByteFromLe( &pCommandFrame->m_le_bFlags); + bFlag |= 0x10; + AmiSetByteToLe(&pCommandFrame->m_le_bFlags, bFlag); + // init variable header + AmiSetDwordToLe(&pCommandFrame->m_le_abCommandData[0],pSdoComCon_p->m_uiTransSize); + // copy data in frame + EPL_MEMCPY(&pCommandFrame->m_le_abCommandData[4],pSdoComCon_p->m_pData, (EPL_SDO_MAX_PAYLOAD-4)); + + // correct byte-counter + pSdoComCon_p->m_uiTransSize -= (EPL_SDO_MAX_PAYLOAD-4); + pSdoComCon_p->m_uiTransferredByte += (EPL_SDO_MAX_PAYLOAD-4); + // move data pointer + pSdoComCon_p->m_pData +=(EPL_SDO_MAX_PAYLOAD-4); + + // set segment size + AmiSetWordToLe(&pCommandFrame->m_le_wSegmentSize,(EPL_SDO_MAX_PAYLOAD-4)); + + // send frame + uiSizeOfFrame += EPL_SDO_MAX_PAYLOAD; + Ret = EplSdoAsySeqSendData(pSdoComCon_p->m_SdoSeqConHdl, + uiSizeOfFrame, + pFrame); + + } + else if((pSdoComCon_p->m_uiTransferredByte > 0) + &&(pSdoComCon_p->m_uiTransSize > EPL_SDO_MAX_PAYLOAD)) + { // segment + // set segment flag + bFlag = AmiGetByteFromLe( &pCommandFrame->m_le_bFlags); + bFlag |= 0x20; + AmiSetByteToLe(&pCommandFrame->m_le_bFlags, bFlag); + + // copy data in frame + EPL_MEMCPY(&pCommandFrame->m_le_abCommandData[0],pSdoComCon_p->m_pData, EPL_SDO_MAX_PAYLOAD); + + // correct byte-counter + pSdoComCon_p->m_uiTransSize -= EPL_SDO_MAX_PAYLOAD; + pSdoComCon_p->m_uiTransferredByte += EPL_SDO_MAX_PAYLOAD; + // move data pointer + pSdoComCon_p->m_pData +=EPL_SDO_MAX_PAYLOAD; + + // set segment size + AmiSetWordToLe(&pCommandFrame->m_le_wSegmentSize,EPL_SDO_MAX_PAYLOAD); + + // send frame + uiSizeOfFrame += EPL_SDO_MAX_PAYLOAD; + Ret = EplSdoAsySeqSendData(pSdoComCon_p->m_SdoSeqConHdl, + uiSizeOfFrame, + pFrame); + } + else + { + if((pSdoComCon_p->m_uiTransSize == 0) + && (pSdoComCon_p->m_SdoServiceType != kEplSdoServiceWriteByIndex)) + { + goto Exit; + } + // complete + // set segment complete flag + bFlag = AmiGetByteFromLe( &pCommandFrame->m_le_bFlags); + bFlag |= 0x30; + AmiSetByteToLe(&pCommandFrame->m_le_bFlags, bFlag); + + // copy data in frame + EPL_MEMCPY(&pCommandFrame->m_le_abCommandData[0],pSdoComCon_p->m_pData, pSdoComCon_p->m_uiTransSize); + + // correct byte-counter + pSdoComCon_p->m_uiTransferredByte += pSdoComCon_p->m_uiTransSize; + + + // move data pointer + pSdoComCon_p->m_pData +=pSdoComCon_p->m_uiTransSize; + + // set segment size + AmiSetWordToLe(&pCommandFrame->m_le_wSegmentSize, (WORD) pSdoComCon_p->m_uiTransSize); + + // send frame + uiSizeOfFrame += pSdoComCon_p->m_uiTransSize; + pSdoComCon_p->m_uiTransSize = 0; + Ret = EplSdoAsySeqSendData(pSdoComCon_p->m_SdoSeqConHdl, + uiSizeOfFrame, + pFrame); + } + + } + break; + } + // abort to send + case kEplSdoComSendTypeAbort: + { + // set response and abort flag + bFlag = AmiGetByteFromLe( &pCommandFrame->m_le_bFlags); + bFlag |= 0xC0; + AmiSetByteToLe(&pCommandFrame->m_le_bFlags, bFlag); + + // copy abortcode to frame + AmiSetDwordToLe(&pCommandFrame->m_le_abCommandData[0], *((DWORD*)pSdoComCon_p->m_pData)); + + // set size of segment + AmiSetWordToLe(&pCommandFrame->m_le_wSegmentSize, sizeof(DWORD)); + + // update counter + pSdoComCon_p->m_uiTransferredByte = sizeof(DWORD); + pSdoComCon_p->m_uiTransSize = 0; + + // calc framesize + uiSizeOfFrame += sizeof(DWORD); + Ret = EplSdoAsySeqSendData(pSdoComCon_p->m_SdoSeqConHdl, + uiSizeOfFrame, + pFrame); + break; + } + } // end of switch(SendType_p) + +Exit: + return Ret; +} +#endif +//--------------------------------------------------------------------------- +// +// Function: EplSdoComServerInitWriteByIndex +// +// Description: function start the processing of an write by index command +// +// +// +// Parameters: pSdoComCon_p = pointer to control structure of connection +// pAsySdoCom_p = pointer to received frame +// +// Returns: tEplKernel = errorcode +// +// +// State: +// +//--------------------------------------------------------------------------- +#if(((EPL_MODULE_INTEGRATION) & (EPL_MODULE_SDOS)) != 0) +static tEplKernel EplSdoComServerInitWriteByIndex(tEplSdoComCon* pSdoComCon_p, + tEplAsySdoCom* pAsySdoCom_p) +{ +tEplKernel Ret = kEplSuccessful; +unsigned int uiIndex; +unsigned int uiSubindex; +unsigned int uiBytesToTransfer; +tEplObdSize EntrySize; +tEplObdAccess AccessType; +DWORD dwAbortCode; +BYTE* pbSrcData; + + dwAbortCode = 0; + + // a init of a write + // -> variable part of header possible + + // check if expedited or segmented transfer + if ((pAsySdoCom_p->m_le_bFlags & 0x30) == 0x10) + { // initiate segmented transfer + pSdoComCon_p->m_SdoTransType = kEplSdoTransSegmented; + // get index and subindex + uiIndex = AmiGetWordFromLe(&pAsySdoCom_p->m_le_abCommandData[4]); + uiSubindex = AmiGetByteFromLe(&pAsySdoCom_p->m_le_abCommandData[6]); + // get source-pointer for copy + pbSrcData = &pAsySdoCom_p->m_le_abCommandData[8]; + // save size + pSdoComCon_p->m_uiTransSize = AmiGetDwordFromLe(&pAsySdoCom_p->m_le_abCommandData[0]); + + } + else if ((pAsySdoCom_p->m_le_bFlags & 0x30) == 0x00) + { // expedited transfer + pSdoComCon_p->m_SdoTransType = kEplSdoTransExpedited; + // get index and subindex + uiIndex = AmiGetWordFromLe(&pAsySdoCom_p->m_le_abCommandData[0]); + uiSubindex = AmiGetByteFromLe(&pAsySdoCom_p->m_le_abCommandData[2]); + // get source-pointer for copy + pbSrcData = &pAsySdoCom_p->m_le_abCommandData[4]; + // save size + pSdoComCon_p->m_uiTransSize = AmiGetWordFromLe(&pAsySdoCom_p->m_le_wSegmentSize); + // subtract header + pSdoComCon_p->m_uiTransSize -= 4; + + } + else + { + // just ignore any other transfer type + goto Exit; + } + + // check accesstype of entry + // existens of entry +//#if(((EPL_MODULE_INTEGRATION) & (EPL_MODULE_OBDU)) != 0) + Ret = EplObduGetAccessType(uiIndex, uiSubindex, &AccessType); +/*#else + Ret = kEplObdSubindexNotExist; + AccessType = 0; +#endif*/ + if (Ret == kEplObdSubindexNotExist) + { // subentry doesn't exist + pSdoComCon_p->m_dwLastAbortCode = EPL_SDOAC_SUB_INDEX_NOT_EXIST; + // send abort + // d.k. This is wrong: k.t. not needed send abort on end of write + /*pSdoComCon_p->m_pData = (BYTE*)pSdoComCon_p->m_dwLastAbortCode; + Ret = EplSdoComServerSendFrameIntern(pSdoComCon_p, + uiIndex, + uiSubindex, + kEplSdoComSendTypeAbort);*/ + goto Abort; + } + else if(Ret != kEplSuccessful) + { // entry doesn't exist + pSdoComCon_p->m_dwLastAbortCode = EPL_SDOAC_OBJECT_NOT_EXIST; + // send abort + // d.k. This is wrong: k.t. not needed send abort on end of write + /* + pSdoComCon_p->m_pData = (BYTE*)&dwAbortCode; + Ret = EplSdoComServerSendFrameIntern(pSdoComCon_p, + uiIndex, + uiSubindex, + kEplSdoComSendTypeAbort);*/ + goto Abort; + } + + // compare accesstype must be read + if((AccessType & kEplObdAccWrite) == 0) + { + + if((AccessType & kEplObdAccRead) != 0) + { + // entry write a read only object + pSdoComCon_p->m_dwLastAbortCode = EPL_SDOAC_WRITE_TO_READ_ONLY_OBJ; + } + else + { + pSdoComCon_p->m_dwLastAbortCode = EPL_SDOAC_UNSUPPORTED_ACCESS; + } + // send abort + // d.k. This is wrong: k.t. not needed send abort on end of write + /*pSdoComCon_p->m_pData = (BYTE*)&dwAbortCode; + Ret = EplSdoComServerSendFrameIntern(pSdoComCon_p, + uiIndex, + uiSubindex, + kEplSdoComSendTypeAbort);*/ + goto Abort; + } + + // save service + pSdoComCon_p->m_SdoServiceType = kEplSdoServiceWriteByIndex; + + pSdoComCon_p->m_uiTransferredByte = 0; + + // write data to OD + if(pSdoComCon_p->m_SdoTransType == kEplSdoTransExpedited) + { // expedited transfer + // size checking is done by EplObduWriteEntryFromLe() + +//#if(((EPL_MODULE_INTEGRATION) & (EPL_MODULE_OBDU)) != 0) + Ret = EplObduWriteEntryFromLe(uiIndex, + uiSubindex, + pbSrcData, + pSdoComCon_p->m_uiTransSize); + switch (Ret) + { + case kEplSuccessful: + { + break; + } + + case kEplObdAccessViolation: + { + pSdoComCon_p->m_dwLastAbortCode = EPL_SDOAC_UNSUPPORTED_ACCESS; + // send abort + goto Abort; + } + + case kEplObdValueLengthError: + { + pSdoComCon_p->m_dwLastAbortCode = EPL_SDOAC_DATA_TYPE_LENGTH_NOT_MATCH; + // send abort + goto Abort; + } + + case kEplObdValueTooHigh: + { + pSdoComCon_p->m_dwLastAbortCode = EPL_SDOAC_VALUE_RANGE_TOO_HIGH; + // send abort + goto Abort; + } + + case kEplObdValueTooLow: + { + pSdoComCon_p->m_dwLastAbortCode = EPL_SDOAC_VALUE_RANGE_TOO_LOW; + // send abort + goto Abort; + } + + default: + { + pSdoComCon_p->m_dwLastAbortCode = EPL_SDOAC_GENERAL_ERROR; + // send abort + goto Abort; + } + } +//#endif + // send command acknowledge + Ret = EplSdoComServerSendFrameIntern(pSdoComCon_p, + 0, + 0, + kEplSdoComSendTypeAckRes); + + pSdoComCon_p->m_uiTransSize = 0; + goto Exit; + } + else + { + // get size of the object to check if it fits + // because we directly write to the destination memory + // d.k. no one calls the user OD callback function + + //#if(((EPL_MODULE_INTEGRATION) & (EPL_MODULE_OBDU)) != 0) + EntrySize = EplObduGetDataSize(uiIndex, uiSubindex); + /*#else + EntrySize = 0; + #endif*/ + if(EntrySize < pSdoComCon_p->m_uiTransSize) + { // parameter too big + pSdoComCon_p->m_dwLastAbortCode = EPL_SDOAC_DATA_TYPE_LENGTH_TOO_HIGH; + // send abort + // d.k. This is wrong: k.t. not needed send abort on end of write + /*pSdoComCon_p->m_pData = (BYTE*)&dwAbortCode; + Ret = EplSdoComServerSendFrameIntern(pSdoComCon_p, + uiIndex, + uiSubindex, + kEplSdoComSendTypeAbort);*/ + goto Abort; + } + + uiBytesToTransfer = AmiGetWordFromLe(&pAsySdoCom_p->m_le_wSegmentSize); + // eleminate header (Command header (8) + variable part (4) + Command header (4)) + uiBytesToTransfer -= 16; + // get pointer to object entry +//#if(((EPL_MODULE_INTEGRATION) & (EPL_MODULE_OBDU)) != 0) + pSdoComCon_p->m_pData = EplObduGetObjectDataPtr(uiIndex, + uiSubindex); +//#endif + if(pSdoComCon_p->m_pData == NULL) + { + pSdoComCon_p->m_dwLastAbortCode = EPL_SDOAC_GENERAL_ERROR; + // send abort + // d.k. This is wrong: k.t. not needed send abort on end of write +/* pSdoComCon_p->m_pData = (BYTE*)&pSdoComCon_p->m_dwLastAbortCode; + Ret = EplSdoComServerSendFrameIntern(pSdoComCon_p, + uiIndex, + uiSubindex, + kEplSdoComSendTypeAbort);*/ + goto Abort; + } + + // copy data + EPL_MEMCPY(pSdoComCon_p->m_pData, pbSrcData, uiBytesToTransfer); + + // update internal counter + pSdoComCon_p->m_uiTransferredByte = uiBytesToTransfer; + pSdoComCon_p->m_uiTransSize -= uiBytesToTransfer; + + // update target pointer + (/*(BYTE*)*/pSdoComCon_p->m_pData) += uiBytesToTransfer; + + // send acknowledge without any Command layer data + Ret = EplSdoAsySeqSendData(pSdoComCon_p->m_SdoSeqConHdl, + 0, + (tEplFrame*)NULL); + goto Exit; + } + +Abort: + if(pSdoComCon_p->m_dwLastAbortCode != 0) + { + // send abort + pSdoComCon_p->m_pData = (BYTE*)&pSdoComCon_p->m_dwLastAbortCode; + Ret = EplSdoComServerSendFrameIntern(pSdoComCon_p, + uiIndex, + uiSubindex, + kEplSdoComSendTypeAbort); + + // reset abort code + pSdoComCon_p->m_dwLastAbortCode = 0; + pSdoComCon_p->m_uiTransSize = 0; + goto Exit; + } + +Exit: + return Ret; +} +#endif + +//--------------------------------------------------------------------------- +// +// Function: EplSdoComClientSend +// +// Description: function starts an sdo transfer an send all further frames +// +// +// +// Parameters: pSdoComCon_p = pointer to control structure of connection +// +// Returns: tEplKernel = errorcode +// +// +// State: +// +//--------------------------------------------------------------------------- +#if(((EPL_MODULE_INTEGRATION) & (EPL_MODULE_SDOC)) != 0) +static tEplKernel EplSdoComClientSend(tEplSdoComCon* pSdoComCon_p) +{ +tEplKernel Ret; +BYTE abFrame[EPL_MAX_SDO_FRAME_SIZE]; +tEplFrame* pFrame; +tEplAsySdoCom* pCommandFrame; +unsigned int uiSizeOfFrame; +BYTE bFlags; +BYTE* pbPayload; + + Ret = kEplSuccessful; + + pFrame = (tEplFrame*)&abFrame[0]; + + EPL_MEMSET(&abFrame[0], 0x00, sizeof(abFrame)); + + // build generic part of frame + // get pointer to command layerpart of frame + pCommandFrame = &pFrame->m_Data.m_Asnd.m_Payload.m_SdoSequenceFrame.m_le_abSdoSeqPayload; + AmiSetByteToLe( &pCommandFrame->m_le_bCommandId, pSdoComCon_p->m_SdoServiceType); + AmiSetByteToLe( &pCommandFrame->m_le_bTransactionId, pSdoComCon_p->m_bTransactionId); + + // set size constant part of header + uiSizeOfFrame = 8; + + // check if first frame to send -> command header needed + if (pSdoComCon_p->m_uiTransSize > 0) + { + if (pSdoComCon_p->m_uiTransferredByte == 0) + { // start SDO transfer + // check if segmented or expedited transfer + // only for write commands + switch(pSdoComCon_p->m_SdoServiceType) + { + case kEplSdoServiceReadByIndex: + { // first frame of read access always expedited + pSdoComCon_p->m_SdoTransType = kEplSdoTransExpedited; + pbPayload = &pCommandFrame->m_le_abCommandData[0]; + // fill rest of header + AmiSetWordToLe( &pCommandFrame->m_le_wSegmentSize, 4); + + // create command header + AmiSetWordToLe(pbPayload, (WORD)pSdoComCon_p->m_uiTargetIndex); + pbPayload += 2; + AmiSetByteToLe(pbPayload, (BYTE)pSdoComCon_p->m_uiTargetSubIndex); + // calc size + uiSizeOfFrame += 4; + + // set pSdoComCon_p->m_uiTransferredByte to one + pSdoComCon_p->m_uiTransferredByte = 1; + break; + } + + case kEplSdoServiceWriteByIndex: + { + if(pSdoComCon_p->m_uiTransSize > EPL_SDO_MAX_PAYLOAD ) + { // segmented transfer + // -> variable part of header needed + // save that transfer is segmented + pSdoComCon_p->m_SdoTransType = kEplSdoTransSegmented; + // fill variable part of header + AmiSetDwordToLe( &pCommandFrame->m_le_abCommandData[0], pSdoComCon_p->m_uiTransSize); + // set pointer to real payload + pbPayload = &pCommandFrame->m_le_abCommandData[4]; + // fill rest of header + AmiSetWordToLe( &pCommandFrame->m_le_wSegmentSize, EPL_SDO_MAX_PAYLOAD); + bFlags = 0x10; + AmiSetByteToLe( &pCommandFrame->m_le_bFlags, bFlags); + // create command header + AmiSetWordToLe(pbPayload, (WORD) pSdoComCon_p->m_uiTargetIndex); + pbPayload += 2; + AmiSetByteToLe(pbPayload, (BYTE)pSdoComCon_p->m_uiTargetSubIndex); + // on byte for reserved + pbPayload += 2; + // calc size + uiSizeOfFrame += EPL_SDO_MAX_PAYLOAD; + + // copy payload + EPL_MEMCPY( pbPayload,pSdoComCon_p->m_pData, (EPL_SDO_MAX_PAYLOAD - 8)); + pSdoComCon_p->m_pData += (EPL_SDO_MAX_PAYLOAD - 8); + // correct intern counter + pSdoComCon_p->m_uiTransSize -= (EPL_SDO_MAX_PAYLOAD - 8); + pSdoComCon_p->m_uiTransferredByte = (EPL_SDO_MAX_PAYLOAD - 8); + + } + else + { // expedited trandsfer + // save that transfer is expedited + pSdoComCon_p->m_SdoTransType = kEplSdoTransExpedited; + pbPayload = &pCommandFrame->m_le_abCommandData[0]; + + // create command header + AmiSetWordToLe(pbPayload, (WORD) pSdoComCon_p->m_uiTargetIndex); + pbPayload += 2; + AmiSetByteToLe(pbPayload, (BYTE)pSdoComCon_p->m_uiTargetSubIndex); + // + 2 -> one byte for subindex and one byte reserved + pbPayload += 2; + // copy data + EPL_MEMCPY( pbPayload,pSdoComCon_p->m_pData, pSdoComCon_p->m_uiTransSize); + // calc size + uiSizeOfFrame += (4 + pSdoComCon_p->m_uiTransSize); + // fill rest of header + AmiSetWordToLe( &pCommandFrame->m_le_wSegmentSize, (WORD) (4 + pSdoComCon_p->m_uiTransSize)); + + pSdoComCon_p->m_uiTransferredByte = pSdoComCon_p->m_uiTransSize; + pSdoComCon_p->m_uiTransSize = 0; + } + break; + } + + case kEplSdoServiceNIL: + default: + // invalid service requested + Ret = kEplSdoComInvalidServiceType; + goto Exit; + } // end of switch(pSdoComCon_p->m_SdoServiceType) + } + else // (pSdoComCon_p->m_uiTransferredByte > 0) + { // continue SDO transfer + switch(pSdoComCon_p->m_SdoServiceType) + { + // for expedited read is nothing to do + // -> server sends data + + case kEplSdoServiceWriteByIndex: + { // send next frame + if(pSdoComCon_p->m_SdoTransType == kEplSdoTransSegmented) + { + if(pSdoComCon_p->m_uiTransSize > EPL_SDO_MAX_PAYLOAD) + { // next segment + pbPayload = &pCommandFrame->m_le_abCommandData[0]; + // fill rest of header + AmiSetWordToLe( &pCommandFrame->m_le_wSegmentSize, EPL_SDO_MAX_PAYLOAD); + bFlags = 0x20; + AmiSetByteToLe( &pCommandFrame->m_le_bFlags, bFlags); + // copy data + EPL_MEMCPY( pbPayload,pSdoComCon_p->m_pData, EPL_SDO_MAX_PAYLOAD); + pSdoComCon_p->m_pData += EPL_SDO_MAX_PAYLOAD; + // correct intern counter + pSdoComCon_p->m_uiTransSize -= EPL_SDO_MAX_PAYLOAD; + pSdoComCon_p->m_uiTransferredByte = EPL_SDO_MAX_PAYLOAD; + // calc size + uiSizeOfFrame += EPL_SDO_MAX_PAYLOAD; + + + } + else + { // end of transfer + pbPayload = &pCommandFrame->m_le_abCommandData[0]; + // fill rest of header + AmiSetWordToLe( &pCommandFrame->m_le_wSegmentSize, (WORD) pSdoComCon_p->m_uiTransSize); + bFlags = 0x30; + AmiSetByteToLe( &pCommandFrame->m_le_bFlags, bFlags); + // copy data + EPL_MEMCPY( pbPayload,pSdoComCon_p->m_pData, pSdoComCon_p->m_uiTransSize); + pSdoComCon_p->m_pData += pSdoComCon_p->m_uiTransSize; + // calc size + uiSizeOfFrame += pSdoComCon_p->m_uiTransSize; + // correct intern counter + pSdoComCon_p->m_uiTransSize = 0; + pSdoComCon_p->m_uiTransferredByte = pSdoComCon_p->m_uiTransSize; + + } + } + else + { + goto Exit; + } + break; + } + default: + { + goto Exit; + } + } // end of switch(pSdoComCon_p->m_SdoServiceType) + } + } + else + { + goto Exit; + } + + + // call send function of lower layer + switch(pSdoComCon_p->m_SdoProtType) + { + case kEplSdoTypeAsnd: + case kEplSdoTypeUdp: + { + Ret = EplSdoAsySeqSendData(pSdoComCon_p->m_SdoSeqConHdl, + uiSizeOfFrame, + pFrame); + break; + } + + default: + { + Ret = kEplSdoComUnsupportedProt; + } + } // end of switch(pSdoComCon_p->m_SdoProtType) + + +Exit: + return Ret; + +} +#endif +//--------------------------------------------------------------------------- +// +// Function: EplSdoComClientProcessFrame +// +// Description: function process a received frame +// +// +// +// Parameters: SdoComCon_p = connection handle +// pAsySdoCom_p = pointer to frame to process +// +// Returns: tEplKernel = errorcode +// +// +// State: +// +//--------------------------------------------------------------------------- +#if(((EPL_MODULE_INTEGRATION) & (EPL_MODULE_SDOC)) != 0) +static tEplKernel EplSdoComClientProcessFrame(tEplSdoComConHdl SdoComCon_p, + tEplAsySdoCom* pAsySdoCom_p) +{ +tEplKernel Ret; +BYTE bBuffer; +unsigned int uiBuffer; +unsigned int uiDataSize; +unsigned long ulBuffer; +tEplSdoComCon* pSdoComCon; + + + Ret = kEplSuccessful; + + // get pointer to control structure + pSdoComCon = &SdoComInstance_g.m_SdoComCon[SdoComCon_p]; + + // check if transaction Id fit + bBuffer = AmiGetByteFromLe(&pAsySdoCom_p->m_le_bTransactionId); + if(pSdoComCon->m_bTransactionId != bBuffer) + { + // incorrect transaction id + + // if running transfer + if((pSdoComCon->m_uiTransferredByte != 0) + && (pSdoComCon->m_uiTransSize !=0)) + { + pSdoComCon->m_dwLastAbortCode = EPL_SDOAC_GENERAL_ERROR; + // -> send abort + EplSdoComClientSendAbort(pSdoComCon, pSdoComCon->m_dwLastAbortCode); + // call callback of application + Ret = EplSdoComTransferFinished(SdoComCon_p, pSdoComCon, kEplSdoComTransferTxAborted); + } + + } + else + { // check if correct command + bBuffer = AmiGetByteFromLe(&pAsySdoCom_p->m_le_bCommandId); + if(pSdoComCon->m_SdoServiceType != bBuffer) + { + // incorrect command + // if running transfer + if((pSdoComCon->m_uiTransferredByte != 0) + && (pSdoComCon->m_uiTransSize !=0)) + { + pSdoComCon->m_dwLastAbortCode = EPL_SDOAC_GENERAL_ERROR; + // -> send abort + EplSdoComClientSendAbort(pSdoComCon, pSdoComCon->m_dwLastAbortCode); + // call callback of application + Ret = EplSdoComTransferFinished(SdoComCon_p, pSdoComCon, kEplSdoComTransferTxAborted); + } + + } + else + { // switch on command + switch(pSdoComCon->m_SdoServiceType) + { + case kEplSdoServiceWriteByIndex: + { // check if confirmation from server + // nothing more to do + break; + } + + case kEplSdoServiceReadByIndex: + { // check if it is an segmented or an expedited transfer + bBuffer = AmiGetByteFromLe(&pAsySdoCom_p->m_le_bFlags); + // mask uninteressting bits + bBuffer &= 0x30; + switch(bBuffer) + { + // expedited transfer + case 0x00: + { + // check size of buffer + uiBuffer = AmiGetWordFromLe(&pAsySdoCom_p->m_le_wSegmentSize); + if(uiBuffer > pSdoComCon->m_uiTransSize) + { // buffer provided by the application is to small + // copy only a part + uiDataSize = pSdoComCon->m_uiTransSize; + } + else + { // buffer fits + uiDataSize = uiBuffer; + } + + // copy data + EPL_MEMCPY(pSdoComCon->m_pData, &pAsySdoCom_p->m_le_abCommandData[0], uiDataSize); + + // correct counter + pSdoComCon->m_uiTransSize = 0; + pSdoComCon->m_uiTransferredByte = uiDataSize; + break; + } + + // start of a segmented transfer + case 0x10: + { // get total size of transfer + ulBuffer = AmiGetDwordFromLe(&pAsySdoCom_p->m_le_abCommandData[0]); + if(ulBuffer <= pSdoComCon->m_uiTransSize) + { // buffer fit + pSdoComCon->m_uiTransSize = (unsigned int)ulBuffer; + } + else + { // buffer to small + // send abort + pSdoComCon->m_dwLastAbortCode = EPL_SDOAC_DATA_TYPE_LENGTH_TOO_HIGH; + // -> send abort + EplSdoComClientSendAbort(pSdoComCon, pSdoComCon->m_dwLastAbortCode); + // call callback of application + Ret = EplSdoComTransferFinished(SdoComCon_p, pSdoComCon, kEplSdoComTransferRxAborted); + goto Exit; + } + + // get segment size + // check size of buffer + uiBuffer = AmiGetWordFromLe(&pAsySdoCom_p->m_le_wSegmentSize); + // subtract size of vaiable header from datasize + uiBuffer -= 4; + // copy data + EPL_MEMCPY(pSdoComCon->m_pData, &pAsySdoCom_p->m_le_abCommandData[4], uiBuffer); + + // correct counter an pointer + pSdoComCon->m_pData += uiBuffer; + pSdoComCon->m_uiTransferredByte += uiBuffer; + pSdoComCon->m_uiTransSize -= uiBuffer; + + break; + } + + // segment + case 0x20: + { + // get segment size + // check size of buffer + uiBuffer = AmiGetWordFromLe(&pAsySdoCom_p->m_le_wSegmentSize); + // check if data to copy fit to buffer + if(uiBuffer >= pSdoComCon->m_uiTransSize) + { // to much data + uiBuffer = (pSdoComCon->m_uiTransSize - 1); + } + // copy data + EPL_MEMCPY(pSdoComCon->m_pData, &pAsySdoCom_p->m_le_abCommandData[0], uiBuffer); + + // correct counter an pointer + pSdoComCon->m_pData += uiBuffer; + pSdoComCon->m_uiTransferredByte += uiBuffer; + pSdoComCon->m_uiTransSize -= uiBuffer; + break; + } + + // last segment + case 0x30: + { + // get segment size + // check size of buffer + uiBuffer = AmiGetWordFromLe(&pAsySdoCom_p->m_le_wSegmentSize); + // check if data to copy fit to buffer + if(uiBuffer > pSdoComCon->m_uiTransSize) + { // to much data + uiBuffer = (pSdoComCon->m_uiTransSize - 1); + } + // copy data + EPL_MEMCPY(pSdoComCon->m_pData, &pAsySdoCom_p->m_le_abCommandData[0], uiBuffer); + + // correct counter an pointer + pSdoComCon->m_pData += uiBuffer; + pSdoComCon->m_uiTransferredByte += uiBuffer; + pSdoComCon->m_uiTransSize = 0; + + break; + } + }// end of switch(bBuffer & 0x30) + + break; + } + + case kEplSdoServiceNIL: + default: + // invalid service requested + // $$$ d.k. What should we do? + break; + }// end of switch(pSdoComCon->m_SdoServiceType) + } + } + +Exit: + return Ret; +} +#endif + +//--------------------------------------------------------------------------- +// +// Function: EplSdoComClientSendAbort +// +// Description: function send a abort message +// +// +// +// Parameters: pSdoComCon_p = pointer to control structure of connection +// dwAbortCode_p = Sdo abort code +// +// Returns: tEplKernel = errorcode +// +// +// State: +// +//--------------------------------------------------------------------------- +#if(((EPL_MODULE_INTEGRATION) & (EPL_MODULE_SDOC)) != 0) +static tEplKernel EplSdoComClientSendAbort(tEplSdoComCon* pSdoComCon_p, + DWORD dwAbortCode_p) +{ +tEplKernel Ret; +BYTE abFrame[EPL_MAX_SDO_FRAME_SIZE]; +tEplFrame* pFrame; +tEplAsySdoCom* pCommandFrame; +unsigned int uiSizeOfFrame; + + Ret = kEplSuccessful; + + pFrame = (tEplFrame*)&abFrame[0]; + + EPL_MEMSET(&abFrame[0], 0x00, sizeof(abFrame)); + + // build generic part of frame + // get pointer to command layerpart of frame + pCommandFrame = &pFrame->m_Data.m_Asnd.m_Payload.m_SdoSequenceFrame.m_le_abSdoSeqPayload; + AmiSetByteToLe( &pCommandFrame->m_le_bCommandId, pSdoComCon_p->m_SdoServiceType); + AmiSetByteToLe( &pCommandFrame->m_le_bTransactionId, pSdoComCon_p->m_bTransactionId); + + uiSizeOfFrame = 8; + + // set response and abort flag + pCommandFrame->m_le_bFlags |= 0x40; + + // copy abortcode to frame + AmiSetDwordToLe(&pCommandFrame->m_le_abCommandData[0], dwAbortCode_p); + + // set size of segment + AmiSetWordToLe(&pCommandFrame->m_le_wSegmentSize, sizeof(DWORD)); + + // update counter + pSdoComCon_p->m_uiTransferredByte = sizeof(DWORD); + pSdoComCon_p->m_uiTransSize = 0; + + // calc framesize + uiSizeOfFrame += sizeof(DWORD); + + // save abort code + pSdoComCon_p->m_dwLastAbortCode = dwAbortCode_p; + + // call send function of lower layer + switch(pSdoComCon_p->m_SdoProtType) + { + case kEplSdoTypeAsnd: + case kEplSdoTypeUdp: + { + Ret = EplSdoAsySeqSendData(pSdoComCon_p->m_SdoSeqConHdl, + uiSizeOfFrame, + pFrame); + break; + } + + default: + { + Ret = kEplSdoComUnsupportedProt; + } + } // end of switch(pSdoComCon_p->m_SdoProtType) + + + return Ret; +} +#endif + +//--------------------------------------------------------------------------- +// +// Function: EplSdoComTransferFinished +// +// Description: calls callback function of application if available +// and clears entry in control structure +// +// Parameters: pSdoComCon_p = pointer to control structure of connection +// SdoComConState_p = state of SDO transfer +// +// Returns: tEplKernel = errorcode +// +// +// State: +// +//--------------------------------------------------------------------------- +static tEplKernel EplSdoComTransferFinished(tEplSdoComConHdl SdoComCon_p, + tEplSdoComCon* pSdoComCon_p, + tEplSdoComConState SdoComConState_p) +{ +tEplKernel Ret; + + Ret = kEplSuccessful; + + if(pSdoComCon_p->m_pfnTransferFinished != NULL) + { + tEplSdoFinishedCb pfnTransferFinished; + tEplSdoComFinished SdoComFinished; + + SdoComFinished.m_pUserArg = pSdoComCon_p->m_pUserArg; + SdoComFinished.m_uiNodeId = pSdoComCon_p->m_uiNodeId; + SdoComFinished.m_uiTargetIndex = pSdoComCon_p->m_uiTargetIndex; + SdoComFinished.m_uiTargetSubIndex = pSdoComCon_p->m_uiTargetSubIndex; + SdoComFinished.m_uiTransferredByte = pSdoComCon_p->m_uiTransferredByte; + SdoComFinished.m_dwAbortCode = pSdoComCon_p->m_dwLastAbortCode; + SdoComFinished.m_SdoComConHdl = SdoComCon_p; + SdoComFinished.m_SdoComConState = SdoComConState_p; + if (pSdoComCon_p->m_SdoServiceType == kEplSdoServiceWriteByIndex) + { + SdoComFinished.m_SdoAccessType = kEplSdoAccessTypeWrite; + } + else + { + SdoComFinished.m_SdoAccessType = kEplSdoAccessTypeRead; + } + + // reset transfer state so this handle is not busy anymore + pSdoComCon_p->m_uiTransferredByte = 0; + pSdoComCon_p->m_uiTransSize = 0; + + pfnTransferFinished = pSdoComCon_p->m_pfnTransferFinished; + // delete function pointer to inform application only once for each transfer + pSdoComCon_p->m_pfnTransferFinished = NULL; + + // call application's callback function + pfnTransferFinished(&SdoComFinished); + + } + + return Ret; +} + +// EOF + |