| /**************************************************************************** |
| |
| (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 |
| |