dcf5371cde
It's u16 in kernelspace, not WORD. Cc: Daniel Krueger <daniel.krueger@systec-electronic.com> Cc: Ronald Sieber <Ronald.Sieber@systec-electronic.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2523 lines
69 KiB
C
2523 lines
69 KiB
C
/****************************************************************************
|
|
|
|
(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
|