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