3784 lines
142 KiB
C
3784 lines
142 KiB
C
|
/****************************************************************************
|
||
|
|
||
|
(c) SYSTEC electronic GmbH, D-07973 Greiz, August-Bebel-Str. 29
|
||
|
www.systec-electronic.com
|
||
|
|
||
|
Project: openPOWERLINK
|
||
|
|
||
|
Description: source file for kernel DLL 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: EplDllk.c,v $
|
||
|
|
||
|
$Author: D.Krueger $
|
||
|
|
||
|
$Revision: 1.21 $ $Date: 2008/11/13 17:13:09 $
|
||
|
|
||
|
$State: Exp $
|
||
|
|
||
|
Build Environment:
|
||
|
GCC V3.4
|
||
|
|
||
|
-------------------------------------------------------------------------
|
||
|
|
||
|
Revision History:
|
||
|
|
||
|
2006/06/12 d.k.: start of the implementation, version 1.00
|
||
|
|
||
|
****************************************************************************/
|
||
|
|
||
|
#include "kernel/EplDllk.h"
|
||
|
#include "kernel/EplDllkCal.h"
|
||
|
#include "kernel/EplEventk.h"
|
||
|
#include "kernel/EplNmtk.h"
|
||
|
#include "edrv.h"
|
||
|
#include "Benchmark.h"
|
||
|
|
||
|
#if (((EPL_MODULE_INTEGRATION) & (EPL_MODULE_PDOK)) != 0)
|
||
|
#include "kernel/EplPdok.h"
|
||
|
#endif
|
||
|
|
||
|
#if (((EPL_MODULE_INTEGRATION) & (EPL_MODULE_VETH)) != 0)
|
||
|
#include "kernel/VirtualEthernet.h"
|
||
|
#endif
|
||
|
|
||
|
//#if EPL_TIMER_USE_HIGHRES != FALSE
|
||
|
#include "kernel/EplTimerHighResk.h"
|
||
|
//#endif
|
||
|
|
||
|
#if(((EPL_MODULE_INTEGRATION) & (EPL_MODULE_DLLK)) != 0)
|
||
|
|
||
|
#if(((EPL_MODULE_INTEGRATION) & (EPL_MODULE_NMTK)) == 0)
|
||
|
#error "EPL module DLLK needs EPL module NMTK!"
|
||
|
#endif
|
||
|
|
||
|
#if (EPL_DLL_PRES_READY_AFTER_SOA != FALSE) && (EPL_DLL_PRES_READY_AFTER_SOC != FALSE)
|
||
|
#error "EPL module DLLK: select only one of EPL_DLL_PRES_READY_AFTER_SOA and EPL_DLL_PRES_READY_AFTER_SOC."
|
||
|
#endif
|
||
|
|
||
|
#if ((EPL_DLL_PRES_READY_AFTER_SOA != FALSE) || (EPL_DLL_PRES_READY_AFTER_SOC != FALSE)) \
|
||
|
&& (((EPL_MODULE_INTEGRATION) & (EPL_MODULE_NMT_MN)) == 0)
|
||
|
#error "EPL module DLLK: currently, EPL_DLL_PRES_READY_AFTER_* is not supported if EPL_MODULE_NMT_MN is enabled."
|
||
|
#endif
|
||
|
|
||
|
#if (EDRV_FAST_TXFRAMES == FALSE) && \
|
||
|
((EPL_DLL_PRES_READY_AFTER_SOA != FALSE) || (EPL_DLL_PRES_READY_AFTER_SOC != FALSE))
|
||
|
#error "EPL module DLLK: EPL_DLL_PRES_READY_AFTER_* is enabled, but not EDRV_FAST_TXFRAMES."
|
||
|
#endif
|
||
|
|
||
|
/***************************************************************************/
|
||
|
/* */
|
||
|
/* */
|
||
|
/* G L O B A L D E F I N I T I O N S */
|
||
|
/* */
|
||
|
/* */
|
||
|
/***************************************************************************/
|
||
|
|
||
|
//---------------------------------------------------------------------------
|
||
|
// const defines
|
||
|
//---------------------------------------------------------------------------
|
||
|
|
||
|
// TracePoint support for realtime-debugging
|
||
|
#ifdef _DBG_TRACE_POINTS_
|
||
|
void PUBLIC TgtDbgSignalTracePoint (BYTE bTracePointNumber_p);
|
||
|
void PUBLIC TgtDbgPostTraceValue (DWORD dwTraceValue_p);
|
||
|
#define TGT_DBG_SIGNAL_TRACE_POINT(p) TgtDbgSignalTracePoint(p)
|
||
|
#define TGT_DBG_POST_TRACE_VALUE(v) TgtDbgPostTraceValue(v)
|
||
|
#else
|
||
|
#define TGT_DBG_SIGNAL_TRACE_POINT(p)
|
||
|
#define TGT_DBG_POST_TRACE_VALUE(v)
|
||
|
#endif
|
||
|
#define EPL_DLLK_DBG_POST_TRACE_VALUE(Event_p, uiNodeId_p, wErrorCode_p) \
|
||
|
TGT_DBG_POST_TRACE_VALUE((kEplEventSinkDllk << 28) | (Event_p << 24) \
|
||
|
| (uiNodeId_p << 16) | wErrorCode_p)
|
||
|
|
||
|
|
||
|
/***************************************************************************/
|
||
|
/* */
|
||
|
/* */
|
||
|
/* C L A S S EplDllk */
|
||
|
/* */
|
||
|
/* */
|
||
|
/***************************************************************************/
|
||
|
//
|
||
|
// Description:
|
||
|
//
|
||
|
//
|
||
|
/***************************************************************************/
|
||
|
|
||
|
|
||
|
//=========================================================================//
|
||
|
// //
|
||
|
// P R I V A T E D E F I N I T I O N S //
|
||
|
// //
|
||
|
//=========================================================================//
|
||
|
|
||
|
//---------------------------------------------------------------------------
|
||
|
// const defines
|
||
|
//---------------------------------------------------------------------------
|
||
|
|
||
|
// defines for indexes of tEplDllInstance.m_pTxFrameInfo
|
||
|
#define EPL_DLLK_TXFRAME_IDENTRES 0 // IdentResponse on CN / MN
|
||
|
#define EPL_DLLK_TXFRAME_STATUSRES 1 // StatusResponse on CN / MN
|
||
|
#define EPL_DLLK_TXFRAME_NMTREQ 2 // NMT Request from FIFO on CN / MN
|
||
|
#define EPL_DLLK_TXFRAME_NONEPL 3 // non-EPL frame from FIFO on CN / MN
|
||
|
#define EPL_DLLK_TXFRAME_PRES 4 // PRes on CN / MN
|
||
|
#define EPL_DLLK_TXFRAME_SOC 5 // SoC on MN
|
||
|
#define EPL_DLLK_TXFRAME_SOA 6 // SoA on MN
|
||
|
#define EPL_DLLK_TXFRAME_PREQ 7 // PReq on MN
|
||
|
#if(((EPL_MODULE_INTEGRATION) & (EPL_MODULE_NMT_MN)) != 0)
|
||
|
#define EPL_DLLK_TXFRAME_COUNT (7 + EPL_D_NMT_MaxCNNumber_U8 + 2) // on MN: 7 + MaxPReq of regular CNs + 1 Diag + 1 Router
|
||
|
#else
|
||
|
#define EPL_DLLK_TXFRAME_COUNT 5 // on CN: 5
|
||
|
#endif
|
||
|
|
||
|
#define EPL_DLLK_BUFLEN_EMPTY 0 // buffer is empty
|
||
|
#define EPL_DLLK_BUFLEN_FILLING 1 // just the buffer is being filled
|
||
|
#define EPL_DLLK_BUFLEN_MIN 60 // minimum ethernet frame length
|
||
|
|
||
|
//---------------------------------------------------------------------------
|
||
|
// local types
|
||
|
//---------------------------------------------------------------------------
|
||
|
|
||
|
typedef enum
|
||
|
{
|
||
|
kEplDllGsInit = 0x00, // MN/CN: initialisation (< PreOp2)
|
||
|
kEplDllCsWaitPreq = 0x01, // CN: wait for PReq frame
|
||
|
kEplDllCsWaitSoc = 0x02, // CN: wait for SoC frame
|
||
|
kEplDllCsWaitSoa = 0x03, // CN: wait for SoA frame
|
||
|
kEplDllMsNonCyclic = 0x04, // MN: reduced EPL cycle (PreOp1)
|
||
|
kEplDllMsWaitSocTrig = 0x05, // MN: wait for SoC trigger (cycle timer)
|
||
|
kEplDllMsWaitPreqTrig = 0x06, // MN: wait for (first) PReq trigger (WaitSoCPReq_U32)
|
||
|
kEplDllMsWaitPres = 0x07, // MN: wait for PRes frame from CN
|
||
|
kEplDllMsWaitSoaTrig = 0x08, // MN: wait for SoA trigger (PRes transmitted)
|
||
|
kEplDllMsWaitAsndTrig = 0x09, // MN: wait for ASnd trigger (SoA transmitted)
|
||
|
kEplDllMsWaitAsnd = 0x0A, // MN: wait for ASnd frame if SoA contained invitation
|
||
|
|
||
|
} tEplDllState;
|
||
|
|
||
|
typedef struct
|
||
|
{
|
||
|
BYTE m_be_abSrcMac[6];
|
||
|
tEdrvTxBuffer* m_pTxBuffer; // Buffers for Tx-Frames
|
||
|
unsigned int m_uiMaxTxFrames;
|
||
|
BYTE m_bFlag1; // Flag 1 with EN, EC for PRes, StatusRes
|
||
|
BYTE m_bMnFlag1; // Flag 1 with EA, ER from PReq, SoA of MN
|
||
|
BYTE m_bFlag2; // Flag 2 with PR and RS for PRes, StatusRes, IdentRes
|
||
|
tEplDllConfigParam m_DllConfigParam;
|
||
|
tEplDllIdentParam m_DllIdentParam;
|
||
|
tEplDllState m_DllState;
|
||
|
tEplDllkCbAsync m_pfnCbAsync;
|
||
|
tEplDllAsndFilter m_aAsndFilter[EPL_DLL_MAX_ASND_SERVICE_ID];
|
||
|
|
||
|
#if (((EPL_MODULE_INTEGRATION) & (EPL_MODULE_NMT_MN)) != 0)
|
||
|
tEplDllkNodeInfo* m_pFirstNodeInfo;
|
||
|
tEplDllkNodeInfo* m_pCurNodeInfo;
|
||
|
tEplDllkNodeInfo m_aNodeInfo[EPL_NMT_MAX_NODE_ID];
|
||
|
tEplDllReqServiceId m_LastReqServiceId;
|
||
|
unsigned int m_uiLastTargetNodeId;
|
||
|
#endif
|
||
|
|
||
|
#if EPL_TIMER_USE_HIGHRES != FALSE
|
||
|
tEplTimerHdl m_TimerHdlCycle; // used for EPL cycle monitoring on CN and generation on MN
|
||
|
#if (((EPL_MODULE_INTEGRATION) & (EPL_MODULE_NMT_MN)) != 0)
|
||
|
tEplTimerHdl m_TimerHdlResponse; // used for CN response monitoring
|
||
|
#endif //(((EPL_MODULE_INTEGRATION) & (EPL_MODULE_NMT_MN)) != 0)
|
||
|
#endif
|
||
|
|
||
|
unsigned int m_uiCycleCount; // cycle counter (needed for multiplexed cycle support)
|
||
|
unsigned long long m_ullFrameTimeout; // frame timeout (cycle length + loss of frame tolerance)
|
||
|
|
||
|
} tEplDllkInstance;
|
||
|
|
||
|
|
||
|
//---------------------------------------------------------------------------
|
||
|
// local vars
|
||
|
//---------------------------------------------------------------------------
|
||
|
|
||
|
// if no dynamic memory allocation shall be used
|
||
|
// define structures statically
|
||
|
static tEplDllkInstance EplDllkInstance_g;
|
||
|
|
||
|
static tEdrvTxBuffer aEplDllkTxBuffer_l[EPL_DLLK_TXFRAME_COUNT];
|
||
|
|
||
|
|
||
|
//---------------------------------------------------------------------------
|
||
|
// local function prototypes
|
||
|
//---------------------------------------------------------------------------
|
||
|
|
||
|
// change DLL state on event
|
||
|
static tEplKernel EplDllkChangeState(tEplNmtEvent NmtEvent_p, tEplNmtState NmtState_p);
|
||
|
|
||
|
// called from EdrvInterruptHandler()
|
||
|
static void EplDllkCbFrameReceived(tEdrvRxBuffer * pRxBuffer_p);
|
||
|
|
||
|
// called from EdrvInterruptHandler()
|
||
|
static void EplDllkCbFrameTransmitted(tEdrvTxBuffer * pTxBuffer_p);
|
||
|
|
||
|
// check frame and set missing information
|
||
|
static tEplKernel EplDllkCheckFrame(tEplFrame * pFrame_p, unsigned int uiFrameSize_p);
|
||
|
|
||
|
// called by high resolution timer module to monitor EPL cycle as CN
|
||
|
#if EPL_TIMER_USE_HIGHRES != FALSE
|
||
|
static tEplKernel PUBLIC EplDllkCbCnTimer(tEplTimerEventArg* pEventArg_p);
|
||
|
#endif
|
||
|
|
||
|
#if (((EPL_MODULE_INTEGRATION) & (EPL_MODULE_NMT_MN)) != 0)
|
||
|
// MN: returns internal node info structure
|
||
|
static tEplDllkNodeInfo* EplDllkGetNodeInfo(unsigned int uiNodeId_p);
|
||
|
|
||
|
// transmit SoA
|
||
|
static tEplKernel EplDllkMnSendSoa(tEplNmtState NmtState_p,
|
||
|
tEplDllState* pDllStateProposed_p,
|
||
|
BOOL fEnableInvitation_p);
|
||
|
|
||
|
static tEplKernel EplDllkMnSendSoc(void);
|
||
|
|
||
|
static tEplKernel EplDllkMnSendPreq(tEplNmtState NmtState_p,
|
||
|
tEplDllState* pDllStateProposed_p);
|
||
|
|
||
|
static tEplKernel EplDllkAsyncFrameNotReceived(tEplDllReqServiceId ReqServiceId_p, unsigned int uiNodeId_p);
|
||
|
|
||
|
static tEplKernel PUBLIC EplDllkCbMnTimerCycle(tEplTimerEventArg* pEventArg_p);
|
||
|
|
||
|
static tEplKernel PUBLIC EplDllkCbMnTimerResponse(tEplTimerEventArg* pEventArg_p);
|
||
|
|
||
|
#endif
|
||
|
|
||
|
//=========================================================================//
|
||
|
// //
|
||
|
// P U B L I C F U N C T I O N S //
|
||
|
// //
|
||
|
//=========================================================================//
|
||
|
|
||
|
//---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: EplDllkAddInstance()
|
||
|
//
|
||
|
// Description: add and initialize new instance of EPL stack
|
||
|
//
|
||
|
// Parameters: pInitParam_p = initialisation parameters like MAC address
|
||
|
//
|
||
|
// Returns: tEplKernel = error code
|
||
|
//
|
||
|
//
|
||
|
// State:
|
||
|
//
|
||
|
//---------------------------------------------------------------------------
|
||
|
|
||
|
tEplKernel EplDllkAddInstance(tEplDllkInitParam * pInitParam_p)
|
||
|
{
|
||
|
tEplKernel Ret = kEplSuccessful;
|
||
|
unsigned int uiIndex;
|
||
|
tEdrvInitParam EdrvInitParam;
|
||
|
|
||
|
// reset instance structure
|
||
|
EPL_MEMSET(&EplDllkInstance_g, 0, sizeof (EplDllkInstance_g));
|
||
|
|
||
|
#if EPL_TIMER_USE_HIGHRES != FALSE
|
||
|
Ret = EplTimerHighReskInit();
|
||
|
if (Ret != kEplSuccessful)
|
||
|
{ // error occured while initializing high resolution timer module
|
||
|
goto Exit;
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
// if dynamic memory allocation available
|
||
|
// allocate instance structure
|
||
|
// allocate TPDO and RPDO table with default size
|
||
|
|
||
|
// initialize and link pointers in instance structure to frame tables
|
||
|
EplDllkInstance_g.m_pTxBuffer = aEplDllkTxBuffer_l;
|
||
|
EplDllkInstance_g.m_uiMaxTxFrames = sizeof (aEplDllkTxBuffer_l) / sizeof (tEdrvTxBuffer);
|
||
|
|
||
|
// initialize state
|
||
|
EplDllkInstance_g.m_DllState = kEplDllGsInit;
|
||
|
|
||
|
#if (((EPL_MODULE_INTEGRATION) & (EPL_MODULE_NMT_MN)) != 0)
|
||
|
// set up node info structure
|
||
|
for (uiIndex = 0; uiIndex < tabentries (EplDllkInstance_g.m_aNodeInfo); uiIndex++)
|
||
|
{
|
||
|
EplDllkInstance_g.m_aNodeInfo[uiIndex].m_uiNodeId = uiIndex + 1;
|
||
|
EplDllkInstance_g.m_aNodeInfo[uiIndex].m_wPresPayloadLimit = 0xFFFF;
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
// initialize Edrv
|
||
|
EPL_MEMCPY(EdrvInitParam.m_abMyMacAddr, pInitParam_p->m_be_abSrcMac, 6);
|
||
|
EdrvInitParam.m_pfnRxHandler = EplDllkCbFrameReceived;
|
||
|
EdrvInitParam.m_pfnTxHandler = EplDllkCbFrameTransmitted;
|
||
|
Ret = EdrvInit(&EdrvInitParam);
|
||
|
if (Ret != kEplSuccessful)
|
||
|
{ // error occured while initializing ethernet driver
|
||
|
goto Exit;
|
||
|
}
|
||
|
|
||
|
// copy local MAC address from Ethernet driver back to local instance structure
|
||
|
// because Ethernet driver may have read it from controller EEPROM
|
||
|
EPL_MEMCPY(EplDllkInstance_g.m_be_abSrcMac, EdrvInitParam.m_abMyMacAddr, 6);
|
||
|
EPL_MEMCPY(pInitParam_p->m_be_abSrcMac, EdrvInitParam.m_abMyMacAddr, 6);
|
||
|
|
||
|
// initialize TxBuffer array
|
||
|
for (uiIndex = 0; uiIndex < EplDllkInstance_g.m_uiMaxTxFrames; uiIndex++)
|
||
|
{
|
||
|
EplDllkInstance_g.m_pTxBuffer[uiIndex].m_pbBuffer = NULL;
|
||
|
}
|
||
|
|
||
|
#if (((EPL_MODULE_INTEGRATION) & (EPL_MODULE_VETH)) != 0)
|
||
|
Ret = VEthAddInstance(pInitParam_p);
|
||
|
#endif
|
||
|
|
||
|
Exit:
|
||
|
return Ret;
|
||
|
}
|
||
|
|
||
|
//---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: EplDllkDelInstance()
|
||
|
//
|
||
|
// Description: deletes an instance of EPL stack
|
||
|
//
|
||
|
// Parameters: (none)
|
||
|
//
|
||
|
// Returns: tEplKernel = error code
|
||
|
//
|
||
|
//
|
||
|
// State:
|
||
|
//
|
||
|
//---------------------------------------------------------------------------
|
||
|
|
||
|
tEplKernel EplDllkDelInstance(void)
|
||
|
{
|
||
|
tEplKernel Ret = kEplSuccessful;
|
||
|
|
||
|
// reset state
|
||
|
EplDllkInstance_g.m_DllState = kEplDllGsInit;
|
||
|
|
||
|
#if EPL_TIMER_USE_HIGHRES != FALSE
|
||
|
Ret = EplTimerHighReskDelInstance();
|
||
|
#endif
|
||
|
|
||
|
#if (((EPL_MODULE_INTEGRATION) & (EPL_MODULE_VETH)) != 0)
|
||
|
Ret = VEthDelInstance();
|
||
|
#endif
|
||
|
|
||
|
Ret = EdrvShutdown();
|
||
|
return Ret;
|
||
|
}
|
||
|
|
||
|
//---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: EplDllkCreateTxFrame
|
||
|
//
|
||
|
// Description: creates the buffer for a Tx frame and registers it to the
|
||
|
// ethernet driver
|
||
|
//
|
||
|
// Parameters: puiHandle_p = OUT: handle to frame buffer
|
||
|
// ppFrame_p = OUT: pointer to pointer of EPL frame
|
||
|
// puiFrameSize_p = IN/OUT: pointer to size of frame
|
||
|
// returned size is always equal or larger than
|
||
|
// requested size, if that is not possible
|
||
|
// an error will be returned
|
||
|
// MsgType_p = EPL message type
|
||
|
// ServiceId_p = Service ID in case of ASnd frame, otherwise
|
||
|
// kEplDllAsndNotDefined
|
||
|
//
|
||
|
// Returns: tEplKernel = error code
|
||
|
//
|
||
|
//
|
||
|
// State:
|
||
|
//
|
||
|
//---------------------------------------------------------------------------
|
||
|
|
||
|
tEplKernel EplDllkCreateTxFrame (unsigned int * puiHandle_p,
|
||
|
tEplFrame ** ppFrame_p,
|
||
|
unsigned int * puiFrameSize_p,
|
||
|
tEplMsgType MsgType_p,
|
||
|
tEplDllAsndServiceId ServiceId_p)
|
||
|
{
|
||
|
tEplKernel Ret = kEplSuccessful;
|
||
|
tEplFrame *pTxFrame;
|
||
|
unsigned int uiHandle = EplDllkInstance_g.m_uiMaxTxFrames;
|
||
|
tEdrvTxBuffer *pTxBuffer = NULL;
|
||
|
|
||
|
if (MsgType_p == kEplMsgTypeAsnd)
|
||
|
{
|
||
|
// search for fixed Tx buffers
|
||
|
if (ServiceId_p == kEplDllAsndIdentResponse)
|
||
|
{
|
||
|
uiHandle = EPL_DLLK_TXFRAME_IDENTRES;
|
||
|
}
|
||
|
else if (ServiceId_p == kEplDllAsndStatusResponse)
|
||
|
{
|
||
|
uiHandle = EPL_DLLK_TXFRAME_STATUSRES;
|
||
|
}
|
||
|
else if ((ServiceId_p == kEplDllAsndNmtRequest) || (ServiceId_p == kEplDllAsndNmtCommand))
|
||
|
{
|
||
|
uiHandle = EPL_DLLK_TXFRAME_NMTREQ;
|
||
|
}
|
||
|
|
||
|
if (uiHandle >= EplDllkInstance_g.m_uiMaxTxFrames)
|
||
|
{ // look for free entry
|
||
|
uiHandle = EPL_DLLK_TXFRAME_PREQ;
|
||
|
pTxBuffer = &EplDllkInstance_g.m_pTxBuffer[uiHandle];
|
||
|
for (; uiHandle < EplDllkInstance_g.m_uiMaxTxFrames; uiHandle++, pTxBuffer++)
|
||
|
{
|
||
|
if (pTxBuffer->m_pbBuffer == NULL)
|
||
|
{ // free entry found
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else if (MsgType_p == kEplMsgTypeNonEpl)
|
||
|
{
|
||
|
uiHandle = EPL_DLLK_TXFRAME_NONEPL;
|
||
|
}
|
||
|
else if (MsgType_p == kEplMsgTypePres)
|
||
|
{
|
||
|
uiHandle = EPL_DLLK_TXFRAME_PRES;
|
||
|
}
|
||
|
else if (MsgType_p == kEplMsgTypeSoc)
|
||
|
{
|
||
|
uiHandle = EPL_DLLK_TXFRAME_SOC;
|
||
|
}
|
||
|
else if (MsgType_p == kEplMsgTypeSoa)
|
||
|
{
|
||
|
uiHandle = EPL_DLLK_TXFRAME_SOA;
|
||
|
}
|
||
|
else
|
||
|
{ // look for free entry
|
||
|
uiHandle = EPL_DLLK_TXFRAME_PREQ;
|
||
|
pTxBuffer = &EplDllkInstance_g.m_pTxBuffer[uiHandle];
|
||
|
for (; uiHandle < EplDllkInstance_g.m_uiMaxTxFrames; uiHandle++, pTxBuffer++)
|
||
|
{
|
||
|
if (pTxBuffer->m_pbBuffer == NULL)
|
||
|
{ // free entry found
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
if (pTxBuffer->m_pbBuffer != NULL)
|
||
|
{
|
||
|
Ret = kEplEdrvNoFreeBufEntry;
|
||
|
goto Exit;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// test if requested entry is free
|
||
|
pTxBuffer = &EplDllkInstance_g.m_pTxBuffer[uiHandle];
|
||
|
if (pTxBuffer->m_pbBuffer != NULL)
|
||
|
{ // entry is not free
|
||
|
Ret = kEplEdrvNoFreeBufEntry;
|
||
|
goto Exit;
|
||
|
}
|
||
|
|
||
|
// setup Tx buffer
|
||
|
pTxBuffer->m_EplMsgType = MsgType_p;
|
||
|
pTxBuffer->m_uiMaxBufferLen = *puiFrameSize_p;
|
||
|
|
||
|
Ret = EdrvAllocTxMsgBuffer(pTxBuffer);
|
||
|
if (Ret != kEplSuccessful)
|
||
|
{ // error occured while registering Tx frame
|
||
|
goto Exit;
|
||
|
}
|
||
|
|
||
|
// because buffer size may be larger than requested
|
||
|
// memorize real length of frame
|
||
|
pTxBuffer->m_uiTxMsgLen = *puiFrameSize_p;
|
||
|
|
||
|
// fill whole frame with 0
|
||
|
EPL_MEMSET(pTxBuffer->m_pbBuffer, 0, pTxBuffer->m_uiMaxBufferLen);
|
||
|
|
||
|
pTxFrame = (tEplFrame *) pTxBuffer->m_pbBuffer;
|
||
|
|
||
|
if (MsgType_p != kEplMsgTypeNonEpl)
|
||
|
{ // fill out Frame only if it is an EPL frame
|
||
|
// ethertype
|
||
|
AmiSetWordToBe(&pTxFrame->m_be_wEtherType, EPL_C_DLL_ETHERTYPE_EPL);
|
||
|
// source node ID
|
||
|
AmiSetByteToLe(&pTxFrame->m_le_bSrcNodeId, (BYTE) EplDllkInstance_g.m_DllConfigParam.m_uiNodeId);
|
||
|
// source MAC address
|
||
|
EPL_MEMCPY(&pTxFrame->m_be_abSrcMac[0], &EplDllkInstance_g.m_be_abSrcMac[0], 6);
|
||
|
switch (MsgType_p)
|
||
|
{
|
||
|
case kEplMsgTypeAsnd:
|
||
|
// destination MAC address
|
||
|
AmiSetQword48ToBe(&pTxFrame->m_be_abDstMac[0], EPL_C_DLL_MULTICAST_ASND);
|
||
|
// destination node ID
|
||
|
switch (ServiceId_p)
|
||
|
{
|
||
|
case kEplDllAsndIdentResponse:
|
||
|
case kEplDllAsndStatusResponse:
|
||
|
{ // IdentResponses and StatusResponses are Broadcast
|
||
|
AmiSetByteToLe(&pTxFrame->m_le_bDstNodeId, (BYTE) EPL_C_ADR_BROADCAST);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
default:
|
||
|
break;
|
||
|
}
|
||
|
// ASnd Service ID
|
||
|
AmiSetByteToLe(&pTxFrame->m_Data.m_Asnd.m_le_bServiceId, ServiceId_p);
|
||
|
break;
|
||
|
|
||
|
case kEplMsgTypeSoc:
|
||
|
// destination MAC address
|
||
|
AmiSetQword48ToBe(&pTxFrame->m_be_abDstMac[0], EPL_C_DLL_MULTICAST_SOC);
|
||
|
// destination node ID
|
||
|
AmiSetByteToLe(&pTxFrame->m_le_bDstNodeId, (BYTE) EPL_C_ADR_BROADCAST);
|
||
|
// reset Flags
|
||
|
//AmiSetByteToLe(&pTxFrame->m_Data.m_Soc.m_le_bFlag1, (BYTE) 0);
|
||
|
//AmiSetByteToLe(&pTxFrame->m_Data.m_Soc.m_le_bFlag2, (BYTE) 0);
|
||
|
break;
|
||
|
|
||
|
case kEplMsgTypeSoa:
|
||
|
// destination MAC address
|
||
|
AmiSetQword48ToBe(&pTxFrame->m_be_abDstMac[0], EPL_C_DLL_MULTICAST_SOA);
|
||
|
// destination node ID
|
||
|
AmiSetByteToLe(&pTxFrame->m_le_bDstNodeId, (BYTE) EPL_C_ADR_BROADCAST);
|
||
|
// reset Flags
|
||
|
//AmiSetByteToLe(&pTxFrame->m_Data.m_Soa.m_le_bFlag1, (BYTE) 0);
|
||
|
//AmiSetByteToLe(&pTxFrame->m_Data.m_Soa.m_le_bFlag2, (BYTE) 0);
|
||
|
// EPL profile version
|
||
|
AmiSetByteToLe(&pTxFrame->m_Data.m_Soa.m_le_bEplVersion, (BYTE) EPL_SPEC_VERSION);
|
||
|
break;
|
||
|
|
||
|
case kEplMsgTypePres:
|
||
|
// destination MAC address
|
||
|
AmiSetQword48ToBe(&pTxFrame->m_be_abDstMac[0], EPL_C_DLL_MULTICAST_PRES);
|
||
|
// destination node ID
|
||
|
AmiSetByteToLe(&pTxFrame->m_le_bDstNodeId, (BYTE) EPL_C_ADR_BROADCAST);
|
||
|
// reset Flags
|
||
|
//AmiSetByteToLe(&pTxFrame->m_Data.m_Pres.m_le_bFlag1, (BYTE) 0);
|
||
|
//AmiSetByteToLe(&pTxFrame->m_Data.m_Pres.m_le_bFlag2, (BYTE) 0);
|
||
|
// PDO size
|
||
|
//AmiSetWordToLe(&pTxFrame->m_Data.m_Pres.m_le_wSize, 0);
|
||
|
break;
|
||
|
|
||
|
case kEplMsgTypePreq:
|
||
|
// reset Flags
|
||
|
//AmiSetByteToLe(&pTxFrame->m_Data.m_Preq.m_le_bFlag1, (BYTE) 0);
|
||
|
//AmiSetByteToLe(&pTxFrame->m_Data.m_Preq.m_le_bFlag2, (BYTE) 0);
|
||
|
// PDO size
|
||
|
//AmiSetWordToLe(&pTxFrame->m_Data.m_Preq.m_le_wSize, 0);
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
break;
|
||
|
}
|
||
|
// EPL message type
|
||
|
AmiSetByteToLe(&pTxFrame->m_le_bMessageType, (BYTE) MsgType_p);
|
||
|
}
|
||
|
|
||
|
*ppFrame_p = pTxFrame;
|
||
|
*puiFrameSize_p = pTxBuffer->m_uiMaxBufferLen;
|
||
|
*puiHandle_p = uiHandle;
|
||
|
|
||
|
Exit:
|
||
|
return Ret;
|
||
|
}
|
||
|
|
||
|
//---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: EplDllkDeleteTxFrame
|
||
|
//
|
||
|
// Description: deletes the buffer for a Tx frame and frees it in the
|
||
|
// ethernet driver
|
||
|
//
|
||
|
// Parameters: uiHandle_p = IN: handle to frame buffer
|
||
|
//
|
||
|
// Returns: tEplKernel = error code
|
||
|
//
|
||
|
//
|
||
|
// State:
|
||
|
//
|
||
|
//---------------------------------------------------------------------------
|
||
|
|
||
|
tEplKernel EplDllkDeleteTxFrame (unsigned int uiHandle_p)
|
||
|
{
|
||
|
tEplKernel Ret = kEplSuccessful;
|
||
|
tEdrvTxBuffer *pTxBuffer = NULL;
|
||
|
|
||
|
if (uiHandle_p >= EplDllkInstance_g.m_uiMaxTxFrames)
|
||
|
{ // handle is not valid
|
||
|
Ret = kEplDllIllegalHdl;
|
||
|
goto Exit;
|
||
|
}
|
||
|
|
||
|
pTxBuffer = &EplDllkInstance_g.m_pTxBuffer[uiHandle_p];
|
||
|
|
||
|
// mark buffer as free so that frame will not be send in future anymore
|
||
|
// $$$ d.k. What's up with running transmissions?
|
||
|
pTxBuffer->m_uiTxMsgLen = EPL_DLLK_BUFLEN_EMPTY;
|
||
|
pTxBuffer->m_pbBuffer = NULL;
|
||
|
|
||
|
// delete Tx buffer
|
||
|
Ret = EdrvReleaseTxMsgBuffer(pTxBuffer);
|
||
|
if (Ret != kEplSuccessful)
|
||
|
{ // error occured while releasing Tx frame
|
||
|
goto Exit;
|
||
|
}
|
||
|
|
||
|
Exit:
|
||
|
return Ret;
|
||
|
}
|
||
|
|
||
|
//---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: EplDllkProcess
|
||
|
//
|
||
|
// Description: process the passed event
|
||
|
//
|
||
|
// Parameters: pEvent_p = event to be processed
|
||
|
//
|
||
|
// Returns: tEplKernel = error code
|
||
|
//
|
||
|
//
|
||
|
// State:
|
||
|
//
|
||
|
//---------------------------------------------------------------------------
|
||
|
|
||
|
tEplKernel EplDllkProcess(tEplEvent * pEvent_p)
|
||
|
{
|
||
|
tEplKernel Ret = kEplSuccessful;
|
||
|
tEplFrame *pTxFrame;
|
||
|
tEdrvTxBuffer *pTxBuffer;
|
||
|
unsigned int uiHandle;
|
||
|
unsigned int uiFrameSize;
|
||
|
BYTE abMulticastMac[6];
|
||
|
tEplDllAsyncReqPriority AsyncReqPriority;
|
||
|
unsigned int uiFrameCount;
|
||
|
tEplNmtState NmtState;
|
||
|
#if (((EPL_MODULE_INTEGRATION) & (EPL_MODULE_PDOK)) != 0)
|
||
|
tEplFrameInfo FrameInfo;
|
||
|
#endif
|
||
|
|
||
|
|
||
|
switch (pEvent_p->m_EventType)
|
||
|
{
|
||
|
case kEplEventTypeDllkCreate:
|
||
|
{
|
||
|
// $$$ reset ethernet driver
|
||
|
|
||
|
NmtState = *((tEplNmtState*)pEvent_p->m_pArg);
|
||
|
|
||
|
// initialize flags for PRes and StatusRes
|
||
|
EplDllkInstance_g.m_bFlag1 = EPL_FRAME_FLAG1_EC;
|
||
|
EplDllkInstance_g.m_bMnFlag1 = 0;
|
||
|
EplDllkInstance_g.m_bFlag2 = 0;
|
||
|
|
||
|
#if (((EPL_MODULE_INTEGRATION) & (EPL_MODULE_NMT_MN)) != 0)
|
||
|
// initialize linked node list
|
||
|
EplDllkInstance_g.m_pFirstNodeInfo = NULL;
|
||
|
#endif
|
||
|
|
||
|
// register TxFrames in Edrv
|
||
|
|
||
|
// IdentResponse
|
||
|
uiFrameSize = EPL_C_DLL_MINSIZE_IDENTRES;
|
||
|
Ret = EplDllkCreateTxFrame(&uiHandle, &pTxFrame, &uiFrameSize, kEplMsgTypeAsnd, kEplDllAsndIdentResponse);
|
||
|
if (Ret != kEplSuccessful)
|
||
|
{ // error occured while registering Tx frame
|
||
|
goto Exit;
|
||
|
}
|
||
|
|
||
|
// EPL profile version
|
||
|
AmiSetByteToLe(&pTxFrame->m_Data.m_Asnd.m_Payload.m_IdentResponse.m_le_bEplProfileVersion,
|
||
|
(BYTE) EPL_SPEC_VERSION);
|
||
|
// FeatureFlags
|
||
|
AmiSetDwordToLe(&pTxFrame->m_Data.m_Asnd.m_Payload.m_IdentResponse.m_le_dwFeatureFlags,
|
||
|
EplDllkInstance_g.m_DllConfigParam.m_dwFeatureFlags);
|
||
|
// MTU
|
||
|
AmiSetWordToLe(&pTxFrame->m_Data.m_Asnd.m_Payload.m_IdentResponse.m_le_wMtu,
|
||
|
(WORD) EplDllkInstance_g.m_DllConfigParam.m_uiAsyncMtu);
|
||
|
// PollInSize
|
||
|
AmiSetWordToLe(&pTxFrame->m_Data.m_Asnd.m_Payload.m_IdentResponse.m_le_wPollInSize,
|
||
|
(WORD)EplDllkInstance_g.m_DllConfigParam.m_uiPreqActPayloadLimit);
|
||
|
// PollOutSize
|
||
|
AmiSetWordToLe(&pTxFrame->m_Data.m_Asnd.m_Payload.m_IdentResponse.m_le_wPollOutSize,
|
||
|
(WORD)EplDllkInstance_g.m_DllConfigParam.m_uiPresActPayloadLimit);
|
||
|
// ResponseTime / PresMaxLatency
|
||
|
AmiSetDwordToLe(&pTxFrame->m_Data.m_Asnd.m_Payload.m_IdentResponse.m_le_dwResponseTime,
|
||
|
EplDllkInstance_g.m_DllConfigParam.m_dwPresMaxLatency);
|
||
|
// DeviceType
|
||
|
AmiSetDwordToLe(&pTxFrame->m_Data.m_Asnd.m_Payload.m_IdentResponse.m_le_dwDeviceType,
|
||
|
EplDllkInstance_g.m_DllIdentParam.m_dwDeviceType);
|
||
|
// VendorId
|
||
|
AmiSetDwordToLe(&pTxFrame->m_Data.m_Asnd.m_Payload.m_IdentResponse.m_le_dwVendorId,
|
||
|
EplDllkInstance_g.m_DllIdentParam.m_dwVendorId);
|
||
|
// ProductCode
|
||
|
AmiSetDwordToLe(&pTxFrame->m_Data.m_Asnd.m_Payload.m_IdentResponse.m_le_dwProductCode,
|
||
|
EplDllkInstance_g.m_DllIdentParam.m_dwProductCode);
|
||
|
// RevisionNumber
|
||
|
AmiSetDwordToLe(&pTxFrame->m_Data.m_Asnd.m_Payload.m_IdentResponse.m_le_dwRevisionNumber,
|
||
|
EplDllkInstance_g.m_DllIdentParam.m_dwRevisionNumber);
|
||
|
// SerialNumber
|
||
|
AmiSetDwordToLe(&pTxFrame->m_Data.m_Asnd.m_Payload.m_IdentResponse.m_le_dwSerialNumber,
|
||
|
EplDllkInstance_g.m_DllIdentParam.m_dwSerialNumber);
|
||
|
// VendorSpecificExt1
|
||
|
AmiSetQword64ToLe(&pTxFrame->m_Data.m_Asnd.m_Payload.m_IdentResponse.m_le_qwVendorSpecificExt1,
|
||
|
EplDllkInstance_g.m_DllIdentParam.m_qwVendorSpecificExt1);
|
||
|
// VerifyConfigurationDate
|
||
|
AmiSetDwordToLe(&pTxFrame->m_Data.m_Asnd.m_Payload.m_IdentResponse.m_le_dwVerifyConfigurationDate,
|
||
|
EplDllkInstance_g.m_DllIdentParam.m_dwVerifyConfigurationDate);
|
||
|
// VerifyConfigurationTime
|
||
|
AmiSetDwordToLe(&pTxFrame->m_Data.m_Asnd.m_Payload.m_IdentResponse.m_le_dwVerifyConfigurationTime,
|
||
|
EplDllkInstance_g.m_DllIdentParam.m_dwVerifyConfigurationTime);
|
||
|
// ApplicationSwDate
|
||
|
AmiSetDwordToLe(&pTxFrame->m_Data.m_Asnd.m_Payload.m_IdentResponse.m_le_dwApplicationSwDate,
|
||
|
EplDllkInstance_g.m_DllIdentParam.m_dwApplicationSwDate);
|
||
|
// ApplicationSwTime
|
||
|
AmiSetDwordToLe(&pTxFrame->m_Data.m_Asnd.m_Payload.m_IdentResponse.m_le_dwApplicationSwTime,
|
||
|
EplDllkInstance_g.m_DllIdentParam.m_dwApplicationSwTime);
|
||
|
// IPAddress
|
||
|
AmiSetDwordToLe(&pTxFrame->m_Data.m_Asnd.m_Payload.m_IdentResponse.m_le_dwIpAddress,
|
||
|
EplDllkInstance_g.m_DllIdentParam.m_dwIpAddress);
|
||
|
// SubnetMask
|
||
|
AmiSetDwordToLe(&pTxFrame->m_Data.m_Asnd.m_Payload.m_IdentResponse.m_le_dwSubnetMask,
|
||
|
EplDllkInstance_g.m_DllIdentParam.m_dwSubnetMask);
|
||
|
// DefaultGateway
|
||
|
AmiSetDwordToLe(&pTxFrame->m_Data.m_Asnd.m_Payload.m_IdentResponse.m_le_dwDefaultGateway,
|
||
|
EplDllkInstance_g.m_DllIdentParam.m_dwDefaultGateway);
|
||
|
// HostName
|
||
|
EPL_MEMCPY(&pTxFrame->m_Data.m_Asnd.m_Payload.m_IdentResponse.m_le_sHostname[0],
|
||
|
&EplDllkInstance_g.m_DllIdentParam.m_sHostname[0],
|
||
|
sizeof (EplDllkInstance_g.m_DllIdentParam.m_sHostname));
|
||
|
// VendorSpecificExt2
|
||
|
EPL_MEMCPY(&pTxFrame->m_Data.m_Asnd.m_Payload.m_IdentResponse.m_le_abVendorSpecificExt2[0],
|
||
|
&EplDllkInstance_g.m_DllIdentParam.m_abVendorSpecificExt2[0],
|
||
|
sizeof (EplDllkInstance_g.m_DllIdentParam.m_abVendorSpecificExt2));
|
||
|
|
||
|
// StatusResponse
|
||
|
uiFrameSize = EPL_C_DLL_MINSIZE_STATUSRES;
|
||
|
Ret = EplDllkCreateTxFrame(&uiHandle, &pTxFrame, &uiFrameSize, kEplMsgTypeAsnd, kEplDllAsndStatusResponse);
|
||
|
if (Ret != kEplSuccessful)
|
||
|
{ // error occured while registering Tx frame
|
||
|
goto Exit;
|
||
|
}
|
||
|
|
||
|
// PRes $$$ maybe move this to PDO module
|
||
|
if ((EplDllkInstance_g.m_DllConfigParam.m_fAsyncOnly == FALSE)
|
||
|
&& (EplDllkInstance_g.m_DllConfigParam.m_uiPresActPayloadLimit >= 36))
|
||
|
{ // it is not configured as async-only CN,
|
||
|
// so take part in isochronous phase and register PRes frame
|
||
|
uiFrameSize = EplDllkInstance_g.m_DllConfigParam.m_uiPresActPayloadLimit + 24;
|
||
|
Ret = EplDllkCreateTxFrame(&uiHandle, &pTxFrame, &uiFrameSize, kEplMsgTypePres, kEplDllAsndNotDefined);
|
||
|
if (Ret != kEplSuccessful)
|
||
|
{ // error occured while registering Tx frame
|
||
|
goto Exit;
|
||
|
}
|
||
|
|
||
|
#if (((EPL_MODULE_INTEGRATION) & (EPL_MODULE_PDOK)) != 0)
|
||
|
// initially encode TPDO -> inform PDO module
|
||
|
FrameInfo.m_pFrame = pTxFrame;
|
||
|
FrameInfo.m_uiFrameSize = uiFrameSize;
|
||
|
Ret = EplPdokCbPdoTransmitted(&FrameInfo);
|
||
|
#endif
|
||
|
// reset cycle counter
|
||
|
EplDllkInstance_g.m_uiCycleCount = 0;
|
||
|
}
|
||
|
else
|
||
|
{ // it is an async-only CN
|
||
|
// fool EplDllkChangeState() to think that PRes was not expected
|
||
|
EplDllkInstance_g.m_uiCycleCount = 1;
|
||
|
}
|
||
|
|
||
|
// NMT request
|
||
|
uiFrameSize = EPL_C_IP_MAX_MTU;
|
||
|
Ret = EplDllkCreateTxFrame(&uiHandle, &pTxFrame, &uiFrameSize, kEplMsgTypeAsnd, kEplDllAsndNmtRequest);
|
||
|
if (Ret != kEplSuccessful)
|
||
|
{ // error occured while registering Tx frame
|
||
|
goto Exit;
|
||
|
}
|
||
|
// mark Tx buffer as empty
|
||
|
EplDllkInstance_g.m_pTxBuffer[uiHandle].m_uiTxMsgLen = EPL_DLLK_BUFLEN_EMPTY;
|
||
|
|
||
|
// non-EPL frame
|
||
|
uiFrameSize = EPL_C_IP_MAX_MTU;
|
||
|
Ret = EplDllkCreateTxFrame(&uiHandle, &pTxFrame, &uiFrameSize, kEplMsgTypeNonEpl, kEplDllAsndNotDefined);
|
||
|
if (Ret != kEplSuccessful)
|
||
|
{ // error occured while registering Tx frame
|
||
|
goto Exit;
|
||
|
}
|
||
|
// mark Tx buffer as empty
|
||
|
EplDllkInstance_g.m_pTxBuffer[uiHandle].m_uiTxMsgLen = EPL_DLLK_BUFLEN_EMPTY;
|
||
|
|
||
|
// register multicast MACs in ethernet driver
|
||
|
AmiSetQword48ToBe(&abMulticastMac[0], EPL_C_DLL_MULTICAST_SOC);
|
||
|
Ret = EdrvDefineRxMacAddrEntry(abMulticastMac);
|
||
|
AmiSetQword48ToBe(&abMulticastMac[0], EPL_C_DLL_MULTICAST_SOA);
|
||
|
Ret = EdrvDefineRxMacAddrEntry(abMulticastMac);
|
||
|
AmiSetQword48ToBe(&abMulticastMac[0], EPL_C_DLL_MULTICAST_PRES);
|
||
|
Ret = EdrvDefineRxMacAddrEntry(abMulticastMac);
|
||
|
AmiSetQword48ToBe(&abMulticastMac[0], EPL_C_DLL_MULTICAST_ASND);
|
||
|
Ret = EdrvDefineRxMacAddrEntry(abMulticastMac);
|
||
|
|
||
|
#if (((EPL_MODULE_INTEGRATION) & (EPL_MODULE_NMT_MN)) != 0)
|
||
|
if (NmtState >= kEplNmtMsNotActive)
|
||
|
{ // local node is MN
|
||
|
unsigned int uiIndex;
|
||
|
|
||
|
// SoC
|
||
|
uiFrameSize = EPL_C_DLL_MINSIZE_SOC;
|
||
|
Ret = EplDllkCreateTxFrame(&uiHandle, &pTxFrame, &uiFrameSize, kEplMsgTypeSoc, kEplDllAsndNotDefined);
|
||
|
if (Ret != kEplSuccessful)
|
||
|
{ // error occured while registering Tx frame
|
||
|
goto Exit;
|
||
|
}
|
||
|
|
||
|
// SoA
|
||
|
uiFrameSize = EPL_C_DLL_MINSIZE_SOA;
|
||
|
Ret = EplDllkCreateTxFrame(&uiHandle, &pTxFrame, &uiFrameSize, kEplMsgTypeSoa, kEplDllAsndNotDefined);
|
||
|
if (Ret != kEplSuccessful)
|
||
|
{ // error occured while registering Tx frame
|
||
|
goto Exit;
|
||
|
}
|
||
|
|
||
|
for (uiIndex = 0; uiIndex < tabentries (EplDllkInstance_g.m_aNodeInfo); uiIndex++)
|
||
|
{
|
||
|
// EplDllkInstance_g.m_aNodeInfo[uiIndex].m_uiNodeId = uiIndex + 1;
|
||
|
EplDllkInstance_g.m_aNodeInfo[uiIndex].m_wPresPayloadLimit = (WORD) EplDllkInstance_g.m_DllConfigParam.m_uiIsochrRxMaxPayload;
|
||
|
}
|
||
|
|
||
|
// calculate cycle length
|
||
|
EplDllkInstance_g.m_ullFrameTimeout = 1000LL
|
||
|
* ((unsigned long long) EplDllkInstance_g.m_DllConfigParam.m_dwCycleLen);
|
||
|
}
|
||
|
#endif //(((EPL_MODULE_INTEGRATION) & (EPL_MODULE_NMT_MN)) != 0)
|
||
|
|
||
|
Ret = EplDllkCalAsyncClearBuffer();
|
||
|
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
case kEplEventTypeDllkDestroy:
|
||
|
{
|
||
|
// destroy all data structures
|
||
|
|
||
|
NmtState = *((tEplNmtState*)pEvent_p->m_pArg);
|
||
|
|
||
|
// delete Tx frames
|
||
|
Ret = EplDllkDeleteTxFrame(EPL_DLLK_TXFRAME_IDENTRES);
|
||
|
if (Ret != kEplSuccessful)
|
||
|
{ // error occured while deregistering Tx frame
|
||
|
goto Exit;
|
||
|
}
|
||
|
|
||
|
Ret = EplDllkDeleteTxFrame(EPL_DLLK_TXFRAME_STATUSRES);
|
||
|
if (Ret != kEplSuccessful)
|
||
|
{ // error occured while deregistering Tx frame
|
||
|
goto Exit;
|
||
|
}
|
||
|
|
||
|
Ret = EplDllkDeleteTxFrame(EPL_DLLK_TXFRAME_PRES);
|
||
|
if (Ret != kEplSuccessful)
|
||
|
{ // error occured while deregistering Tx frame
|
||
|
goto Exit;
|
||
|
}
|
||
|
|
||
|
Ret = EplDllkDeleteTxFrame(EPL_DLLK_TXFRAME_NMTREQ);
|
||
|
if (Ret != kEplSuccessful)
|
||
|
{ // error occured while deregistering Tx frame
|
||
|
goto Exit;
|
||
|
}
|
||
|
|
||
|
Ret = EplDllkDeleteTxFrame(EPL_DLLK_TXFRAME_NONEPL);
|
||
|
if (Ret != kEplSuccessful)
|
||
|
{ // error occured while deregistering Tx frame
|
||
|
goto Exit;
|
||
|
}
|
||
|
|
||
|
#if (((EPL_MODULE_INTEGRATION) & (EPL_MODULE_NMT_MN)) != 0)
|
||
|
if (NmtState >= kEplNmtMsNotActive)
|
||
|
{ // local node was MN
|
||
|
unsigned int uiIndex;
|
||
|
|
||
|
Ret = EplDllkDeleteTxFrame(EPL_DLLK_TXFRAME_SOC);
|
||
|
if (Ret != kEplSuccessful)
|
||
|
{ // error occured while deregistering Tx frame
|
||
|
goto Exit;
|
||
|
}
|
||
|
|
||
|
Ret = EplDllkDeleteTxFrame(EPL_DLLK_TXFRAME_SOA);
|
||
|
if (Ret != kEplSuccessful)
|
||
|
{ // error occured while deregistering Tx frame
|
||
|
goto Exit;
|
||
|
}
|
||
|
|
||
|
for (uiIndex = 0; uiIndex < tabentries (EplDllkInstance_g.m_aNodeInfo); uiIndex++)
|
||
|
{
|
||
|
if (EplDllkInstance_g.m_aNodeInfo[uiIndex].m_pPreqTxBuffer != NULL)
|
||
|
{
|
||
|
uiHandle = EplDllkInstance_g.m_aNodeInfo[uiIndex].m_pPreqTxBuffer - EplDllkInstance_g.m_pTxBuffer;
|
||
|
EplDllkInstance_g.m_aNodeInfo[uiIndex].m_pPreqTxBuffer = NULL;
|
||
|
Ret = EplDllkDeleteTxFrame(uiHandle);
|
||
|
if (Ret != kEplSuccessful)
|
||
|
{ // error occured while deregistering Tx frame
|
||
|
goto Exit;
|
||
|
}
|
||
|
|
||
|
}
|
||
|
EplDllkInstance_g.m_aNodeInfo[uiIndex].m_wPresPayloadLimit = 0xFFFF;
|
||
|
}
|
||
|
}
|
||
|
#endif //(((EPL_MODULE_INTEGRATION) & (EPL_MODULE_NMT_MN)) != 0)
|
||
|
|
||
|
// deregister multicast MACs in ethernet driver
|
||
|
AmiSetQword48ToBe(&abMulticastMac[0], EPL_C_DLL_MULTICAST_SOC);
|
||
|
Ret = EdrvUndefineRxMacAddrEntry(abMulticastMac);
|
||
|
AmiSetQword48ToBe(&abMulticastMac[0], EPL_C_DLL_MULTICAST_SOA);
|
||
|
Ret = EdrvUndefineRxMacAddrEntry(abMulticastMac);
|
||
|
AmiSetQword48ToBe(&abMulticastMac[0], EPL_C_DLL_MULTICAST_PRES);
|
||
|
Ret = EdrvUndefineRxMacAddrEntry(abMulticastMac);
|
||
|
AmiSetQword48ToBe(&abMulticastMac[0], EPL_C_DLL_MULTICAST_ASND);
|
||
|
Ret = EdrvUndefineRxMacAddrEntry(abMulticastMac);
|
||
|
|
||
|
// delete timer
|
||
|
#if EPL_TIMER_USE_HIGHRES != FALSE
|
||
|
Ret = EplTimerHighReskDeleteTimer(&EplDllkInstance_g.m_TimerHdlCycle);
|
||
|
#endif
|
||
|
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
case kEplEventTypeDllkFillTx:
|
||
|
{
|
||
|
// fill TxBuffer of specified priority with new frame if empty
|
||
|
|
||
|
pTxFrame = NULL;
|
||
|
AsyncReqPriority = *((tEplDllAsyncReqPriority *) pEvent_p->m_pArg);
|
||
|
switch (AsyncReqPriority)
|
||
|
{
|
||
|
case kEplDllAsyncReqPrioNmt: // NMT request priority
|
||
|
{
|
||
|
pTxBuffer = &EplDllkInstance_g.m_pTxBuffer[EPL_DLLK_TXFRAME_NMTREQ];
|
||
|
if (pTxBuffer->m_pbBuffer != NULL)
|
||
|
{ // NmtRequest does exist
|
||
|
// check if frame is empty and not being filled
|
||
|
if (pTxBuffer->m_uiTxMsgLen == EPL_DLLK_BUFLEN_EMPTY)
|
||
|
{
|
||
|
// mark Tx buffer as filling is in process
|
||
|
pTxBuffer->m_uiTxMsgLen = EPL_DLLK_BUFLEN_FILLING;
|
||
|
// set max buffer size as input parameter
|
||
|
uiFrameSize = pTxBuffer->m_uiMaxBufferLen;
|
||
|
// copy frame from shared loop buffer to Tx buffer
|
||
|
Ret = EplDllkCalAsyncGetTxFrame(
|
||
|
pTxBuffer->m_pbBuffer, &uiFrameSize, AsyncReqPriority);
|
||
|
if (Ret == kEplSuccessful)
|
||
|
{
|
||
|
pTxFrame = (tEplFrame *) pTxBuffer->m_pbBuffer;
|
||
|
Ret = EplDllkCheckFrame(pTxFrame, uiFrameSize);
|
||
|
|
||
|
// set buffer valid
|
||
|
pTxBuffer->m_uiTxMsgLen = uiFrameSize;
|
||
|
}
|
||
|
else if (Ret == kEplDllAsyncTxBufferEmpty)
|
||
|
{ // empty Tx buffer is not a real problem
|
||
|
// so just ignore it
|
||
|
Ret = kEplSuccessful;
|
||
|
// mark Tx buffer as empty
|
||
|
pTxBuffer->m_uiTxMsgLen = EPL_DLLK_BUFLEN_EMPTY;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
default: // generic priority
|
||
|
{
|
||
|
pTxBuffer = &EplDllkInstance_g.m_pTxBuffer[EPL_DLLK_TXFRAME_NONEPL];
|
||
|
if (pTxBuffer->m_pbBuffer != NULL)
|
||
|
{ // non-EPL frame does exist
|
||
|
// check if frame is empty and not being filled
|
||
|
if (pTxBuffer->m_uiTxMsgLen == EPL_DLLK_BUFLEN_EMPTY)
|
||
|
{
|
||
|
// mark Tx buffer as filling is in process
|
||
|
pTxBuffer->m_uiTxMsgLen = EPL_DLLK_BUFLEN_FILLING;
|
||
|
// set max buffer size as input parameter
|
||
|
uiFrameSize = pTxBuffer->m_uiMaxBufferLen;
|
||
|
// copy frame from shared loop buffer to Tx buffer
|
||
|
Ret = EplDllkCalAsyncGetTxFrame(
|
||
|
pTxBuffer->m_pbBuffer, &uiFrameSize, AsyncReqPriority);
|
||
|
if (Ret == kEplSuccessful)
|
||
|
{
|
||
|
pTxFrame = (tEplFrame *) pTxBuffer->m_pbBuffer;
|
||
|
Ret = EplDllkCheckFrame(pTxFrame, uiFrameSize);
|
||
|
|
||
|
// set buffer valid
|
||
|
pTxBuffer->m_uiTxMsgLen = uiFrameSize;
|
||
|
}
|
||
|
else if (Ret == kEplDllAsyncTxBufferEmpty)
|
||
|
{ // empty Tx buffer is not a real problem
|
||
|
// so just ignore it
|
||
|
Ret = kEplSuccessful;
|
||
|
// mark Tx buffer as empty
|
||
|
pTxBuffer->m_uiTxMsgLen = EPL_DLLK_BUFLEN_EMPTY;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
NmtState = EplNmtkGetNmtState();
|
||
|
|
||
|
if ((NmtState == kEplNmtCsBasicEthernet) || (NmtState == kEplNmtMsBasicEthernet))
|
||
|
{ // send frame immediately
|
||
|
if (pTxFrame != NULL)
|
||
|
{ // frame is present
|
||
|
// padding is done by Edrv or ethernet controller
|
||
|
Ret = EdrvSendTxMsg(pTxBuffer);
|
||
|
}
|
||
|
else
|
||
|
{ // no frame moved to TxBuffer
|
||
|
// check if TxBuffers contain unsent frames
|
||
|
if (EplDllkInstance_g.m_pTxBuffer[EPL_DLLK_TXFRAME_NMTREQ].m_uiTxMsgLen > EPL_DLLK_BUFLEN_EMPTY)
|
||
|
{ // NMT request Tx buffer contains a frame
|
||
|
Ret = EdrvSendTxMsg(
|
||
|
&EplDllkInstance_g.m_pTxBuffer[EPL_DLLK_TXFRAME_NMTREQ]);
|
||
|
}
|
||
|
else if (EplDllkInstance_g.m_pTxBuffer[EPL_DLLK_TXFRAME_NONEPL].m_uiTxMsgLen > EPL_DLLK_BUFLEN_EMPTY)
|
||
|
{ // non-EPL Tx buffer contains a frame
|
||
|
Ret = EdrvSendTxMsg(
|
||
|
&EplDllkInstance_g.m_pTxBuffer[EPL_DLLK_TXFRAME_NONEPL]);
|
||
|
}
|
||
|
if (Ret == kEplInvalidOperation)
|
||
|
{ // ignore error if caused by already active transmission
|
||
|
Ret = kEplSuccessful;
|
||
|
}
|
||
|
}
|
||
|
// reset PRes flag 2
|
||
|
EplDllkInstance_g.m_bFlag2 = 0;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// update Flag 2 (PR, RS)
|
||
|
Ret = EplDllkCalAsyncGetTxCount(&AsyncReqPriority, &uiFrameCount);
|
||
|
if (AsyncReqPriority == kEplDllAsyncReqPrioNmt)
|
||
|
{ // non-empty FIFO with hightest priority is for NMT requests
|
||
|
if (EplDllkInstance_g.m_pTxBuffer[EPL_DLLK_TXFRAME_NMTREQ].m_uiTxMsgLen > EPL_DLLK_BUFLEN_EMPTY)
|
||
|
{ // NMT request Tx buffer contains a frame
|
||
|
// add one more frame
|
||
|
uiFrameCount++;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{ // non-empty FIFO with highest priority is for generic frames
|
||
|
if (EplDllkInstance_g.m_pTxBuffer[EPL_DLLK_TXFRAME_NMTREQ].m_uiTxMsgLen > EPL_DLLK_BUFLEN_EMPTY)
|
||
|
{ // NMT request Tx buffer contains a frame
|
||
|
// use NMT request FIFO, because of higher priority
|
||
|
uiFrameCount = 1;
|
||
|
AsyncReqPriority = kEplDllAsyncReqPrioNmt;
|
||
|
}
|
||
|
else if (EplDllkInstance_g.m_pTxBuffer[EPL_DLLK_TXFRAME_NONEPL].m_uiTxMsgLen > EPL_DLLK_BUFLEN_EMPTY)
|
||
|
{ // non-EPL Tx buffer contains a frame
|
||
|
// use NMT request FIFO, because of higher priority
|
||
|
// add one more frame
|
||
|
uiFrameCount++;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (uiFrameCount > 7)
|
||
|
{ // limit frame request to send counter to 7
|
||
|
uiFrameCount = 7;
|
||
|
}
|
||
|
if (uiFrameCount > 0)
|
||
|
{
|
||
|
EplDllkInstance_g.m_bFlag2 =
|
||
|
(BYTE) (((AsyncReqPriority << EPL_FRAME_FLAG2_PR_SHIFT) & EPL_FRAME_FLAG2_PR)
|
||
|
| (uiFrameCount & EPL_FRAME_FLAG2_RS));
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
EplDllkInstance_g.m_bFlag2 = 0;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
#if (((EPL_MODULE_INTEGRATION) & (EPL_MODULE_NMT_MN)) != 0)
|
||
|
case kEplEventTypeDllkStartReducedCycle:
|
||
|
{
|
||
|
// start the reduced cycle by programming the cycle timer
|
||
|
// it is issued by NMT MN module, when PreOp1 is entered
|
||
|
|
||
|
// clear the asynchronous queues
|
||
|
Ret = EplDllkCalAsyncClearQueues();
|
||
|
|
||
|
// reset cycle counter (everytime a SoA is triggerd in PreOp1 the counter is incremented
|
||
|
// and when it reaches EPL_C_DLL_PREOP1_START_CYCLES the SoA may contain invitations)
|
||
|
EplDllkInstance_g.m_uiCycleCount = 0;
|
||
|
|
||
|
// remove any CN from isochronous phase
|
||
|
while (EplDllkInstance_g.m_pFirstNodeInfo != NULL)
|
||
|
{
|
||
|
EplDllkDeleteNode(EplDllkInstance_g.m_pFirstNodeInfo->m_uiNodeId);
|
||
|
}
|
||
|
|
||
|
// change state to NonCyclic,
|
||
|
// hence EplDllkChangeState() will not ignore the next call
|
||
|
EplDllkInstance_g.m_DllState = kEplDllMsNonCyclic;
|
||
|
|
||
|
#if EPL_TIMER_USE_HIGHRES != FALSE
|
||
|
if (EplDllkInstance_g.m_DllConfigParam.m_dwAsyncSlotTimeout != 0)
|
||
|
{
|
||
|
Ret = EplTimerHighReskModifyTimerNs(&EplDllkInstance_g.m_TimerHdlCycle,
|
||
|
EplDllkInstance_g.m_DllConfigParam.m_dwAsyncSlotTimeout,
|
||
|
EplDllkCbMnTimerCycle,
|
||
|
0L,
|
||
|
FALSE);
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
break;
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
#if EPL_DLL_PRES_READY_AFTER_SOA != FALSE
|
||
|
case kEplEventTypeDllkPresReady:
|
||
|
{
|
||
|
// post PRes to transmit FIFO
|
||
|
|
||
|
NmtState = EplNmtkGetNmtState();
|
||
|
|
||
|
if (NmtState != kEplNmtCsBasicEthernet)
|
||
|
{
|
||
|
// Does PRes exist?
|
||
|
if (EplDllkInstance_g.m_pTxBuffer[EPL_DLLK_TXFRAME_PRES].m_pbBuffer != NULL)
|
||
|
{ // PRes does exist
|
||
|
pTxFrame = (tEplFrame *) EplDllkInstance_g.m_pTxBuffer[EPL_DLLK_TXFRAME_PRES].m_pbBuffer;
|
||
|
// update frame (NMT state, RD, RS, PR, MS, EN flags)
|
||
|
if (NmtState < kEplNmtCsPreOperational2)
|
||
|
{ // NMT state is not PreOp2, ReadyToOp or Op
|
||
|
// fake NMT state PreOp2, because PRes will be sent only in PreOp2 or greater
|
||
|
NmtState = kEplNmtCsPreOperational2;
|
||
|
}
|
||
|
AmiSetByteToLe(&pTxFrame->m_Data.m_Pres.m_le_bNmtStatus, (BYTE) NmtState);
|
||
|
AmiSetByteToLe(&pTxFrame->m_Data.m_Pres.m_le_bFlag2, EplDllkInstance_g.m_bFlag2);
|
||
|
if (NmtState != kEplNmtCsOperational)
|
||
|
{ // mark PDO as invalid in NMT state Op
|
||
|
// $$$ reset only RD flag; set other flags appropriately
|
||
|
AmiSetByteToLe(&pTxFrame->m_Data.m_Pres.m_le_bFlag1, 0);
|
||
|
}
|
||
|
// $$$ make function that updates Pres, StatusRes
|
||
|
// mark PRes frame as ready for transmission
|
||
|
Ret = EdrvTxMsgReady(&EplDllkInstance_g.m_pTxBuffer[EPL_DLLK_TXFRAME_PRES]);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
break;
|
||
|
}
|
||
|
#endif
|
||
|
default:
|
||
|
{
|
||
|
ASSERTMSG(FALSE, "EplDllkProcess(): unhandled event type!\n");
|
||
|
}
|
||
|
}
|
||
|
|
||
|
Exit:
|
||
|
return Ret;
|
||
|
}
|
||
|
|
||
|
//---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: EplDllkConfig
|
||
|
//
|
||
|
// Description: configure parameters of DLL
|
||
|
//
|
||
|
// Parameters: pDllConfigParam_p = configuration parameters
|
||
|
//
|
||
|
// Returns: tEplKernel = error code
|
||
|
//
|
||
|
//
|
||
|
// State:
|
||
|
//
|
||
|
//---------------------------------------------------------------------------
|
||
|
|
||
|
tEplKernel EplDllkConfig(tEplDllConfigParam * pDllConfigParam_p)
|
||
|
{
|
||
|
tEplKernel Ret = kEplSuccessful;
|
||
|
|
||
|
// d.k. check of NMT state disabled, because CycleLen is programmed at run time by MN without reset of CN
|
||
|
/*tEplNmtState NmtState;
|
||
|
|
||
|
NmtState = EplNmtkGetNmtState();
|
||
|
|
||
|
if (NmtState > kEplNmtGsResetConfiguration)
|
||
|
{ // only allowed in state DLL_GS_INIT
|
||
|
Ret = kEplInvalidOperation;
|
||
|
goto Exit;
|
||
|
}
|
||
|
*/
|
||
|
EPL_MEMCPY (&EplDllkInstance_g.m_DllConfigParam, pDllConfigParam_p,
|
||
|
(pDllConfigParam_p->m_uiSizeOfStruct < sizeof (tEplDllConfigParam) ?
|
||
|
pDllConfigParam_p->m_uiSizeOfStruct : sizeof (tEplDllConfigParam)));
|
||
|
|
||
|
if ((EplDllkInstance_g.m_DllConfigParam.m_dwCycleLen != 0)
|
||
|
&& (EplDllkInstance_g.m_DllConfigParam.m_dwLossOfFrameTolerance != 0))
|
||
|
{ // monitor EPL cycle, calculate frame timeout
|
||
|
EplDllkInstance_g.m_ullFrameTimeout = (1000LL
|
||
|
* ((unsigned long long) EplDllkInstance_g.m_DllConfigParam.m_dwCycleLen))
|
||
|
+ ((unsigned long long) EplDllkInstance_g.m_DllConfigParam.m_dwLossOfFrameTolerance);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
EplDllkInstance_g.m_ullFrameTimeout = 0LL;
|
||
|
}
|
||
|
|
||
|
if (EplDllkInstance_g.m_DllConfigParam.m_fAsyncOnly != FALSE)
|
||
|
{ // it is configured as async-only CN
|
||
|
// disable multiplexed cycle, that m_uiCycleCount will not be incremented spuriously on SoC
|
||
|
EplDllkInstance_g.m_DllConfigParam.m_uiMultiplCycleCnt = 0;
|
||
|
}
|
||
|
|
||
|
//Exit:
|
||
|
return Ret;
|
||
|
}
|
||
|
|
||
|
//---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: EplDllkSetIdentity
|
||
|
//
|
||
|
// Description: configure identity of local node for IdentResponse
|
||
|
//
|
||
|
// Parameters: pDllIdentParam_p = identity
|
||
|
//
|
||
|
// Returns: tEplKernel = error code
|
||
|
//
|
||
|
//
|
||
|
// State:
|
||
|
//
|
||
|
//---------------------------------------------------------------------------
|
||
|
|
||
|
tEplKernel EplDllkSetIdentity(tEplDllIdentParam * pDllIdentParam_p)
|
||
|
{
|
||
|
tEplKernel Ret = kEplSuccessful;
|
||
|
|
||
|
EPL_MEMCPY (&EplDllkInstance_g.m_DllIdentParam, pDllIdentParam_p,
|
||
|
(pDllIdentParam_p->m_uiSizeOfStruct < sizeof (tEplDllIdentParam) ?
|
||
|
pDllIdentParam_p->m_uiSizeOfStruct : sizeof (tEplDllIdentParam)));
|
||
|
|
||
|
// $$$ if IdentResponse frame exists update it
|
||
|
|
||
|
return Ret;
|
||
|
}
|
||
|
|
||
|
|
||
|
//---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: EplDllkRegAsyncHandler
|
||
|
//
|
||
|
// Description: registers handler for non-EPL frames
|
||
|
//
|
||
|
// Parameters: pfnDllkCbAsync_p = pointer to callback function
|
||
|
//
|
||
|
// Returns: tEplKernel = error code
|
||
|
//
|
||
|
//
|
||
|
// State:
|
||
|
//
|
||
|
//---------------------------------------------------------------------------
|
||
|
|
||
|
tEplKernel EplDllkRegAsyncHandler(tEplDllkCbAsync pfnDllkCbAsync_p)
|
||
|
{
|
||
|
tEplKernel Ret = kEplSuccessful;
|
||
|
|
||
|
if (EplDllkInstance_g.m_pfnCbAsync == NULL)
|
||
|
{ // no handler registered yet
|
||
|
EplDllkInstance_g.m_pfnCbAsync = pfnDllkCbAsync_p;
|
||
|
}
|
||
|
else
|
||
|
{ // handler already registered
|
||
|
Ret = kEplDllCbAsyncRegistered;
|
||
|
}
|
||
|
|
||
|
return Ret;
|
||
|
}
|
||
|
|
||
|
//---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: EplDllkDeregAsyncHandler
|
||
|
//
|
||
|
// Description: deregisters handler for non-EPL frames
|
||
|
//
|
||
|
// Parameters: pfnDllkCbAsync_p = pointer to callback function
|
||
|
//
|
||
|
// Returns: tEplKernel = error code
|
||
|
//
|
||
|
//
|
||
|
// State:
|
||
|
//
|
||
|
//---------------------------------------------------------------------------
|
||
|
|
||
|
tEplKernel EplDllkDeregAsyncHandler(tEplDllkCbAsync pfnDllkCbAsync_p)
|
||
|
{
|
||
|
tEplKernel Ret = kEplSuccessful;
|
||
|
|
||
|
if (EplDllkInstance_g.m_pfnCbAsync == pfnDllkCbAsync_p)
|
||
|
{ // same handler is registered
|
||
|
// deregister it
|
||
|
EplDllkInstance_g.m_pfnCbAsync = NULL;
|
||
|
}
|
||
|
else
|
||
|
{ // wrong handler or no handler registered
|
||
|
Ret = kEplDllCbAsyncRegistered;
|
||
|
}
|
||
|
|
||
|
return Ret;
|
||
|
}
|
||
|
|
||
|
//---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: EplDllkSetAsndServiceIdFilter()
|
||
|
//
|
||
|
// Description: sets the specified node ID filter for the specified
|
||
|
// AsndServiceId. It registers C_DLL_MULTICAST_ASND in ethernet
|
||
|
// driver if any AsndServiceId is open.
|
||
|
//
|
||
|
// Parameters: ServiceId_p = ASnd Service ID
|
||
|
// Filter_p = node ID filter
|
||
|
//
|
||
|
// Returns: tEplKernel = error code
|
||
|
//
|
||
|
//
|
||
|
// State:
|
||
|
//
|
||
|
//---------------------------------------------------------------------------
|
||
|
|
||
|
tEplKernel EplDllkSetAsndServiceIdFilter(tEplDllAsndServiceId ServiceId_p, tEplDllAsndFilter Filter_p)
|
||
|
{
|
||
|
tEplKernel Ret = kEplSuccessful;
|
||
|
|
||
|
if (ServiceId_p < tabentries (EplDllkInstance_g.m_aAsndFilter))
|
||
|
{
|
||
|
EplDllkInstance_g.m_aAsndFilter[ServiceId_p] = Filter_p;
|
||
|
}
|
||
|
|
||
|
return Ret;
|
||
|
}
|
||
|
|
||
|
|
||
|
#if (((EPL_MODULE_INTEGRATION) & (EPL_MODULE_NMT_MN)) != 0)
|
||
|
|
||
|
//---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: EplDllkSetFlag1OfNode()
|
||
|
//
|
||
|
// Description: sets Flag1 (for PReq and SoA) of the specified node ID.
|
||
|
//
|
||
|
// Parameters: uiNodeId_p = node ID
|
||
|
// bSoaFlag1_p = flag1
|
||
|
//
|
||
|
// Returns: tEplKernel = error code
|
||
|
//
|
||
|
//
|
||
|
// State:
|
||
|
//
|
||
|
//---------------------------------------------------------------------------
|
||
|
|
||
|
tEplKernel EplDllkSetFlag1OfNode(unsigned int uiNodeId_p, BYTE bSoaFlag1_p)
|
||
|
{
|
||
|
tEplKernel Ret = kEplSuccessful;
|
||
|
tEplDllkNodeInfo* pNodeInfo;
|
||
|
|
||
|
pNodeInfo = EplDllkGetNodeInfo(uiNodeId_p);
|
||
|
if (pNodeInfo == NULL)
|
||
|
{ // no node info structure available
|
||
|
Ret = kEplDllNoNodeInfo;
|
||
|
goto Exit;
|
||
|
}
|
||
|
|
||
|
// store flag1 in internal node info structure
|
||
|
pNodeInfo->m_bSoaFlag1 = bSoaFlag1_p;
|
||
|
|
||
|
Exit:
|
||
|
return Ret;
|
||
|
}
|
||
|
|
||
|
//---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: EplDllkGetFirstNodeInfo()
|
||
|
//
|
||
|
// Description: returns first info structure of first node in isochronous phase.
|
||
|
// It is only useful for ErrorHandlerk module.
|
||
|
//
|
||
|
// Parameters: ppNodeInfo_p = pointer to pointer of internal node info structure
|
||
|
//
|
||
|
// Returns: tEplKernel = error code
|
||
|
//
|
||
|
//
|
||
|
// State:
|
||
|
//
|
||
|
//---------------------------------------------------------------------------
|
||
|
|
||
|
tEplKernel EplDllkGetFirstNodeInfo(tEplDllkNodeInfo** ppNodeInfo_p)
|
||
|
{
|
||
|
tEplKernel Ret = kEplSuccessful;
|
||
|
|
||
|
*ppNodeInfo_p = EplDllkInstance_g.m_pFirstNodeInfo;
|
||
|
|
||
|
return Ret;
|
||
|
}
|
||
|
|
||
|
|
||
|
//---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: EplDllkAddNode()
|
||
|
//
|
||
|
// Description: adds the specified node to the isochronous phase.
|
||
|
//
|
||
|
// Parameters: pNodeInfo_p = pointer of node info structure
|
||
|
//
|
||
|
// Returns: tEplKernel = error code
|
||
|
//
|
||
|
//
|
||
|
// State:
|
||
|
//
|
||
|
//---------------------------------------------------------------------------
|
||
|
|
||
|
tEplKernel EplDllkAddNode(tEplDllNodeInfo * pNodeInfo_p)
|
||
|
{
|
||
|
tEplKernel Ret = kEplSuccessful;
|
||
|
tEplDllkNodeInfo* pIntNodeInfo;
|
||
|
tEplDllkNodeInfo** ppIntNodeInfo;
|
||
|
unsigned int uiHandle;
|
||
|
tEplFrame* pFrame;
|
||
|
unsigned int uiFrameSize;
|
||
|
|
||
|
pIntNodeInfo = EplDllkGetNodeInfo(pNodeInfo_p->m_uiNodeId);
|
||
|
if (pIntNodeInfo == NULL)
|
||
|
{ // no node info structure available
|
||
|
Ret = kEplDllNoNodeInfo;
|
||
|
goto Exit;
|
||
|
}
|
||
|
|
||
|
EPL_DLLK_DBG_POST_TRACE_VALUE(kEplEventTypeDllkAddNode,
|
||
|
pNodeInfo_p->m_uiNodeId,
|
||
|
0);
|
||
|
|
||
|
// copy node configuration
|
||
|
pIntNodeInfo->m_dwPresTimeout = pNodeInfo_p->m_dwPresTimeout;
|
||
|
pIntNodeInfo->m_wPresPayloadLimit = pNodeInfo_p->m_wPresPayloadLimit;
|
||
|
|
||
|
// $$$ d.k.: actually add node only if MN. On CN it is sufficient to update the node configuration
|
||
|
if (pNodeInfo_p->m_uiNodeId == EplDllkInstance_g.m_DllConfigParam.m_uiNodeId)
|
||
|
{ // we shall send PRes ourself
|
||
|
// insert our node at the end of the list
|
||
|
ppIntNodeInfo = &EplDllkInstance_g.m_pFirstNodeInfo;
|
||
|
while ((*ppIntNodeInfo != NULL) && ((*ppIntNodeInfo)->m_pNextNodeInfo != NULL))
|
||
|
{
|
||
|
ppIntNodeInfo = &(*ppIntNodeInfo)->m_pNextNodeInfo;
|
||
|
}
|
||
|
if (*ppIntNodeInfo != NULL)
|
||
|
{
|
||
|
if ((*ppIntNodeInfo)->m_uiNodeId == pNodeInfo_p->m_uiNodeId)
|
||
|
{ // node was already added to list
|
||
|
// $$$ d.k. maybe this should be an error
|
||
|
goto Exit;
|
||
|
}
|
||
|
else
|
||
|
{ // add our node at the end of the list
|
||
|
ppIntNodeInfo = &(*ppIntNodeInfo)->m_pNextNodeInfo;
|
||
|
}
|
||
|
}
|
||
|
// set "PReq"-TxBuffer to PRes-TxBuffer
|
||
|
pIntNodeInfo->m_pPreqTxBuffer = &EplDllkInstance_g.m_pTxBuffer[EPL_DLLK_TXFRAME_PRES];
|
||
|
}
|
||
|
else
|
||
|
{ // normal CN shall be added to isochronous phase
|
||
|
// insert node into list in ascending order
|
||
|
ppIntNodeInfo = &EplDllkInstance_g.m_pFirstNodeInfo;
|
||
|
while ((*ppIntNodeInfo != NULL)
|
||
|
&& ((*ppIntNodeInfo)->m_uiNodeId < pNodeInfo_p->m_uiNodeId)
|
||
|
&& ((*ppIntNodeInfo)->m_uiNodeId != EplDllkInstance_g.m_DllConfigParam.m_uiNodeId))
|
||
|
{
|
||
|
ppIntNodeInfo = &(*ppIntNodeInfo)->m_pNextNodeInfo;
|
||
|
}
|
||
|
if ((*ppIntNodeInfo != NULL) && ((*ppIntNodeInfo)->m_uiNodeId == pNodeInfo_p->m_uiNodeId))
|
||
|
{ // node was already added to list
|
||
|
// $$$ d.k. maybe this should be an error
|
||
|
goto Exit;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// initialize elements of internal node info structure
|
||
|
pIntNodeInfo->m_bSoaFlag1 = 0;
|
||
|
pIntNodeInfo->m_fSoftDelete = FALSE;
|
||
|
pIntNodeInfo->m_NmtState = kEplNmtCsNotActive;
|
||
|
if (pIntNodeInfo->m_pPreqTxBuffer == NULL)
|
||
|
{ // create TxBuffer entry
|
||
|
uiFrameSize = pNodeInfo_p->m_wPreqPayloadLimit + 24;
|
||
|
Ret = EplDllkCreateTxFrame(&uiHandle, &pFrame, &uiFrameSize, kEplMsgTypePreq, kEplDllAsndNotDefined);
|
||
|
if (Ret != kEplSuccessful)
|
||
|
{
|
||
|
goto Exit;
|
||
|
}
|
||
|
pIntNodeInfo->m_pPreqTxBuffer = &EplDllkInstance_g.m_pTxBuffer[uiHandle];
|
||
|
AmiSetByteToLe(&pFrame->m_le_bDstNodeId, (BYTE) pNodeInfo_p->m_uiNodeId);
|
||
|
|
||
|
// set up destination MAC address
|
||
|
EPL_MEMCPY(pFrame->m_be_abDstMac, pIntNodeInfo->m_be_abMacAddr, 6);
|
||
|
|
||
|
#if (((EPL_MODULE_INTEGRATION) & (EPL_MODULE_PDOK)) != 0)
|
||
|
{
|
||
|
tEplFrameInfo FrameInfo;
|
||
|
|
||
|
// initially encode TPDO -> inform PDO module
|
||
|
FrameInfo.m_pFrame = pFrame;
|
||
|
FrameInfo.m_uiFrameSize = uiFrameSize;
|
||
|
Ret = EplPdokCbPdoTransmitted(&FrameInfo);
|
||
|
}
|
||
|
#endif
|
||
|
}
|
||
|
pIntNodeInfo->m_ulDllErrorEvents = 0L;
|
||
|
// add node to list
|
||
|
pIntNodeInfo->m_pNextNodeInfo = *ppIntNodeInfo;
|
||
|
*ppIntNodeInfo = pIntNodeInfo;
|
||
|
|
||
|
Exit:
|
||
|
return Ret;
|
||
|
}
|
||
|
|
||
|
|
||
|
//---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: EplDllkDeleteNode()
|
||
|
//
|
||
|
// Description: removes the specified node from the isochronous phase.
|
||
|
//
|
||
|
// Parameters: uiNodeId_p = node ID
|
||
|
//
|
||
|
// Returns: tEplKernel = error code
|
||
|
//
|
||
|
//
|
||
|
// State:
|
||
|
//
|
||
|
//---------------------------------------------------------------------------
|
||
|
|
||
|
tEplKernel EplDllkDeleteNode(unsigned int uiNodeId_p)
|
||
|
{
|
||
|
tEplKernel Ret = kEplSuccessful;
|
||
|
tEplDllkNodeInfo* pIntNodeInfo;
|
||
|
tEplDllkNodeInfo** ppIntNodeInfo;
|
||
|
unsigned int uiHandle;
|
||
|
|
||
|
pIntNodeInfo = EplDllkGetNodeInfo(uiNodeId_p);
|
||
|
if (pIntNodeInfo == NULL)
|
||
|
{ // no node info structure available
|
||
|
Ret = kEplDllNoNodeInfo;
|
||
|
goto Exit;
|
||
|
}
|
||
|
|
||
|
EPL_DLLK_DBG_POST_TRACE_VALUE(kEplEventTypeDllkDelNode,
|
||
|
uiNodeId_p,
|
||
|
0);
|
||
|
|
||
|
// search node in whole list
|
||
|
ppIntNodeInfo = &EplDllkInstance_g.m_pFirstNodeInfo;
|
||
|
while ((*ppIntNodeInfo != NULL) && ((*ppIntNodeInfo)->m_uiNodeId != uiNodeId_p))
|
||
|
{
|
||
|
ppIntNodeInfo = &(*ppIntNodeInfo)->m_pNextNodeInfo;
|
||
|
}
|
||
|
if ((*ppIntNodeInfo == NULL) || ((*ppIntNodeInfo)->m_uiNodeId != uiNodeId_p))
|
||
|
{ // node was not found in list
|
||
|
// $$$ d.k. maybe this should be an error
|
||
|
goto Exit;
|
||
|
}
|
||
|
|
||
|
// remove node from list
|
||
|
*ppIntNodeInfo = pIntNodeInfo->m_pNextNodeInfo;
|
||
|
|
||
|
if ((pIntNodeInfo->m_pPreqTxBuffer != NULL)
|
||
|
&& (pIntNodeInfo->m_pPreqTxBuffer != &EplDllkInstance_g.m_pTxBuffer[EPL_DLLK_TXFRAME_PRES]))
|
||
|
{ // delete TxBuffer entry
|
||
|
uiHandle = pIntNodeInfo->m_pPreqTxBuffer - EplDllkInstance_g.m_pTxBuffer;
|
||
|
pIntNodeInfo->m_pPreqTxBuffer = NULL;
|
||
|
Ret = EplDllkDeleteTxFrame(uiHandle);
|
||
|
/* if (Ret != kEplSuccessful)
|
||
|
{
|
||
|
goto Exit;
|
||
|
}*/
|
||
|
}
|
||
|
|
||
|
Exit:
|
||
|
return Ret;
|
||
|
}
|
||
|
|
||
|
|
||
|
//---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: EplDllkSoftDeleteNode()
|
||
|
//
|
||
|
// Description: removes the specified node not immediately from the isochronous phase.
|
||
|
// Instead the will be removed after error (late/loss PRes) without
|
||
|
// charging the error.
|
||
|
//
|
||
|
// Parameters: uiNodeId_p = node ID
|
||
|
//
|
||
|
// Returns: tEplKernel = error code
|
||
|
//
|
||
|
//
|
||
|
// State:
|
||
|
//
|
||
|
//---------------------------------------------------------------------------
|
||
|
|
||
|
tEplKernel EplDllkSoftDeleteNode(unsigned int uiNodeId_p)
|
||
|
{
|
||
|
tEplKernel Ret = kEplSuccessful;
|
||
|
tEplDllkNodeInfo* pIntNodeInfo;
|
||
|
|
||
|
pIntNodeInfo = EplDllkGetNodeInfo(uiNodeId_p);
|
||
|
if (pIntNodeInfo == NULL)
|
||
|
{ // no node info structure available
|
||
|
Ret = kEplDllNoNodeInfo;
|
||
|
goto Exit;
|
||
|
}
|
||
|
|
||
|
EPL_DLLK_DBG_POST_TRACE_VALUE(kEplEventTypeDllkSoftDelNode,
|
||
|
uiNodeId_p,
|
||
|
0);
|
||
|
|
||
|
pIntNodeInfo->m_fSoftDelete = TRUE;
|
||
|
|
||
|
Exit:
|
||
|
return Ret;
|
||
|
}
|
||
|
|
||
|
|
||
|
#endif //(((EPL_MODULE_INTEGRATION) & (EPL_MODULE_NMT_MN)) != 0)
|
||
|
|
||
|
|
||
|
//=========================================================================//
|
||
|
// //
|
||
|
// P R I V A T E F U N C T I O N S //
|
||
|
// //
|
||
|
//=========================================================================//
|
||
|
|
||
|
|
||
|
//---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: EplDllkChangeState
|
||
|
//
|
||
|
// Description: change DLL state on event and diagnose some communication errors
|
||
|
//
|
||
|
// Parameters: NmtEvent_p = DLL event (wrapped in NMT event)
|
||
|
//
|
||
|
// Returns: tEplKernel = error code
|
||
|
//
|
||
|
//
|
||
|
// State:
|
||
|
//
|
||
|
//---------------------------------------------------------------------------
|
||
|
|
||
|
static tEplKernel EplDllkChangeState(tEplNmtEvent NmtEvent_p, tEplNmtState NmtState_p)
|
||
|
{
|
||
|
tEplKernel Ret = kEplSuccessful;
|
||
|
tEplEvent Event;
|
||
|
tEplErrorHandlerkEvent DllEvent;
|
||
|
|
||
|
DllEvent.m_ulDllErrorEvents = 0;
|
||
|
DllEvent.m_uiNodeId = 0;
|
||
|
DllEvent.m_NmtState = NmtState_p;
|
||
|
|
||
|
switch (NmtState_p)
|
||
|
{
|
||
|
case kEplNmtGsOff:
|
||
|
case kEplNmtGsInitialising:
|
||
|
case kEplNmtGsResetApplication:
|
||
|
case kEplNmtGsResetCommunication:
|
||
|
case kEplNmtGsResetConfiguration:
|
||
|
case kEplNmtCsBasicEthernet:
|
||
|
// enter DLL_GS_INIT
|
||
|
EplDllkInstance_g.m_DllState = kEplDllGsInit;
|
||
|
break;
|
||
|
|
||
|
case kEplNmtCsNotActive:
|
||
|
case kEplNmtCsPreOperational1:
|
||
|
// reduced EPL cycle is active
|
||
|
if (NmtEvent_p == kEplNmtEventDllCeSoc)
|
||
|
{ // SoC received
|
||
|
// enter DLL_CS_WAIT_PREQ
|
||
|
EplDllkInstance_g.m_DllState = kEplDllCsWaitPreq;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// enter DLL_GS_INIT
|
||
|
EplDllkInstance_g.m_DllState = kEplDllGsInit;
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case kEplNmtCsPreOperational2:
|
||
|
case kEplNmtCsReadyToOperate:
|
||
|
case kEplNmtCsOperational:
|
||
|
// full EPL cycle is active
|
||
|
|
||
|
switch (EplDllkInstance_g.m_DllState)
|
||
|
{
|
||
|
case kEplDllCsWaitPreq:
|
||
|
switch (NmtEvent_p)
|
||
|
{
|
||
|
// DLL_CT2
|
||
|
case kEplNmtEventDllCePreq:
|
||
|
// enter DLL_CS_WAIT_SOA
|
||
|
DllEvent.m_ulDllErrorEvents |= EPL_DLL_ERR_CN_RECVD_PREQ;
|
||
|
EplDllkInstance_g.m_DllState = kEplDllCsWaitSoa;
|
||
|
break;
|
||
|
|
||
|
// DLL_CT8
|
||
|
case kEplNmtEventDllCeFrameTimeout:
|
||
|
if (NmtState_p == kEplNmtCsPreOperational2)
|
||
|
{ // ignore frame timeout in PreOp2,
|
||
|
// because the previously configured cycle len
|
||
|
// may be wrong.
|
||
|
// 2008/10/15 d.k. If it would not be ignored,
|
||
|
// we would go cyclically to PreOp1 and on next
|
||
|
// SoC back to PreOp2.
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
// report DLL_CEV_LOSS_SOC and DLL_CEV_LOSS_SOA
|
||
|
DllEvent.m_ulDllErrorEvents |= EPL_DLL_ERR_CN_LOSS_SOA | EPL_DLL_ERR_CN_LOSS_SOC;
|
||
|
|
||
|
// enter DLL_CS_WAIT_SOC
|
||
|
EplDllkInstance_g.m_DllState = kEplDllCsWaitSoc;
|
||
|
break;
|
||
|
|
||
|
case kEplNmtEventDllCeSoa:
|
||
|
// check if multiplexed and PReq should have been received in this cycle
|
||
|
// and if >= NMT_CS_READY_TO_OPERATE
|
||
|
if ((EplDllkInstance_g.m_uiCycleCount == 0)
|
||
|
&& (NmtState_p >= kEplNmtCsReadyToOperate))
|
||
|
{ // report DLL_CEV_LOSS_OF_PREQ
|
||
|
DllEvent.m_ulDllErrorEvents |= EPL_DLL_ERR_CN_LOSS_PREQ;
|
||
|
}
|
||
|
|
||
|
// enter DLL_CS_WAIT_SOC
|
||
|
EplDllkInstance_g.m_DllState = kEplDllCsWaitSoc;
|
||
|
break;
|
||
|
|
||
|
// DLL_CT7
|
||
|
case kEplNmtEventDllCeSoc:
|
||
|
case kEplNmtEventDllCeAsnd:
|
||
|
// report DLL_CEV_LOSS_SOA
|
||
|
DllEvent.m_ulDllErrorEvents |= EPL_DLL_ERR_CN_LOSS_SOA;
|
||
|
|
||
|
case kEplNmtEventDllCePres:
|
||
|
default:
|
||
|
// remain in this state
|
||
|
break;
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case kEplDllCsWaitSoc:
|
||
|
switch (NmtEvent_p)
|
||
|
{
|
||
|
// DLL_CT1
|
||
|
case kEplNmtEventDllCeSoc:
|
||
|
// start of cycle and isochronous phase
|
||
|
// enter DLL_CS_WAIT_PREQ
|
||
|
EplDllkInstance_g.m_DllState = kEplDllCsWaitPreq;
|
||
|
break;
|
||
|
|
||
|
// DLL_CT4
|
||
|
// case kEplNmtEventDllCePres:
|
||
|
case kEplNmtEventDllCeFrameTimeout:
|
||
|
if (NmtState_p == kEplNmtCsPreOperational2)
|
||
|
{ // ignore frame timeout in PreOp2,
|
||
|
// because the previously configured cycle len
|
||
|
// may be wrong.
|
||
|
// 2008/10/15 d.k. If it would not be ignored,
|
||
|
// we would go cyclically to PreOp1 and on next
|
||
|
// SoC back to PreOp2.
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
// fall through
|
||
|
|
||
|
case kEplNmtEventDllCePreq:
|
||
|
case kEplNmtEventDllCeSoa:
|
||
|
// report DLL_CEV_LOSS_SOC
|
||
|
DllEvent.m_ulDllErrorEvents |= EPL_DLL_ERR_CN_LOSS_SOC;
|
||
|
|
||
|
case kEplNmtEventDllCeAsnd:
|
||
|
default:
|
||
|
// remain in this state
|
||
|
break;
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case kEplDllCsWaitSoa:
|
||
|
switch (NmtEvent_p)
|
||
|
{
|
||
|
case kEplNmtEventDllCeFrameTimeout:
|
||
|
// DLL_CT3
|
||
|
if (NmtState_p == kEplNmtCsPreOperational2)
|
||
|
{ // ignore frame timeout in PreOp2,
|
||
|
// because the previously configured cycle len
|
||
|
// may be wrong.
|
||
|
// 2008/10/15 d.k. If it would not be ignored,
|
||
|
// we would go cyclically to PreOp1 and on next
|
||
|
// SoC back to PreOp2.
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
// fall through
|
||
|
|
||
|
case kEplNmtEventDllCePreq:
|
||
|
// report DLL_CEV_LOSS_SOC and DLL_CEV_LOSS_SOA
|
||
|
DllEvent.m_ulDllErrorEvents |= EPL_DLL_ERR_CN_LOSS_SOA | EPL_DLL_ERR_CN_LOSS_SOC;
|
||
|
|
||
|
case kEplNmtEventDllCeSoa:
|
||
|
// enter DLL_CS_WAIT_SOC
|
||
|
EplDllkInstance_g.m_DllState = kEplDllCsWaitSoc;
|
||
|
break;
|
||
|
|
||
|
// DLL_CT9
|
||
|
case kEplNmtEventDllCeSoc:
|
||
|
// report DLL_CEV_LOSS_SOA
|
||
|
DllEvent.m_ulDllErrorEvents |= EPL_DLL_ERR_CN_LOSS_SOA;
|
||
|
|
||
|
// enter DLL_CS_WAIT_PREQ
|
||
|
EplDllkInstance_g.m_DllState = kEplDllCsWaitPreq;
|
||
|
break;
|
||
|
|
||
|
// DLL_CT10
|
||
|
case kEplNmtEventDllCeAsnd:
|
||
|
// report DLL_CEV_LOSS_SOA
|
||
|
DllEvent.m_ulDllErrorEvents |= EPL_DLL_ERR_CN_LOSS_SOA;
|
||
|
|
||
|
case kEplNmtEventDllCePres:
|
||
|
default:
|
||
|
// remain in this state
|
||
|
break;
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case kEplDllGsInit:
|
||
|
// enter DLL_CS_WAIT_PREQ
|
||
|
EplDllkInstance_g.m_DllState = kEplDllCsWaitPreq;
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
break;
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case kEplNmtCsStopped:
|
||
|
// full EPL cycle is active, but without PReq/PRes
|
||
|
|
||
|
switch (EplDllkInstance_g.m_DllState)
|
||
|
{
|
||
|
case kEplDllCsWaitPreq:
|
||
|
switch (NmtEvent_p)
|
||
|
{
|
||
|
// DLL_CT2
|
||
|
case kEplNmtEventDllCePreq:
|
||
|
// enter DLL_CS_WAIT_SOA
|
||
|
EplDllkInstance_g.m_DllState = kEplDllCsWaitSoa;
|
||
|
break;
|
||
|
|
||
|
// DLL_CT8
|
||
|
case kEplNmtEventDllCeFrameTimeout:
|
||
|
// report DLL_CEV_LOSS_SOC and DLL_CEV_LOSS_SOA
|
||
|
DllEvent.m_ulDllErrorEvents |= EPL_DLL_ERR_CN_LOSS_SOA | EPL_DLL_ERR_CN_LOSS_SOC;
|
||
|
|
||
|
case kEplNmtEventDllCeSoa:
|
||
|
// NMT_CS_STOPPED active
|
||
|
// it is Ok if no PReq was received
|
||
|
|
||
|
// enter DLL_CS_WAIT_SOC
|
||
|
EplDllkInstance_g.m_DllState = kEplDllCsWaitSoc;
|
||
|
break;
|
||
|
|
||
|
// DLL_CT7
|
||
|
case kEplNmtEventDllCeSoc:
|
||
|
case kEplNmtEventDllCeAsnd:
|
||
|
// report DLL_CEV_LOSS_SOA
|
||
|
DllEvent.m_ulDllErrorEvents |= EPL_DLL_ERR_CN_LOSS_SOA;
|
||
|
|
||
|
case kEplNmtEventDllCePres:
|
||
|
default:
|
||
|
// remain in this state
|
||
|
break;
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case kEplDllCsWaitSoc:
|
||
|
switch (NmtEvent_p)
|
||
|
{
|
||
|
// DLL_CT1
|
||
|
case kEplNmtEventDllCeSoc:
|
||
|
// start of cycle and isochronous phase
|
||
|
// enter DLL_CS_WAIT_SOA
|
||
|
EplDllkInstance_g.m_DllState = kEplDllCsWaitSoa;
|
||
|
break;
|
||
|
|
||
|
// DLL_CT4
|
||
|
// case kEplNmtEventDllCePres:
|
||
|
case kEplNmtEventDllCePreq:
|
||
|
case kEplNmtEventDllCeSoa:
|
||
|
case kEplNmtEventDllCeFrameTimeout:
|
||
|
// report DLL_CEV_LOSS_SOC
|
||
|
DllEvent.m_ulDllErrorEvents |= EPL_DLL_ERR_CN_LOSS_SOC;
|
||
|
|
||
|
case kEplNmtEventDllCeAsnd:
|
||
|
default:
|
||
|
// remain in this state
|
||
|
break;
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case kEplDllCsWaitSoa:
|
||
|
switch (NmtEvent_p)
|
||
|
{
|
||
|
// DLL_CT3
|
||
|
case kEplNmtEventDllCeFrameTimeout:
|
||
|
// report DLL_CEV_LOSS_SOC and DLL_CEV_LOSS_SOA
|
||
|
DllEvent.m_ulDllErrorEvents |= EPL_DLL_ERR_CN_LOSS_SOA | EPL_DLL_ERR_CN_LOSS_SOC;
|
||
|
|
||
|
case kEplNmtEventDllCeSoa:
|
||
|
// enter DLL_CS_WAIT_SOC
|
||
|
EplDllkInstance_g.m_DllState = kEplDllCsWaitSoc;
|
||
|
break;
|
||
|
|
||
|
// DLL_CT9
|
||
|
case kEplNmtEventDllCeSoc:
|
||
|
// report DLL_CEV_LOSS_SOA
|
||
|
DllEvent.m_ulDllErrorEvents |= EPL_DLL_ERR_CN_LOSS_SOA;
|
||
|
// remain in DLL_CS_WAIT_SOA
|
||
|
break;
|
||
|
|
||
|
// DLL_CT10
|
||
|
case kEplNmtEventDllCeAsnd:
|
||
|
// report DLL_CEV_LOSS_SOA
|
||
|
DllEvent.m_ulDllErrorEvents |= EPL_DLL_ERR_CN_LOSS_SOA;
|
||
|
|
||
|
case kEplNmtEventDllCePreq:
|
||
|
// NMT_CS_STOPPED active and we do not expect any PReq
|
||
|
// so just ignore it
|
||
|
case kEplNmtEventDllCePres:
|
||
|
default:
|
||
|
// remain in this state
|
||
|
break;
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case kEplDllGsInit:
|
||
|
default:
|
||
|
// enter DLL_CS_WAIT_PREQ
|
||
|
EplDllkInstance_g.m_DllState = kEplDllCsWaitSoa;
|
||
|
break;
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
#if (((EPL_MODULE_INTEGRATION) & (EPL_MODULE_NMT_MN)) != 0)
|
||
|
case kEplNmtMsNotActive:
|
||
|
case kEplNmtMsBasicEthernet:
|
||
|
break;
|
||
|
|
||
|
case kEplNmtMsPreOperational1:
|
||
|
// reduced EPL cycle is active
|
||
|
if (EplDllkInstance_g.m_DllState != kEplDllMsNonCyclic)
|
||
|
{ // stop cycle timer
|
||
|
#if EPL_TIMER_USE_HIGHRES != FALSE
|
||
|
Ret = EplTimerHighReskDeleteTimer(&EplDllkInstance_g.m_TimerHdlCycle);
|
||
|
#endif
|
||
|
EplDllkInstance_g.m_DllState = kEplDllMsNonCyclic;
|
||
|
|
||
|
// stop further processing,
|
||
|
// because it will be restarted by NMT MN module
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
switch (NmtEvent_p)
|
||
|
{
|
||
|
case kEplNmtEventDllMeSocTrig:
|
||
|
case kEplNmtEventDllCeAsnd:
|
||
|
{ // because of reduced EPL cycle SoA shall be triggered, not SoC
|
||
|
tEplDllState DummyDllState;
|
||
|
|
||
|
Ret = EplDllkAsyncFrameNotReceived(EplDllkInstance_g.m_LastReqServiceId,
|
||
|
EplDllkInstance_g.m_uiLastTargetNodeId);
|
||
|
|
||
|
// go ahead and send SoA
|
||
|
Ret = EplDllkMnSendSoa(NmtState_p,
|
||
|
&DummyDllState,
|
||
|
(EplDllkInstance_g.m_uiCycleCount >= EPL_C_DLL_PREOP1_START_CYCLES));
|
||
|
// increment cycle counter to detect if EPL_C_DLL_PREOP1_START_CYCLES empty cycles are elapsed
|
||
|
EplDllkInstance_g.m_uiCycleCount++;
|
||
|
|
||
|
// reprogram timer
|
||
|
#if EPL_TIMER_USE_HIGHRES != FALSE
|
||
|
if (EplDllkInstance_g.m_DllConfigParam.m_dwAsyncSlotTimeout != 0)
|
||
|
{
|
||
|
Ret = EplTimerHighReskModifyTimerNs(&EplDllkInstance_g.m_TimerHdlCycle,
|
||
|
EplDllkInstance_g.m_DllConfigParam.m_dwAsyncSlotTimeout,
|
||
|
EplDllkCbMnTimerCycle,
|
||
|
0L,
|
||
|
FALSE);
|
||
|
}
|
||
|
#endif
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
default:
|
||
|
break;
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case kEplNmtMsPreOperational2:
|
||
|
case kEplNmtMsReadyToOperate:
|
||
|
case kEplNmtMsOperational:
|
||
|
// full EPL cycle is active
|
||
|
switch (NmtEvent_p)
|
||
|
{
|
||
|
case kEplNmtEventDllMeSocTrig:
|
||
|
{
|
||
|
// update cycle counter
|
||
|
if (EplDllkInstance_g.m_DllConfigParam.m_uiMultiplCycleCnt > 0)
|
||
|
{ // multiplexed cycle active
|
||
|
EplDllkInstance_g.m_uiCycleCount = (EplDllkInstance_g.m_uiCycleCount + 1) % EplDllkInstance_g.m_DllConfigParam.m_uiMultiplCycleCnt;
|
||
|
// $$$ check multiplexed cycle restart
|
||
|
// -> toggle MC flag
|
||
|
// -> change node linked list
|
||
|
}
|
||
|
else
|
||
|
{ // non-multiplexed cycle active
|
||
|
// start with first node in isochronous phase
|
||
|
EplDllkInstance_g.m_pCurNodeInfo = NULL;
|
||
|
}
|
||
|
|
||
|
switch (EplDllkInstance_g.m_DllState)
|
||
|
{
|
||
|
case kEplDllMsNonCyclic:
|
||
|
{ // start continuous cycle timer
|
||
|
#if EPL_TIMER_USE_HIGHRES != FALSE
|
||
|
Ret = EplTimerHighReskModifyTimerNs(&EplDllkInstance_g.m_TimerHdlCycle,
|
||
|
EplDllkInstance_g.m_ullFrameTimeout,
|
||
|
EplDllkCbMnTimerCycle,
|
||
|
0L,
|
||
|
TRUE);
|
||
|
#endif
|
||
|
// continue with sending SoC
|
||
|
}
|
||
|
|
||
|
case kEplDllMsWaitAsnd:
|
||
|
case kEplDllMsWaitSocTrig:
|
||
|
{ // if m_LastReqServiceId is still valid,
|
||
|
// SoA was not correctly answered
|
||
|
// and user part has to be informed
|
||
|
Ret = EplDllkAsyncFrameNotReceived(EplDllkInstance_g.m_LastReqServiceId,
|
||
|
EplDllkInstance_g.m_uiLastTargetNodeId);
|
||
|
|
||
|
// send SoC
|
||
|
Ret = EplDllkMnSendSoc();
|
||
|
|
||
|
// new DLL state
|
||
|
EplDllkInstance_g.m_DllState = kEplDllMsWaitPreqTrig;
|
||
|
|
||
|
// start WaitSoCPReq Timer
|
||
|
#if EPL_TIMER_USE_HIGHRES != FALSE
|
||
|
Ret = EplTimerHighReskModifyTimerNs(&EplDllkInstance_g.m_TimerHdlResponse,
|
||
|
EplDllkInstance_g.m_DllConfigParam.m_dwWaitSocPreq,
|
||
|
EplDllkCbMnTimerResponse,
|
||
|
0L,
|
||
|
FALSE);
|
||
|
#endif
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
default:
|
||
|
{ // wrong DLL state / cycle time exceeded
|
||
|
DllEvent.m_ulDllErrorEvents |= EPL_DLL_ERR_MN_CYCTIMEEXCEED;
|
||
|
EplDllkInstance_g.m_DllState = kEplDllMsWaitSocTrig;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
case kEplNmtEventDllMePresTimeout:
|
||
|
{
|
||
|
|
||
|
switch (EplDllkInstance_g.m_DllState)
|
||
|
{
|
||
|
case kEplDllMsWaitPres:
|
||
|
{ // PRes not received
|
||
|
|
||
|
if (EplDllkInstance_g.m_pCurNodeInfo->m_fSoftDelete == FALSE)
|
||
|
{ // normal isochronous CN
|
||
|
DllEvent.m_ulDllErrorEvents |= EPL_DLL_ERR_MN_CN_LOSS_PRES;
|
||
|
DllEvent.m_uiNodeId = EplDllkInstance_g.m_pCurNodeInfo->m_uiNodeId;
|
||
|
}
|
||
|
else
|
||
|
{ // CN shall be deleted softly
|
||
|
Event.m_EventSink = kEplEventSinkDllkCal;
|
||
|
Event.m_EventType = kEplEventTypeDllkSoftDelNode;
|
||
|
// $$$ d.k. set Event.m_NetTime to current time
|
||
|
Event.m_uiSize = sizeof (unsigned int);
|
||
|
Event.m_pArg = &EplDllkInstance_g.m_pCurNodeInfo->m_uiNodeId;
|
||
|
Ret = EplEventkPost(&Event);
|
||
|
}
|
||
|
|
||
|
// continue with sending next PReq
|
||
|
}
|
||
|
|
||
|
case kEplDllMsWaitPreqTrig:
|
||
|
{
|
||
|
// send next PReq
|
||
|
Ret = EplDllkMnSendPreq(NmtState_p, &EplDllkInstance_g.m_DllState);
|
||
|
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
default:
|
||
|
{ // wrong DLL state
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
case kEplNmtEventDllCePres:
|
||
|
{
|
||
|
|
||
|
switch (EplDllkInstance_g.m_DllState)
|
||
|
{
|
||
|
case kEplDllMsWaitPres:
|
||
|
{ // PRes received
|
||
|
// send next PReq
|
||
|
Ret = EplDllkMnSendPreq(NmtState_p, &EplDllkInstance_g.m_DllState);
|
||
|
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
default:
|
||
|
{ // wrong DLL state
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
case kEplNmtEventDllMeSoaTrig:
|
||
|
{
|
||
|
|
||
|
switch (EplDllkInstance_g.m_DllState)
|
||
|
{
|
||
|
case kEplDllMsWaitSoaTrig:
|
||
|
{ // MN PRes sent
|
||
|
// send SoA
|
||
|
Ret = EplDllkMnSendSoa(NmtState_p, &EplDllkInstance_g.m_DllState, TRUE);
|
||
|
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
default:
|
||
|
{ // wrong DLL state
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
case kEplNmtEventDllCeAsnd:
|
||
|
{ // ASnd has been received, but it may be not the requested one
|
||
|
/*
|
||
|
// report if SoA was correctly answered
|
||
|
Ret = EplDllkAsyncFrameNotReceived(EplDllkInstance_g.m_LastReqServiceId,
|
||
|
EplDllkInstance_g.m_uiLastTargetNodeId);
|
||
|
*/
|
||
|
if (EplDllkInstance_g.m_DllState == kEplDllMsWaitAsnd)
|
||
|
{
|
||
|
EplDllkInstance_g.m_DllState = kEplDllMsWaitSocTrig;
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
default:
|
||
|
break;
|
||
|
}
|
||
|
break;
|
||
|
#endif //(((EPL_MODULE_INTEGRATION) & (EPL_MODULE_NMT_MN)) != 0)
|
||
|
|
||
|
default:
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if (DllEvent.m_ulDllErrorEvents != 0)
|
||
|
{ // error event set -> post it to error handler
|
||
|
Event.m_EventSink = kEplEventSinkErrk;
|
||
|
Event.m_EventType = kEplEventTypeDllError;
|
||
|
// $$$ d.k. set Event.m_NetTime to current time
|
||
|
Event.m_uiSize = sizeof (DllEvent);
|
||
|
Event.m_pArg = &DllEvent;
|
||
|
Ret = EplEventkPost(&Event);
|
||
|
}
|
||
|
|
||
|
return Ret;
|
||
|
}
|
||
|
|
||
|
//---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: EplDllkCbFrameReceived()
|
||
|
//
|
||
|
// Description: called from EdrvInterruptHandler()
|
||
|
//
|
||
|
// Parameters: pRxBuffer_p = receive buffer structure
|
||
|
//
|
||
|
// Returns: (none)
|
||
|
//
|
||
|
//
|
||
|
// State:
|
||
|
//
|
||
|
//---------------------------------------------------------------------------
|
||
|
|
||
|
static void EplDllkCbFrameReceived(tEdrvRxBuffer * pRxBuffer_p)
|
||
|
{
|
||
|
tEplKernel Ret = kEplSuccessful;
|
||
|
tEplNmtState NmtState;
|
||
|
tEplNmtEvent NmtEvent = kEplNmtEventNoEvent;
|
||
|
tEplEvent Event;
|
||
|
tEplFrame *pFrame;
|
||
|
tEplFrame *pTxFrame;
|
||
|
tEdrvTxBuffer *pTxBuffer = NULL;
|
||
|
tEplFrameInfo FrameInfo;
|
||
|
tEplMsgType MsgType;
|
||
|
tEplDllReqServiceId ReqServiceId;
|
||
|
unsigned int uiAsndServiceId;
|
||
|
unsigned int uiNodeId;
|
||
|
BYTE bFlag1;
|
||
|
|
||
|
BENCHMARK_MOD_02_SET(3);
|
||
|
NmtState = EplNmtkGetNmtState();
|
||
|
|
||
|
if (NmtState <= kEplNmtGsResetConfiguration)
|
||
|
{
|
||
|
goto Exit;
|
||
|
}
|
||
|
|
||
|
pFrame = (tEplFrame *) pRxBuffer_p->m_pbBuffer;
|
||
|
|
||
|
#if EDRV_EARLY_RX_INT != FALSE
|
||
|
switch (pRxBuffer_p->m_BufferInFrame)
|
||
|
{
|
||
|
case kEdrvBufferFirstInFrame:
|
||
|
{
|
||
|
MsgType = (tEplMsgType)AmiGetByteFromLe(&pFrame->m_le_bMessageType);
|
||
|
if (MsgType == kEplMsgTypePreq)
|
||
|
{
|
||
|
if (EplDllkInstance_g.m_DllState == kEplDllCsWaitPreq)
|
||
|
{ // PReq expected and actually received
|
||
|
// d.k.: The condition above is sufficent, because EPL cycle is active
|
||
|
// and no non-EPL frame shall be received in isochronous phase.
|
||
|
// start transmission PRes
|
||
|
// $$$ What if Tx buffer is invalid?
|
||
|
pTxBuffer = &EplDllkInstance_g.m_pTxBuffer[EPL_DLLK_TXFRAME_PRES];
|
||
|
#if (EPL_DLL_PRES_READY_AFTER_SOA != FALSE) || (EPL_DLL_PRES_READY_AFTER_SOC != FALSE)
|
||
|
Ret = EdrvTxMsgStart(pTxBuffer);
|
||
|
#else
|
||
|
pTxFrame = (tEplFrame *) pTxBuffer->m_pbBuffer;
|
||
|
// update frame (NMT state, RD, RS, PR, MS, EN flags)
|
||
|
AmiSetByteToLe(&pTxFrame->m_Data.m_Pres.m_le_bNmtStatus, (BYTE) NmtState);
|
||
|
AmiSetByteToLe(&pTxFrame->m_Data.m_Pres.m_le_bFlag2, EplDllkInstance_g.m_bFlag2);
|
||
|
if (NmtState != kEplNmtCsOperational)
|
||
|
{ // mark PDO as invalid in NMT state Op
|
||
|
// $$$ reset only RD flag; set other flags appropriately
|
||
|
AmiSetByteToLe(&pTxFrame->m_Data.m_Pres.m_le_bFlag1, 0);
|
||
|
}
|
||
|
// $$$ make function that updates Pres, StatusRes
|
||
|
// send PRes frame
|
||
|
Ret = EdrvSendTxMsg(pTxBuffer);
|
||
|
#endif
|
||
|
}
|
||
|
}
|
||
|
goto Exit;
|
||
|
}
|
||
|
|
||
|
case kEdrvBufferMiddleInFrame:
|
||
|
{
|
||
|
goto Exit;
|
||
|
}
|
||
|
|
||
|
case kEdrvBufferLastInFrame:
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
FrameInfo.m_pFrame = pFrame;
|
||
|
FrameInfo.m_uiFrameSize = pRxBuffer_p->m_uiRxMsgLen;
|
||
|
FrameInfo.m_NetTime.m_dwNanoSec = pRxBuffer_p->m_NetTime.m_dwNanoSec;
|
||
|
FrameInfo.m_NetTime.m_dwSec = pRxBuffer_p->m_NetTime.m_dwSec;
|
||
|
|
||
|
if (AmiGetWordFromBe(&pFrame->m_be_wEtherType) != EPL_C_DLL_ETHERTYPE_EPL)
|
||
|
{ // non-EPL frame
|
||
|
//TRACE2("EplDllkCbFrameReceived: pfnCbAsync=0x%p SrcMAC=0x%llx\n", EplDllkInstance_g.m_pfnCbAsync, AmiGetQword48FromBe(pFrame->m_be_abSrcMac));
|
||
|
if (EplDllkInstance_g.m_pfnCbAsync != NULL)
|
||
|
{ // handler for async frames is registered
|
||
|
EplDllkInstance_g.m_pfnCbAsync(&FrameInfo);
|
||
|
}
|
||
|
|
||
|
goto Exit;
|
||
|
}
|
||
|
|
||
|
MsgType = (tEplMsgType)AmiGetByteFromLe(&pFrame->m_le_bMessageType);
|
||
|
switch (MsgType)
|
||
|
{
|
||
|
case kEplMsgTypePreq:
|
||
|
{
|
||
|
// PReq frame
|
||
|
// d.k.: (we assume that this PReq frame is intended for us and don't check DstNodeId)
|
||
|
if (AmiGetByteFromLe(&pFrame->m_le_bDstNodeId) != EplDllkInstance_g.m_DllConfigParam.m_uiNodeId)
|
||
|
{ // this PReq is not intended for us
|
||
|
goto Exit;
|
||
|
}
|
||
|
NmtEvent = kEplNmtEventDllCePreq;
|
||
|
|
||
|
if (NmtState >= kEplNmtMsNotActive)
|
||
|
{ // MN is active -> wrong msg type
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
#if EDRV_EARLY_RX_INT == FALSE
|
||
|
if (NmtState >= kEplNmtCsPreOperational2)
|
||
|
{ // respond to and process PReq frames only in PreOp2, ReadyToOp and Op
|
||
|
// Does PRes exist?
|
||
|
pTxBuffer = &EplDllkInstance_g.m_pTxBuffer[EPL_DLLK_TXFRAME_PRES];
|
||
|
if (pTxBuffer->m_pbBuffer != NULL)
|
||
|
{ // PRes does exist
|
||
|
#if (EPL_DLL_PRES_READY_AFTER_SOA != FALSE) || (EPL_DLL_PRES_READY_AFTER_SOC != FALSE)
|
||
|
EdrvTxMsgStart(pTxBuffer);
|
||
|
#else
|
||
|
pTxFrame = (tEplFrame *) pTxBuffer->m_pbBuffer;
|
||
|
// update frame (NMT state, RD, RS, PR, MS, EN flags)
|
||
|
AmiSetByteToLe(&pTxFrame->m_Data.m_Pres.m_le_bNmtStatus, (BYTE) NmtState);
|
||
|
AmiSetByteToLe(&pTxFrame->m_Data.m_Pres.m_le_bFlag2, EplDllkInstance_g.m_bFlag2);
|
||
|
bFlag1 = AmiGetByteFromLe(&pFrame->m_Data.m_Preq.m_le_bFlag1);
|
||
|
// save EA flag
|
||
|
EplDllkInstance_g.m_bMnFlag1 =
|
||
|
(EplDllkInstance_g.m_bMnFlag1 & ~EPL_FRAME_FLAG1_EA)
|
||
|
| (bFlag1 & EPL_FRAME_FLAG1_EA);
|
||
|
// preserve MS flag
|
||
|
bFlag1 &= EPL_FRAME_FLAG1_MS;
|
||
|
// add EN flag from Error signaling module
|
||
|
bFlag1 |= EplDllkInstance_g.m_bFlag1 & EPL_FRAME_FLAG1_EN;
|
||
|
if (NmtState != kEplNmtCsOperational)
|
||
|
{ // mark PDO as invalid in NMT state Op
|
||
|
// reset only RD flag
|
||
|
AmiSetByteToLe(&pTxFrame->m_Data.m_Pres.m_le_bFlag1, bFlag1);
|
||
|
}
|
||
|
else
|
||
|
{ // leave RD flag untouched
|
||
|
AmiSetByteToLe(&pTxFrame->m_Data.m_Pres.m_le_bFlag1,
|
||
|
(AmiGetByteFromLe(&pTxFrame->m_Data.m_Pres.m_le_bFlag1) & EPL_FRAME_FLAG1_RD)
|
||
|
| bFlag1);
|
||
|
}
|
||
|
// $$$ update EPL_DLL_PRES_READY_AFTER_* code
|
||
|
// send PRes frame
|
||
|
Ret = EdrvSendTxMsg(pTxBuffer);
|
||
|
if (Ret != kEplSuccessful)
|
||
|
{
|
||
|
goto Exit;
|
||
|
}
|
||
|
#endif
|
||
|
}
|
||
|
#endif
|
||
|
// inform PDO module
|
||
|
#if (((EPL_MODULE_INTEGRATION) & (EPL_MODULE_PDOK)) != 0)
|
||
|
if (NmtState >= kEplNmtCsReadyToOperate)
|
||
|
{ // inform PDO module only in ReadyToOp and Op
|
||
|
if (NmtState != kEplNmtCsOperational)
|
||
|
{
|
||
|
// reset RD flag and all other flags, but that does not matter, because they were processed above
|
||
|
AmiSetByteToLe(&pFrame->m_Data.m_Preq.m_le_bFlag1, 0);
|
||
|
}
|
||
|
|
||
|
// compares real frame size and PDO size
|
||
|
if ((unsigned int) (AmiGetWordFromLe(&pFrame->m_Data.m_Preq.m_le_wSize) + 24)
|
||
|
> FrameInfo.m_uiFrameSize)
|
||
|
{ // format error
|
||
|
tEplErrorHandlerkEvent DllEvent;
|
||
|
|
||
|
DllEvent.m_ulDllErrorEvents = EPL_DLL_ERR_INVALID_FORMAT;
|
||
|
DllEvent.m_uiNodeId = AmiGetByteFromLe(&pFrame->m_le_bSrcNodeId);
|
||
|
DllEvent.m_NmtState = NmtState;
|
||
|
Event.m_EventSink = kEplEventSinkErrk;
|
||
|
Event.m_EventType = kEplEventTypeDllError;
|
||
|
Event.m_NetTime = FrameInfo.m_NetTime;
|
||
|
Event.m_uiSize = sizeof (DllEvent);
|
||
|
Event.m_pArg = &DllEvent;
|
||
|
Ret = EplEventkPost(&Event);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
// forward PReq frame as RPDO to PDO module
|
||
|
Ret = EplPdokCbPdoReceived(&FrameInfo);
|
||
|
|
||
|
}
|
||
|
#if (EPL_DLL_PRES_READY_AFTER_SOC != FALSE)
|
||
|
if (pTxBuffer->m_pbBuffer != NULL)
|
||
|
{ // PRes does exist
|
||
|
// inform PDO module about PRes after PReq
|
||
|
FrameInfo.m_pFrame = (tEplFrame *) pTxBuffer->m_pbBuffer;
|
||
|
FrameInfo.m_uiFrameSize = pTxBuffer->m_uiMaxBufferLen;
|
||
|
Ret = EplPdokCbPdoTransmitted(&FrameInfo);
|
||
|
}
|
||
|
#endif
|
||
|
#endif
|
||
|
|
||
|
#if EDRV_EARLY_RX_INT == FALSE
|
||
|
// $$$ inform emergency protocol handling (error signaling module) about flags
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
// reset cycle counter
|
||
|
EplDllkInstance_g.m_uiCycleCount = 0;
|
||
|
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
case kEplMsgTypePres:
|
||
|
{
|
||
|
#if (((EPL_MODULE_INTEGRATION) & (EPL_MODULE_NMT_MN)) != 0)
|
||
|
tEplDllkNodeInfo* pIntNodeInfo;
|
||
|
tEplHeartbeatEvent HeartbeatEvent;
|
||
|
#endif
|
||
|
|
||
|
// PRes frame
|
||
|
NmtEvent = kEplNmtEventDllCePres;
|
||
|
|
||
|
uiNodeId = AmiGetByteFromLe(&pFrame->m_le_bSrcNodeId);
|
||
|
|
||
|
if ((NmtState >= kEplNmtCsPreOperational2)
|
||
|
&& (NmtState <= kEplNmtCsOperational))
|
||
|
{ // process PRes frames only in PreOp2, ReadyToOp and Op of CN
|
||
|
|
||
|
#if (((EPL_MODULE_INTEGRATION) & (EPL_MODULE_NMT_MN)) != 0)
|
||
|
pIntNodeInfo = EplDllkGetNodeInfo(uiNodeId);
|
||
|
if (pIntNodeInfo == NULL)
|
||
|
{ // no node info structure available
|
||
|
Ret = kEplDllNoNodeInfo;
|
||
|
goto Exit;
|
||
|
}
|
||
|
}
|
||
|
else if (EplDllkInstance_g.m_DllState == kEplDllMsWaitPres)
|
||
|
{ // or process PRes frames in MsWaitPres
|
||
|
|
||
|
pIntNodeInfo = EplDllkInstance_g.m_pCurNodeInfo;
|
||
|
if ((pIntNodeInfo == NULL) || (pIntNodeInfo->m_uiNodeId != uiNodeId))
|
||
|
{ // ignore PRes, because it is from wrong CN
|
||
|
// $$$ maybe post event to NmtMn module
|
||
|
goto Exit;
|
||
|
}
|
||
|
|
||
|
// forward Flag2 to asynchronous scheduler
|
||
|
bFlag1 = AmiGetByteFromLe(&pFrame->m_Data.m_Asnd.m_Payload.m_StatusResponse.m_le_bFlag2);
|
||
|
Ret = EplDllkCalAsyncSetPendingRequests(uiNodeId,
|
||
|
((tEplDllAsyncReqPriority) ((bFlag1 & EPL_FRAME_FLAG2_PR) >> EPL_FRAME_FLAG2_PR_SHIFT)),
|
||
|
(bFlag1 & EPL_FRAME_FLAG2_RS));
|
||
|
|
||
|
#endif
|
||
|
}
|
||
|
else
|
||
|
{ // ignore PRes, because it was received in wrong NMT state
|
||
|
// but execute EplDllkChangeState() and post event to NMT module
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
#if (((EPL_MODULE_INTEGRATION) & (EPL_MODULE_NMT_MN)) != 0)
|
||
|
{ // check NMT state of CN
|
||
|
HeartbeatEvent.m_wErrorCode = EPL_E_NO_ERROR;
|
||
|
HeartbeatEvent.m_NmtState =
|
||
|
(tEplNmtState) (AmiGetByteFromLe(&pFrame->m_Data.m_Pres.m_le_bNmtStatus) | EPL_NMT_TYPE_CS);
|
||
|
if (pIntNodeInfo->m_NmtState != HeartbeatEvent.m_NmtState)
|
||
|
{ // NMT state of CN has changed -> post event to NmtMnu module
|
||
|
if (pIntNodeInfo->m_fSoftDelete == FALSE)
|
||
|
{ // normal isochronous CN
|
||
|
HeartbeatEvent.m_uiNodeId = uiNodeId;
|
||
|
Event.m_EventSink = kEplEventSinkNmtMnu;
|
||
|
Event.m_EventType = kEplEventTypeHeartbeat;
|
||
|
Event.m_uiSize = sizeof (HeartbeatEvent);
|
||
|
Event.m_pArg = &HeartbeatEvent;
|
||
|
}
|
||
|
else
|
||
|
{ // CN shall be deleted softly
|
||
|
Event.m_EventSink = kEplEventSinkDllkCal;
|
||
|
Event.m_EventType = kEplEventTypeDllkSoftDelNode;
|
||
|
Event.m_uiSize = sizeof (unsigned int);
|
||
|
Event.m_pArg = &pIntNodeInfo->m_uiNodeId;
|
||
|
}
|
||
|
Event.m_NetTime = FrameInfo.m_NetTime;
|
||
|
Ret = EplEventkPost(&Event);
|
||
|
|
||
|
// save current NMT state of CN in internal node structure
|
||
|
pIntNodeInfo->m_NmtState = HeartbeatEvent.m_NmtState;
|
||
|
}
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
// inform PDO module
|
||
|
#if (((EPL_MODULE_INTEGRATION) & (EPL_MODULE_PDOK)) != 0)
|
||
|
if ((NmtState != kEplNmtCsPreOperational2)
|
||
|
&& (NmtState != kEplNmtMsPreOperational2))
|
||
|
{ // inform PDO module only in ReadyToOp and Op
|
||
|
// compare real frame size and PDO size?
|
||
|
if (((unsigned int) (AmiGetWordFromLe(&pFrame->m_Data.m_Pres.m_le_wSize) + 24)
|
||
|
> FrameInfo.m_uiFrameSize)
|
||
|
#if (((EPL_MODULE_INTEGRATION) & (EPL_MODULE_NMT_MN)) != 0)
|
||
|
|| (AmiGetWordFromLe(&pFrame->m_Data.m_Pres.m_le_wSize) > pIntNodeInfo->m_wPresPayloadLimit)
|
||
|
#endif
|
||
|
)
|
||
|
{ // format error
|
||
|
tEplErrorHandlerkEvent DllEvent;
|
||
|
|
||
|
DllEvent.m_ulDllErrorEvents = EPL_DLL_ERR_INVALID_FORMAT;
|
||
|
DllEvent.m_uiNodeId = uiNodeId;
|
||
|
DllEvent.m_NmtState = NmtState;
|
||
|
Event.m_EventSink = kEplEventSinkErrk;
|
||
|
Event.m_EventType = kEplEventTypeDllError;
|
||
|
Event.m_NetTime = FrameInfo.m_NetTime;
|
||
|
Event.m_uiSize = sizeof (DllEvent);
|
||
|
Event.m_pArg = &DllEvent;
|
||
|
Ret = EplEventkPost(&Event);
|
||
|
break;
|
||
|
}
|
||
|
if ((NmtState != kEplNmtCsOperational)
|
||
|
&& (NmtState != kEplNmtMsOperational))
|
||
|
{
|
||
|
// reset RD flag and all other flags, but that does not matter, because they were processed above
|
||
|
AmiSetByteToLe(&pFrame->m_Data.m_Pres.m_le_bFlag1, 0);
|
||
|
}
|
||
|
Ret = EplPdokCbPdoReceived(&FrameInfo);
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
case kEplMsgTypeSoc:
|
||
|
{
|
||
|
// SoC frame
|
||
|
NmtEvent = kEplNmtEventDllCeSoc;
|
||
|
|
||
|
if (NmtState >= kEplNmtMsNotActive)
|
||
|
{ // MN is active -> wrong msg type
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
#if EPL_DLL_PRES_READY_AFTER_SOC != FALSE
|
||
|
// post PRes to transmit FIFO of the ethernet controller, but don't start
|
||
|
// transmission over bus
|
||
|
pTxBuffer = &EplDllkInstance_g.m_pTxBuffer[EPL_DLLK_TXFRAME_PRES];
|
||
|
// Does PRes exist?
|
||
|
if (pTxBuffer->m_pbBuffer != NULL)
|
||
|
{ // PRes does exist
|
||
|
pTxFrame = (tEplFrame *) pTxBuffer->m_pbBuffer;
|
||
|
// update frame (NMT state, RD, RS, PR, MS, EN flags)
|
||
|
if (NmtState < kEplNmtCsPreOperational2)
|
||
|
{ // NMT state is not PreOp2, ReadyToOp or Op
|
||
|
// fake NMT state PreOp2, because PRes will be sent only in PreOp2 or greater
|
||
|
NmtState = kEplNmtCsPreOperational2;
|
||
|
}
|
||
|
AmiSetByteToLe(&pTxFrame->m_Data.m_Pres.m_le_bNmtStatus, (BYTE) NmtState);
|
||
|
AmiSetByteToLe(&pTxFrame->m_Data.m_Pres.m_le_bFlag2, EplDllkInstance_g.m_bFlag2);
|
||
|
if (NmtState != kEplNmtCsOperational)
|
||
|
{ // mark PDO as invalid in NMT state Op
|
||
|
// $$$ reset only RD flag; set other flags appropriately
|
||
|
AmiSetByteToLe(&pTxFrame->m_Data.m_Pres.m_le_bFlag1, 0);
|
||
|
}
|
||
|
// $$$ make function that updates Pres, StatusRes
|
||
|
// mark PRes frame as ready for transmission
|
||
|
Ret = EdrvTxMsgReady(pTxBuffer);
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
if (NmtState >= kEplNmtCsPreOperational2)
|
||
|
{ // SoC frames only in PreOp2, ReadyToOp and Op
|
||
|
// trigger synchronous task
|
||
|
Event.m_EventSink = kEplEventSinkSync;
|
||
|
Event.m_EventType = kEplEventTypeSync;
|
||
|
Event.m_uiSize = 0;
|
||
|
Ret = EplEventkPost(&Event);
|
||
|
|
||
|
// update cycle counter
|
||
|
if (EplDllkInstance_g.m_DllConfigParam.m_uiMultiplCycleCnt > 0)
|
||
|
{ // multiplexed cycle active
|
||
|
EplDllkInstance_g.m_uiCycleCount = (EplDllkInstance_g.m_uiCycleCount + 1) % EplDllkInstance_g.m_DllConfigParam.m_uiMultiplCycleCnt;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// reprogram timer
|
||
|
#if EPL_TIMER_USE_HIGHRES != FALSE
|
||
|
if (EplDllkInstance_g.m_ullFrameTimeout != 0)
|
||
|
{
|
||
|
Ret = EplTimerHighReskModifyTimerNs(&EplDllkInstance_g.m_TimerHdlCycle, EplDllkInstance_g.m_ullFrameTimeout, EplDllkCbCnTimer, 0L, FALSE);
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
case kEplMsgTypeSoa:
|
||
|
{
|
||
|
// SoA frame
|
||
|
NmtEvent = kEplNmtEventDllCeSoa;
|
||
|
|
||
|
if (NmtState >= kEplNmtMsNotActive)
|
||
|
{ // MN is active -> wrong msg type
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
pTxFrame = NULL;
|
||
|
|
||
|
if ((NmtState & EPL_NMT_SUPERSTATE_MASK) != EPL_NMT_CS_EPLMODE)
|
||
|
{ // do not respond, if NMT state is < PreOp1 (i.e. not EPL_MODE)
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
// check TargetNodeId
|
||
|
uiNodeId = AmiGetByteFromLe(&pFrame->m_Data.m_Soa.m_le_bReqServiceTarget);
|
||
|
if (uiNodeId == EplDllkInstance_g.m_DllConfigParam.m_uiNodeId)
|
||
|
{ // local node is the target of the current request
|
||
|
|
||
|
// check ServiceId
|
||
|
ReqServiceId = (tEplDllReqServiceId) AmiGetByteFromLe(&pFrame->m_Data.m_Soa.m_le_bReqServiceId);
|
||
|
if (ReqServiceId == kEplDllReqServiceStatus)
|
||
|
{ // StatusRequest
|
||
|
if (EplDllkInstance_g.m_pTxBuffer[EPL_DLLK_TXFRAME_STATUSRES].m_pbBuffer != NULL)
|
||
|
{ // StatusRes does exist
|
||
|
|
||
|
pTxFrame = (tEplFrame *) EplDllkInstance_g.m_pTxBuffer[EPL_DLLK_TXFRAME_STATUSRES].m_pbBuffer;
|
||
|
// update StatusRes frame (NMT state, EN, EC, RS, PR flags)
|
||
|
AmiSetByteToLe(&pTxFrame->m_Data.m_Asnd.m_Payload.m_StatusResponse.m_le_bNmtStatus, (BYTE) NmtState);
|
||
|
AmiSetByteToLe(&pTxFrame->m_Data.m_Asnd.m_Payload.m_StatusResponse.m_le_bFlag1, EplDllkInstance_g.m_bFlag1);
|
||
|
AmiSetByteToLe(&pTxFrame->m_Data.m_Asnd.m_Payload.m_StatusResponse.m_le_bFlag2, EplDllkInstance_g.m_bFlag2);
|
||
|
// send StatusRes
|
||
|
Ret = EdrvSendTxMsg(&EplDllkInstance_g.m_pTxBuffer[EPL_DLLK_TXFRAME_STATUSRES]);
|
||
|
if (Ret != kEplSuccessful)
|
||
|
{
|
||
|
goto Exit;
|
||
|
}
|
||
|
TGT_DBG_SIGNAL_TRACE_POINT(8);
|
||
|
|
||
|
// update error signaling
|
||
|
bFlag1 = AmiGetByteFromLe(&pFrame->m_Data.m_Soa.m_le_bFlag1);
|
||
|
if (((bFlag1 ^ EplDllkInstance_g.m_bMnFlag1) & EPL_FRAME_FLAG1_ER) != 0)
|
||
|
{ // exception reset flag was changed by MN
|
||
|
// assume same state for EC in next cycle (clear all other bits)
|
||
|
if ((bFlag1 & EPL_FRAME_FLAG1_ER) != 0)
|
||
|
{
|
||
|
// set EC and reset rest
|
||
|
EplDllkInstance_g.m_bFlag1 = EPL_FRAME_FLAG1_EC;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// reset complete flag 1 (including EC and EN)
|
||
|
EplDllkInstance_g.m_bFlag1 = 0;
|
||
|
}
|
||
|
}
|
||
|
// save flag 1 from MN for Status request response cycle
|
||
|
EplDllkInstance_g.m_bMnFlag1 = bFlag1;
|
||
|
}
|
||
|
}
|
||
|
else if (ReqServiceId == kEplDllReqServiceIdent)
|
||
|
{ // IdentRequest
|
||
|
if (EplDllkInstance_g.m_pTxBuffer[EPL_DLLK_TXFRAME_IDENTRES].m_pbBuffer != NULL)
|
||
|
{ // IdentRes does exist
|
||
|
pTxFrame = (tEplFrame *) EplDllkInstance_g.m_pTxBuffer[EPL_DLLK_TXFRAME_IDENTRES].m_pbBuffer;
|
||
|
// update IdentRes frame (NMT state, RS, PR flags)
|
||
|
AmiSetByteToLe(&pTxFrame->m_Data.m_Asnd.m_Payload.m_IdentResponse.m_le_bNmtStatus, (BYTE) NmtState);
|
||
|
AmiSetByteToLe(&pTxFrame->m_Data.m_Asnd.m_Payload.m_IdentResponse.m_le_bFlag2, EplDllkInstance_g.m_bFlag2);
|
||
|
// send IdentRes
|
||
|
Ret = EdrvSendTxMsg(&EplDllkInstance_g.m_pTxBuffer[EPL_DLLK_TXFRAME_IDENTRES]);
|
||
|
if (Ret != kEplSuccessful)
|
||
|
{
|
||
|
goto Exit;
|
||
|
}
|
||
|
TGT_DBG_SIGNAL_TRACE_POINT(7);
|
||
|
}
|
||
|
}
|
||
|
else if (ReqServiceId == kEplDllReqServiceNmtRequest)
|
||
|
{ // NmtRequest
|
||
|
if (EplDllkInstance_g.m_pTxBuffer[EPL_DLLK_TXFRAME_NMTREQ].m_pbBuffer != NULL)
|
||
|
{ // NmtRequest does exist
|
||
|
// check if frame is not empty and not being filled
|
||
|
if (EplDllkInstance_g.m_pTxBuffer[EPL_DLLK_TXFRAME_NMTREQ].m_uiTxMsgLen > EPL_DLLK_BUFLEN_FILLING)
|
||
|
{
|
||
|
/*if (EplDllkInstance_g.m_pTxBuffer[EPL_DLLK_TXFRAME_NMTREQ].m_uiTxMsgLen < EPL_DLLK_BUFLEN_MIN)
|
||
|
{ // pad frame
|
||
|
EplDllkInstance_g.m_pTxBuffer[EPL_DLLK_TXFRAME_NMTREQ].m_uiTxMsgLen = EPL_DLLK_BUFLEN_MIN;
|
||
|
}*/
|
||
|
// memorize transmission
|
||
|
pTxFrame = (tEplFrame*)1;
|
||
|
// send NmtRequest
|
||
|
Ret = EdrvSendTxMsg(&EplDllkInstance_g.m_pTxBuffer[EPL_DLLK_TXFRAME_NMTREQ]);
|
||
|
if (Ret != kEplSuccessful)
|
||
|
{
|
||
|
goto Exit;
|
||
|
}
|
||
|
|
||
|
}
|
||
|
}
|
||
|
|
||
|
}
|
||
|
else if (ReqServiceId == kEplDllReqServiceUnspecified)
|
||
|
{ // unspecified invite
|
||
|
if (EplDllkInstance_g.m_pTxBuffer[EPL_DLLK_TXFRAME_NONEPL].m_pbBuffer != NULL)
|
||
|
{ // non-EPL frame does exist
|
||
|
// check if frame is not empty and not being filled
|
||
|
if (EplDllkInstance_g.m_pTxBuffer[EPL_DLLK_TXFRAME_NONEPL].m_uiTxMsgLen > EPL_DLLK_BUFLEN_FILLING)
|
||
|
{
|
||
|
/*if (EplDllkInstance_g.m_pTxBuffer[EPL_DLLK_TXFRAME_NMTREQ].m_uiTxMsgLen < EPL_DLLK_BUFLEN_MIN)
|
||
|
{ // pad frame
|
||
|
EplDllkInstance_g.m_pTxBuffer[EPL_DLLK_TXFRAME_NMTREQ].m_uiTxMsgLen = EPL_DLLK_BUFLEN_MIN;
|
||
|
}*/
|
||
|
// memorize transmission
|
||
|
pTxFrame = (tEplFrame*)1;
|
||
|
// send non-EPL frame
|
||
|
Ret = EdrvSendTxMsg(&EplDllkInstance_g.m_pTxBuffer[EPL_DLLK_TXFRAME_NONEPL]);
|
||
|
if (Ret != kEplSuccessful)
|
||
|
{
|
||
|
goto Exit;
|
||
|
}
|
||
|
|
||
|
}
|
||
|
}
|
||
|
|
||
|
}
|
||
|
else if (ReqServiceId == kEplDllReqServiceNo)
|
||
|
{ // no async service requested -> do nothing
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#if EPL_DLL_PRES_READY_AFTER_SOA != FALSE
|
||
|
if (pTxFrame == NULL)
|
||
|
{ // signal process function readiness of PRes frame
|
||
|
Event.m_EventSink = kEplEventSinkDllk;
|
||
|
Event.m_EventType = kEplEventTypeDllkPresReady;
|
||
|
Event.m_uiSize = 0;
|
||
|
Event.m_pArg = NULL;
|
||
|
Ret = EplEventkPost(&Event);
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
// inform PDO module
|
||
|
#if (((EPL_MODULE_INTEGRATION) & (EPL_MODULE_PDOK)) != 0)
|
||
|
// Ret = EplPdokCbSoa(&FrameInfo);
|
||
|
#endif
|
||
|
|
||
|
// $$$ put SrcNodeId, NMT state and NetTime as HeartbeatEvent into eventqueue
|
||
|
|
||
|
// $$$ inform emergency protocol handling about flags
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
case kEplMsgTypeAsnd:
|
||
|
{
|
||
|
// ASnd frame
|
||
|
NmtEvent = kEplNmtEventDllCeAsnd;
|
||
|
|
||
|
// ASnd service registered?
|
||
|
uiAsndServiceId = (unsigned int) AmiGetByteFromLe(&pFrame->m_Data.m_Asnd.m_le_bServiceId);
|
||
|
|
||
|
#if (((EPL_MODULE_INTEGRATION) & (EPL_MODULE_NMT_MN)) != 0)
|
||
|
if ((EplDllkInstance_g.m_DllState >= kEplDllMsNonCyclic)
|
||
|
&& ((((tEplDllAsndServiceId) uiAsndServiceId) == kEplDllAsndStatusResponse)
|
||
|
|| (((tEplDllAsndServiceId) uiAsndServiceId) == kEplDllAsndIdentResponse)))
|
||
|
{ // StatusRes or IdentRes received
|
||
|
uiNodeId = AmiGetByteFromLe(&pFrame->m_le_bSrcNodeId);
|
||
|
if ((EplDllkInstance_g.m_LastReqServiceId == ((tEplDllReqServiceId) uiAsndServiceId))
|
||
|
&& (uiNodeId == EplDllkInstance_g.m_uiLastTargetNodeId))
|
||
|
{ // mark request as responded
|
||
|
EplDllkInstance_g.m_LastReqServiceId = kEplDllReqServiceNo;
|
||
|
}
|
||
|
if (((tEplDllAsndServiceId) uiAsndServiceId) == kEplDllAsndIdentResponse)
|
||
|
{ // memorize MAC address of CN for PReq
|
||
|
tEplDllkNodeInfo* pIntNodeInfo;
|
||
|
|
||
|
pIntNodeInfo = EplDllkGetNodeInfo(uiNodeId);
|
||
|
if (pIntNodeInfo == NULL)
|
||
|
{ // no node info structure available
|
||
|
Ret = kEplDllNoNodeInfo;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
EPL_MEMCPY(pIntNodeInfo->m_be_abMacAddr, pFrame->m_be_abSrcMac, 6);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// forward Flag2 to asynchronous scheduler
|
||
|
bFlag1 = AmiGetByteFromLe(&pFrame->m_Data.m_Asnd.m_Payload.m_StatusResponse.m_le_bFlag2);
|
||
|
Ret = EplDllkCalAsyncSetPendingRequests(uiNodeId,
|
||
|
((tEplDllAsyncReqPriority) ((bFlag1 & EPL_FRAME_FLAG2_PR) >> EPL_FRAME_FLAG2_PR_SHIFT)),
|
||
|
(bFlag1 & EPL_FRAME_FLAG2_RS));
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
if (uiAsndServiceId < EPL_DLL_MAX_ASND_SERVICE_ID)
|
||
|
{ // ASnd service ID is valid
|
||
|
if (EplDllkInstance_g.m_aAsndFilter[uiAsndServiceId] == kEplDllAsndFilterAny)
|
||
|
{ // ASnd service ID is registered
|
||
|
// forward frame via async receive FIFO to userspace
|
||
|
Ret = EplDllkCalAsyncFrameReceived(&FrameInfo);
|
||
|
}
|
||
|
else if (EplDllkInstance_g.m_aAsndFilter[uiAsndServiceId] == kEplDllAsndFilterLocal)
|
||
|
{ // ASnd service ID is registered, but only local node ID or broadcasts
|
||
|
// shall be forwarded
|
||
|
uiNodeId = AmiGetByteFromLe(&pFrame->m_le_bDstNodeId);
|
||
|
if ((uiNodeId == EplDllkInstance_g.m_DllConfigParam.m_uiNodeId)
|
||
|
|| (uiNodeId == EPL_C_ADR_BROADCAST))
|
||
|
{ // ASnd frame is intended for us
|
||
|
// forward frame via async receive FIFO to userspace
|
||
|
Ret = EplDllkCalAsyncFrameReceived(&FrameInfo);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
default:
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (NmtEvent != kEplNmtEventNoEvent)
|
||
|
{ // event for DLL and NMT state machine generated
|
||
|
Ret = EplDllkChangeState(NmtEvent, NmtState);
|
||
|
if (Ret != kEplSuccessful)
|
||
|
{
|
||
|
goto Exit;
|
||
|
}
|
||
|
|
||
|
if ((NmtEvent != kEplNmtEventDllCeAsnd)
|
||
|
&& ((NmtState <= kEplNmtCsPreOperational1) || (NmtEvent != kEplNmtEventDllCePres)))
|
||
|
{ // NMT state machine is not interested in ASnd frames and PRes frames when not CsNotActive or CsPreOp1
|
||
|
// inform NMT module
|
||
|
Event.m_EventSink = kEplEventSinkNmtk;
|
||
|
Event.m_EventType = kEplEventTypeNmtEvent;
|
||
|
Event.m_uiSize = sizeof (NmtEvent);
|
||
|
Event.m_pArg = &NmtEvent;
|
||
|
Ret = EplEventkPost(&Event);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
Exit:
|
||
|
if (Ret != kEplSuccessful)
|
||
|
{
|
||
|
DWORD dwArg;
|
||
|
|
||
|
BENCHMARK_MOD_02_TOGGLE(9);
|
||
|
|
||
|
dwArg = EplDllkInstance_g.m_DllState | (NmtEvent << 8);
|
||
|
|
||
|
// Error event for API layer
|
||
|
Ret = EplEventkPostError(kEplEventSourceDllk,
|
||
|
Ret,
|
||
|
sizeof(dwArg),
|
||
|
&dwArg);
|
||
|
}
|
||
|
BENCHMARK_MOD_02_RESET(3);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
//---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: EplDllkCbFrameTransmitted()
|
||
|
//
|
||
|
// Description: called from EdrvInterruptHandler().
|
||
|
// It signals
|
||
|
//
|
||
|
// Parameters: pRxBuffer_p = receive buffer structure
|
||
|
//
|
||
|
// Returns: (none)
|
||
|
//
|
||
|
//
|
||
|
// State:
|
||
|
//
|
||
|
//---------------------------------------------------------------------------
|
||
|
|
||
|
static void EplDllkCbFrameTransmitted(tEdrvTxBuffer * pTxBuffer_p)
|
||
|
{
|
||
|
tEplKernel Ret = kEplSuccessful;
|
||
|
tEplEvent Event;
|
||
|
tEplDllAsyncReqPriority Priority;
|
||
|
tEplNmtState NmtState;
|
||
|
|
||
|
#if (((EPL_MODULE_INTEGRATION) & (EPL_MODULE_PDOK)) != 0) \
|
||
|
&& (EPL_DLL_PRES_READY_AFTER_SOC == FALSE)
|
||
|
tEplFrameInfo FrameInfo;
|
||
|
#endif
|
||
|
|
||
|
NmtState = EplNmtkGetNmtState();
|
||
|
|
||
|
if (NmtState <= kEplNmtGsResetConfiguration)
|
||
|
{
|
||
|
goto Exit;
|
||
|
}
|
||
|
|
||
|
if ((pTxBuffer_p - EplDllkInstance_g.m_pTxBuffer) == EPL_DLLK_TXFRAME_NMTREQ)
|
||
|
{ // frame from NMT request FIFO sent
|
||
|
// mark Tx-buffer as empty
|
||
|
pTxBuffer_p->m_uiTxMsgLen = EPL_DLLK_BUFLEN_EMPTY;
|
||
|
|
||
|
// post event to DLL
|
||
|
Priority = kEplDllAsyncReqPrioNmt;
|
||
|
Event.m_EventSink = kEplEventSinkDllk;
|
||
|
Event.m_EventType = kEplEventTypeDllkFillTx;
|
||
|
EPL_MEMSET(&Event.m_NetTime, 0x00, sizeof(Event.m_NetTime));
|
||
|
Event.m_pArg = &Priority;
|
||
|
Event.m_uiSize = sizeof(Priority);
|
||
|
Ret = EplEventkPost(&Event);
|
||
|
}
|
||
|
else if ((pTxBuffer_p - EplDllkInstance_g.m_pTxBuffer) == EPL_DLLK_TXFRAME_NONEPL)
|
||
|
{ // frame from generic priority FIFO sent
|
||
|
// mark Tx-buffer as empty
|
||
|
pTxBuffer_p->m_uiTxMsgLen = EPL_DLLK_BUFLEN_EMPTY;
|
||
|
|
||
|
// post event to DLL
|
||
|
Priority = kEplDllAsyncReqPrioGeneric;
|
||
|
Event.m_EventSink = kEplEventSinkDllk;
|
||
|
Event.m_EventType = kEplEventTypeDllkFillTx;
|
||
|
EPL_MEMSET(&Event.m_NetTime, 0x00, sizeof(Event.m_NetTime));
|
||
|
Event.m_pArg = &Priority;
|
||
|
Event.m_uiSize = sizeof(Priority);
|
||
|
Ret = EplEventkPost(&Event);
|
||
|
}
|
||
|
#if ((((EPL_MODULE_INTEGRATION) & (EPL_MODULE_PDOK)) != 0) \
|
||
|
&& (EPL_DLL_PRES_READY_AFTER_SOC == FALSE)) \
|
||
|
|| (((EPL_MODULE_INTEGRATION) & (EPL_MODULE_NMT_MN)) != 0)
|
||
|
else if ((pTxBuffer_p->m_EplMsgType == kEplMsgTypePreq)
|
||
|
|| (pTxBuffer_p->m_EplMsgType == kEplMsgTypePres))
|
||
|
{ // PRes resp. PReq frame sent
|
||
|
|
||
|
#if ((((EPL_MODULE_INTEGRATION) & (EPL_MODULE_PDOK)) != 0) \
|
||
|
&& (EPL_DLL_PRES_READY_AFTER_SOC == FALSE))
|
||
|
{
|
||
|
// inform PDO module
|
||
|
FrameInfo.m_pFrame = (tEplFrame *) pTxBuffer_p->m_pbBuffer;
|
||
|
FrameInfo.m_uiFrameSize = pTxBuffer_p->m_uiMaxBufferLen;
|
||
|
Ret = EplPdokCbPdoTransmitted(&FrameInfo);
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
#if (((EPL_MODULE_INTEGRATION) & (EPL_MODULE_NMT_MN)) != 0)
|
||
|
{
|
||
|
// if own Pres on MN, trigger SoA
|
||
|
if ((NmtState >= kEplNmtMsPreOperational2)
|
||
|
&& (pTxBuffer_p == &EplDllkInstance_g.m_pTxBuffer[EPL_DLLK_TXFRAME_PRES]))
|
||
|
{
|
||
|
Ret = EplDllkChangeState(kEplNmtEventDllMeSoaTrig, NmtState);
|
||
|
}
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
#if EPL_DLL_PRES_READY_AFTER_SOA != FALSE
|
||
|
goto Exit;
|
||
|
#endif
|
||
|
}
|
||
|
#endif
|
||
|
#if (((EPL_MODULE_INTEGRATION) & (EPL_MODULE_NMT_MN)) != 0)
|
||
|
else if (pTxBuffer_p->m_EplMsgType == kEplMsgTypeSoa)
|
||
|
{ // SoA frame sent
|
||
|
tEplNmtEvent NmtEvent = kEplNmtEventDllMeSoaSent;
|
||
|
|
||
|
// check if we are invited
|
||
|
if (EplDllkInstance_g.m_uiLastTargetNodeId == EplDllkInstance_g.m_DllConfigParam.m_uiNodeId)
|
||
|
{
|
||
|
tEplFrame *pTxFrame;
|
||
|
|
||
|
if (EplDllkInstance_g.m_LastReqServiceId == kEplDllReqServiceStatus)
|
||
|
{ // StatusRequest
|
||
|
if (EplDllkInstance_g.m_pTxBuffer[EPL_DLLK_TXFRAME_STATUSRES].m_pbBuffer != NULL)
|
||
|
{ // StatusRes does exist
|
||
|
|
||
|
pTxFrame = (tEplFrame *) EplDllkInstance_g.m_pTxBuffer[EPL_DLLK_TXFRAME_STATUSRES].m_pbBuffer;
|
||
|
// update StatusRes frame (NMT state, EN, EC, RS, PR flags)
|
||
|
AmiSetByteToLe(&pTxFrame->m_Data.m_Asnd.m_Payload.m_StatusResponse.m_le_bNmtStatus, (BYTE) NmtState);
|
||
|
AmiSetByteToLe(&pTxFrame->m_Data.m_Asnd.m_Payload.m_StatusResponse.m_le_bFlag1, EplDllkInstance_g.m_bFlag1);
|
||
|
AmiSetByteToLe(&pTxFrame->m_Data.m_Asnd.m_Payload.m_StatusResponse.m_le_bFlag2, EplDllkInstance_g.m_bFlag2);
|
||
|
// send StatusRes
|
||
|
Ret = EdrvSendTxMsg(&EplDllkInstance_g.m_pTxBuffer[EPL_DLLK_TXFRAME_STATUSRES]);
|
||
|
if (Ret != kEplSuccessful)
|
||
|
{
|
||
|
goto Exit;
|
||
|
}
|
||
|
TGT_DBG_SIGNAL_TRACE_POINT(8);
|
||
|
|
||
|
}
|
||
|
}
|
||
|
else if (EplDllkInstance_g.m_LastReqServiceId == kEplDllReqServiceIdent)
|
||
|
{ // IdentRequest
|
||
|
if (EplDllkInstance_g.m_pTxBuffer[EPL_DLLK_TXFRAME_IDENTRES].m_pbBuffer != NULL)
|
||
|
{ // IdentRes does exist
|
||
|
pTxFrame = (tEplFrame *) EplDllkInstance_g.m_pTxBuffer[EPL_DLLK_TXFRAME_IDENTRES].m_pbBuffer;
|
||
|
// update IdentRes frame (NMT state, RS, PR flags)
|
||
|
AmiSetByteToLe(&pTxFrame->m_Data.m_Asnd.m_Payload.m_IdentResponse.m_le_bNmtStatus, (BYTE) NmtState);
|
||
|
AmiSetByteToLe(&pTxFrame->m_Data.m_Asnd.m_Payload.m_IdentResponse.m_le_bFlag2, EplDllkInstance_g.m_bFlag2);
|
||
|
// send IdentRes
|
||
|
Ret = EdrvSendTxMsg(&EplDllkInstance_g.m_pTxBuffer[EPL_DLLK_TXFRAME_IDENTRES]);
|
||
|
if (Ret != kEplSuccessful)
|
||
|
{
|
||
|
goto Exit;
|
||
|
}
|
||
|
TGT_DBG_SIGNAL_TRACE_POINT(7);
|
||
|
}
|
||
|
}
|
||
|
else if (EplDllkInstance_g.m_LastReqServiceId == kEplDllReqServiceNmtRequest)
|
||
|
{ // NmtRequest
|
||
|
if (EplDllkInstance_g.m_pTxBuffer[EPL_DLLK_TXFRAME_NMTREQ].m_pbBuffer != NULL)
|
||
|
{ // NmtRequest does exist
|
||
|
// check if frame is not empty and not being filled
|
||
|
if (EplDllkInstance_g.m_pTxBuffer[EPL_DLLK_TXFRAME_NMTREQ].m_uiTxMsgLen > EPL_DLLK_BUFLEN_FILLING)
|
||
|
{
|
||
|
// check if this frame is a NMT command,
|
||
|
// then forward this frame back to NmtMnu module,
|
||
|
// because it needs the time, when this frame is
|
||
|
// actually sent, to start the timer for monitoring
|
||
|
// the NMT state change.
|
||
|
|
||
|
pTxFrame = (tEplFrame *) EplDllkInstance_g.m_pTxBuffer[EPL_DLLK_TXFRAME_NMTREQ].m_pbBuffer;
|
||
|
if ((AmiGetByteFromLe(&pTxFrame->m_le_bMessageType)
|
||
|
== (BYTE) kEplMsgTypeAsnd)
|
||
|
&& (AmiGetByteFromLe(&pTxFrame->m_Data.m_Asnd.m_le_bServiceId)
|
||
|
== (BYTE) kEplDllAsndNmtCommand))
|
||
|
{ // post event directly to NmtMnu module
|
||
|
Event.m_EventSink = kEplEventSinkNmtMnu;
|
||
|
Event.m_EventType = kEplEventTypeNmtMnuNmtCmdSent;
|
||
|
Event.m_uiSize = EplDllkInstance_g.m_pTxBuffer[EPL_DLLK_TXFRAME_NMTREQ].m_uiTxMsgLen;
|
||
|
Event.m_pArg = pTxFrame;
|
||
|
Ret = EplEventkPost(&Event);
|
||
|
|
||
|
}
|
||
|
|
||
|
// send NmtRequest
|
||
|
Ret = EdrvSendTxMsg(&EplDllkInstance_g.m_pTxBuffer[EPL_DLLK_TXFRAME_NMTREQ]);
|
||
|
if (Ret != kEplSuccessful)
|
||
|
{
|
||
|
goto Exit;
|
||
|
}
|
||
|
|
||
|
}
|
||
|
}
|
||
|
|
||
|
}
|
||
|
else if (EplDllkInstance_g.m_LastReqServiceId == kEplDllReqServiceUnspecified)
|
||
|
{ // unspecified invite
|
||
|
if (EplDllkInstance_g.m_pTxBuffer[EPL_DLLK_TXFRAME_NONEPL].m_pbBuffer != NULL)
|
||
|
{ // non-EPL frame does exist
|
||
|
// check if frame is not empty and not being filled
|
||
|
if (EplDllkInstance_g.m_pTxBuffer[EPL_DLLK_TXFRAME_NONEPL].m_uiTxMsgLen > EPL_DLLK_BUFLEN_FILLING)
|
||
|
{
|
||
|
// send non-EPL frame
|
||
|
Ret = EdrvSendTxMsg(&EplDllkInstance_g.m_pTxBuffer[EPL_DLLK_TXFRAME_NONEPL]);
|
||
|
if (Ret != kEplSuccessful)
|
||
|
{
|
||
|
goto Exit;
|
||
|
}
|
||
|
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
// ASnd frame was sent, remove the request
|
||
|
EplDllkInstance_g.m_LastReqServiceId = kEplDllReqServiceNo;
|
||
|
}
|
||
|
|
||
|
// forward event to ErrorHandler and PDO module
|
||
|
Event.m_EventSink = kEplEventSinkNmtk;
|
||
|
Event.m_EventType = kEplEventTypeNmtEvent;
|
||
|
Event.m_uiSize = sizeof (NmtEvent);
|
||
|
Event.m_pArg = &NmtEvent;
|
||
|
Ret = EplEventkPost(&Event);
|
||
|
if (Ret != kEplSuccessful)
|
||
|
{
|
||
|
goto Exit;
|
||
|
}
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
#if EPL_DLL_PRES_READY_AFTER_SOA != FALSE
|
||
|
else
|
||
|
{ // d.k.: Why that else? on CN it is entered on IdentRes and StatusRes
|
||
|
goto Exit;
|
||
|
}
|
||
|
|
||
|
// signal process function readiness of PRes frame
|
||
|
Event.m_EventSink = kEplEventSinkDllk;
|
||
|
Event.m_EventType = kEplEventTypeDllkPresReady;
|
||
|
Event.m_uiSize = 0;
|
||
|
Event.m_pArg = NULL;
|
||
|
Ret = EplEventkPost(&Event);
|
||
|
|
||
|
#endif
|
||
|
|
||
|
Exit:
|
||
|
if (Ret != kEplSuccessful)
|
||
|
{
|
||
|
DWORD dwArg;
|
||
|
|
||
|
BENCHMARK_MOD_02_TOGGLE(9);
|
||
|
|
||
|
dwArg = EplDllkInstance_g.m_DllState | (pTxBuffer_p->m_EplMsgType << 16);
|
||
|
|
||
|
// Error event for API layer
|
||
|
Ret = EplEventkPostError(kEplEventSourceDllk,
|
||
|
Ret,
|
||
|
sizeof(dwArg),
|
||
|
&dwArg);
|
||
|
}
|
||
|
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
//---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: EplDllkCheckFrame()
|
||
|
//
|
||
|
// Description: check frame and set missing information
|
||
|
//
|
||
|
// Parameters: pFrame_p = ethernet frame
|
||
|
// uiFrameSize_p = size of frame
|
||
|
//
|
||
|
// Returns: tEplKernel = error code
|
||
|
//
|
||
|
//
|
||
|
// State:
|
||
|
//
|
||
|
//---------------------------------------------------------------------------
|
||
|
|
||
|
static tEplKernel EplDllkCheckFrame(tEplFrame * pFrame_p, unsigned int uiFrameSize_p)
|
||
|
{
|
||
|
tEplMsgType MsgType;
|
||
|
WORD wEtherType;
|
||
|
|
||
|
// check frame
|
||
|
if (pFrame_p != NULL)
|
||
|
{
|
||
|
// check SrcMAC
|
||
|
if (AmiGetQword48FromBe(pFrame_p->m_be_abSrcMac) == 0)
|
||
|
{
|
||
|
// source MAC address
|
||
|
EPL_MEMCPY(&pFrame_p->m_be_abSrcMac[0], &EplDllkInstance_g.m_be_abSrcMac[0], 6);
|
||
|
}
|
||
|
|
||
|
// check ethertype
|
||
|
wEtherType = AmiGetWordFromBe(&pFrame_p->m_be_wEtherType);
|
||
|
if (wEtherType == 0)
|
||
|
{
|
||
|
// assume EPL frame
|
||
|
wEtherType = EPL_C_DLL_ETHERTYPE_EPL;
|
||
|
AmiSetWordToBe(&pFrame_p->m_be_wEtherType, wEtherType);
|
||
|
}
|
||
|
|
||
|
if (wEtherType == EPL_C_DLL_ETHERTYPE_EPL)
|
||
|
{
|
||
|
// source node ID
|
||
|
AmiSetByteToLe(&pFrame_p->m_le_bSrcNodeId, (BYTE) EplDllkInstance_g.m_DllConfigParam.m_uiNodeId);
|
||
|
|
||
|
// check message type
|
||
|
MsgType = AmiGetByteFromLe(&pFrame_p->m_le_bMessageType);
|
||
|
if (MsgType == 0)
|
||
|
{
|
||
|
MsgType = kEplMsgTypeAsnd;
|
||
|
AmiSetByteToLe(&pFrame_p->m_le_bMessageType, (BYTE) MsgType);
|
||
|
}
|
||
|
|
||
|
if (MsgType == kEplMsgTypeAsnd)
|
||
|
{
|
||
|
// destination MAC address
|
||
|
AmiSetQword48ToBe(&pFrame_p->m_be_abDstMac[0], EPL_C_DLL_MULTICAST_ASND);
|
||
|
}
|
||
|
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return kEplSuccessful;
|
||
|
}
|
||
|
|
||
|
//---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: EplDllkCbCnTimer()
|
||
|
//
|
||
|
// Description: called by timer module. It monitors the EPL cycle when it is a CN.
|
||
|
//
|
||
|
// Parameters: pEventArg_p = timer event argument
|
||
|
//
|
||
|
// Returns: tEplKernel = error code
|
||
|
//
|
||
|
//
|
||
|
// State:
|
||
|
//
|
||
|
//---------------------------------------------------------------------------
|
||
|
|
||
|
#if EPL_TIMER_USE_HIGHRES != FALSE
|
||
|
static tEplKernel PUBLIC EplDllkCbCnTimer(tEplTimerEventArg* pEventArg_p)
|
||
|
{
|
||
|
tEplKernel Ret = kEplSuccessful;
|
||
|
tEplNmtState NmtState;
|
||
|
|
||
|
#if EPL_TIMER_USE_HIGHRES != FALSE
|
||
|
if (pEventArg_p->m_TimerHdl != EplDllkInstance_g.m_TimerHdlCycle)
|
||
|
{ // zombie callback
|
||
|
// just exit
|
||
|
goto Exit;
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
NmtState = EplNmtkGetNmtState();
|
||
|
|
||
|
if (NmtState <= kEplNmtGsResetConfiguration)
|
||
|
{
|
||
|
goto Exit;
|
||
|
}
|
||
|
|
||
|
Ret = EplDllkChangeState(kEplNmtEventDllCeFrameTimeout, NmtState);
|
||
|
if (Ret != kEplSuccessful)
|
||
|
{
|
||
|
goto Exit;
|
||
|
}
|
||
|
|
||
|
// 2008/10/15 d.k. reprogramming of timer not necessary,
|
||
|
// because it will be programmed, when SoC is received.
|
||
|
/*
|
||
|
// reprogram timer
|
||
|
#if EPL_TIMER_USE_HIGHRES != FALSE
|
||
|
if ((NmtState > kEplNmtCsPreOperational1)
|
||
|
&& (EplDllkInstance_g.m_ullFrameTimeout != 0))
|
||
|
{
|
||
|
Ret = EplTimerHighReskModifyTimerNs(&EplDllkInstance_g.m_TimerHdlCycle, EplDllkInstance_g.m_ullFrameTimeout, EplDllkCbCnTimer, 0L, FALSE);
|
||
|
}
|
||
|
#endif
|
||
|
*/
|
||
|
|
||
|
Exit:
|
||
|
if (Ret != kEplSuccessful)
|
||
|
{
|
||
|
DWORD dwArg;
|
||
|
|
||
|
BENCHMARK_MOD_02_TOGGLE(9);
|
||
|
|
||
|
dwArg = EplDllkInstance_g.m_DllState | (kEplNmtEventDllCeFrameTimeout << 8);
|
||
|
|
||
|
// Error event for API layer
|
||
|
Ret = EplEventkPostError(kEplEventSourceDllk,
|
||
|
Ret,
|
||
|
sizeof(dwArg),
|
||
|
&dwArg);
|
||
|
}
|
||
|
|
||
|
return Ret;
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
#if (((EPL_MODULE_INTEGRATION) & (EPL_MODULE_NMT_MN)) != 0)
|
||
|
|
||
|
//---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: EplDllkCbMnTimerCycle()
|
||
|
//
|
||
|
// Description: called by timer module. It triggers the SoC when it is a MN.
|
||
|
//
|
||
|
// Parameters: pEventArg_p = timer event argument
|
||
|
//
|
||
|
// Returns: tEplKernel = error code
|
||
|
//
|
||
|
//
|
||
|
// State:
|
||
|
//
|
||
|
//---------------------------------------------------------------------------
|
||
|
|
||
|
static tEplKernel PUBLIC EplDllkCbMnTimerCycle(tEplTimerEventArg* pEventArg_p)
|
||
|
{
|
||
|
tEplKernel Ret = kEplSuccessful;
|
||
|
tEplNmtState NmtState;
|
||
|
|
||
|
#if EPL_TIMER_USE_HIGHRES != FALSE
|
||
|
if (pEventArg_p->m_TimerHdl != EplDllkInstance_g.m_TimerHdlCycle)
|
||
|
{ // zombie callback
|
||
|
// just exit
|
||
|
goto Exit;
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
NmtState = EplNmtkGetNmtState();
|
||
|
|
||
|
if (NmtState <= kEplNmtGsResetConfiguration)
|
||
|
{
|
||
|
goto Exit;
|
||
|
}
|
||
|
|
||
|
Ret = EplDllkChangeState(kEplNmtEventDllMeSocTrig, NmtState);
|
||
|
|
||
|
Exit:
|
||
|
if (Ret != kEplSuccessful)
|
||
|
{
|
||
|
DWORD dwArg;
|
||
|
|
||
|
BENCHMARK_MOD_02_TOGGLE(9);
|
||
|
|
||
|
dwArg = EplDllkInstance_g.m_DllState | (kEplNmtEventDllMeSocTrig << 8);
|
||
|
|
||
|
// Error event for API layer
|
||
|
Ret = EplEventkPostError(kEplEventSourceDllk,
|
||
|
Ret,
|
||
|
sizeof(dwArg),
|
||
|
&dwArg);
|
||
|
}
|
||
|
|
||
|
return Ret;
|
||
|
}
|
||
|
|
||
|
|
||
|
//---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: EplDllkCbMnTimerResponse()
|
||
|
//
|
||
|
// Description: called by timer module. It monitors the PRes timeout.
|
||
|
//
|
||
|
// Parameters: pEventArg_p = timer event argument
|
||
|
//
|
||
|
// Returns: tEplKernel = error code
|
||
|
//
|
||
|
//
|
||
|
// State:
|
||
|
//
|
||
|
//---------------------------------------------------------------------------
|
||
|
|
||
|
static tEplKernel PUBLIC EplDllkCbMnTimerResponse(tEplTimerEventArg* pEventArg_p)
|
||
|
{
|
||
|
tEplKernel Ret = kEplSuccessful;
|
||
|
tEplNmtState NmtState;
|
||
|
|
||
|
#if EPL_TIMER_USE_HIGHRES != FALSE
|
||
|
if (pEventArg_p->m_TimerHdl != EplDllkInstance_g.m_TimerHdlResponse)
|
||
|
{ // zombie callback
|
||
|
// just exit
|
||
|
goto Exit;
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
NmtState = EplNmtkGetNmtState();
|
||
|
|
||
|
if (NmtState <= kEplNmtGsResetConfiguration)
|
||
|
{
|
||
|
goto Exit;
|
||
|
}
|
||
|
|
||
|
Ret = EplDllkChangeState(kEplNmtEventDllMePresTimeout, NmtState);
|
||
|
|
||
|
Exit:
|
||
|
if (Ret != kEplSuccessful)
|
||
|
{
|
||
|
DWORD dwArg;
|
||
|
|
||
|
BENCHMARK_MOD_02_TOGGLE(9);
|
||
|
|
||
|
dwArg = EplDllkInstance_g.m_DllState | (kEplNmtEventDllMePresTimeout << 8);
|
||
|
|
||
|
// Error event for API layer
|
||
|
Ret = EplEventkPostError(kEplEventSourceDllk,
|
||
|
Ret,
|
||
|
sizeof(dwArg),
|
||
|
&dwArg);
|
||
|
}
|
||
|
|
||
|
return Ret;
|
||
|
}
|
||
|
|
||
|
|
||
|
//---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: EplDllkGetNodeInfo()
|
||
|
//
|
||
|
// Description: returns node info structure of the specified node.
|
||
|
//
|
||
|
// Parameters: uiNodeId_p = node ID
|
||
|
//
|
||
|
// Returns: tEplDllkNodeInfo* = pointer to internal node info structure
|
||
|
//
|
||
|
//
|
||
|
// State:
|
||
|
//
|
||
|
//---------------------------------------------------------------------------
|
||
|
|
||
|
static tEplDllkNodeInfo* EplDllkGetNodeInfo(unsigned int uiNodeId_p)
|
||
|
{
|
||
|
// $$$ d.k.: use hash algorithm to retrieve the appropriate node info structure
|
||
|
// if size of array is less than 254.
|
||
|
uiNodeId_p--; // node ID starts at 1 but array at 0
|
||
|
if (uiNodeId_p >= tabentries (EplDllkInstance_g.m_aNodeInfo))
|
||
|
{
|
||
|
return NULL;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
return &EplDllkInstance_g.m_aNodeInfo[uiNodeId_p];
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
//---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: EplDllkMnSendSoa()
|
||
|
//
|
||
|
// Description: it updates and transmits the SoA.
|
||
|
//
|
||
|
// Parameters: NmtState_p = current NMT state
|
||
|
// pDllStateProposed_p = proposed DLL state
|
||
|
// fEnableInvitation_p = enable invitation for asynchronous phase
|
||
|
// it will be disabled for EPL_C_DLL_PREOP1_START_CYCLES SoAs
|
||
|
//
|
||
|
// Returns: tEplKernel = error code
|
||
|
//
|
||
|
//
|
||
|
// State:
|
||
|
//
|
||
|
//---------------------------------------------------------------------------
|
||
|
|
||
|
static tEplKernel EplDllkMnSendSoa(tEplNmtState NmtState_p,
|
||
|
tEplDllState* pDllStateProposed_p,
|
||
|
BOOL fEnableInvitation_p)
|
||
|
{
|
||
|
tEplKernel Ret = kEplSuccessful;
|
||
|
tEdrvTxBuffer *pTxBuffer = NULL;
|
||
|
tEplFrame *pTxFrame;
|
||
|
tEplDllkNodeInfo* pNodeInfo;
|
||
|
|
||
|
*pDllStateProposed_p = kEplDllMsNonCyclic;
|
||
|
|
||
|
pTxBuffer = &EplDllkInstance_g.m_pTxBuffer[EPL_DLLK_TXFRAME_SOA];
|
||
|
if (pTxBuffer->m_pbBuffer != NULL)
|
||
|
{ // SoA does exist
|
||
|
pTxFrame = (tEplFrame *) pTxBuffer->m_pbBuffer;
|
||
|
|
||
|
if (fEnableInvitation_p != FALSE)
|
||
|
{ // fetch target of asynchronous phase
|
||
|
if (EplDllkInstance_g.m_bFlag2 == 0)
|
||
|
{ // own queues are empty
|
||
|
EplDllkInstance_g.m_LastReqServiceId = kEplDllReqServiceNo;
|
||
|
}
|
||
|
else if (((tEplDllAsyncReqPriority) (EplDllkInstance_g.m_bFlag2 >> EPL_FRAME_FLAG2_PR_SHIFT)) == kEplDllAsyncReqPrioNmt)
|
||
|
{ // frames in own NMT request queue available
|
||
|
EplDllkInstance_g.m_LastReqServiceId = kEplDllReqServiceNmtRequest;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
EplDllkInstance_g.m_LastReqServiceId = kEplDllReqServiceUnspecified;
|
||
|
}
|
||
|
Ret = EplDllkCalAsyncGetSoaRequest(&EplDllkInstance_g.m_LastReqServiceId, &EplDllkInstance_g.m_uiLastTargetNodeId);
|
||
|
if (Ret != kEplSuccessful)
|
||
|
{
|
||
|
goto Exit;
|
||
|
}
|
||
|
if (EplDllkInstance_g.m_LastReqServiceId != kEplDllReqServiceNo)
|
||
|
{ // asynchronous phase will be assigned to one node
|
||
|
if (EplDllkInstance_g.m_uiLastTargetNodeId == EPL_C_ADR_INVALID)
|
||
|
{ // exchange invalid node ID with local node ID
|
||
|
EplDllkInstance_g.m_uiLastTargetNodeId = EplDllkInstance_g.m_DllConfigParam.m_uiNodeId;
|
||
|
// d.k. DLL state WaitAsndTrig is not helpful;
|
||
|
// so just step over to WaitSocTrig,
|
||
|
// because own ASnd is sent automatically in CbFrameTransmitted() after SoA.
|
||
|
//*pDllStateProposed_p = kEplDllMsWaitAsndTrig;
|
||
|
*pDllStateProposed_p = kEplDllMsWaitSocTrig;
|
||
|
}
|
||
|
else
|
||
|
{ // assignment to CN
|
||
|
*pDllStateProposed_p = kEplDllMsWaitAsnd;
|
||
|
}
|
||
|
|
||
|
pNodeInfo = EplDllkGetNodeInfo(EplDllkInstance_g.m_uiLastTargetNodeId);
|
||
|
if (pNodeInfo == NULL)
|
||
|
{ // no node info structure available
|
||
|
Ret = kEplDllNoNodeInfo;
|
||
|
goto Exit;
|
||
|
}
|
||
|
|
||
|
// update frame (EA, ER flags)
|
||
|
AmiSetByteToLe(&pTxFrame->m_Data.m_Soa.m_le_bFlag1,
|
||
|
pNodeInfo->m_bSoaFlag1 & (EPL_FRAME_FLAG1_EA | EPL_FRAME_FLAG1_ER));
|
||
|
}
|
||
|
else
|
||
|
{ // no assignment of asynchronous phase
|
||
|
*pDllStateProposed_p = kEplDllMsWaitSocTrig;
|
||
|
EplDllkInstance_g.m_uiLastTargetNodeId = EPL_C_ADR_INVALID;
|
||
|
}
|
||
|
|
||
|
// update frame (target)
|
||
|
AmiSetByteToLe(&pTxFrame->m_Data.m_Soa.m_le_bReqServiceId, (BYTE) EplDllkInstance_g.m_LastReqServiceId);
|
||
|
AmiSetByteToLe(&pTxFrame->m_Data.m_Soa.m_le_bReqServiceTarget, (BYTE) EplDllkInstance_g.m_uiLastTargetNodeId);
|
||
|
|
||
|
}
|
||
|
else
|
||
|
{ // invite nobody
|
||
|
// update frame (target)
|
||
|
AmiSetByteToLe(&pTxFrame->m_Data.m_Soa.m_le_bReqServiceId, (BYTE) 0);
|
||
|
AmiSetByteToLe(&pTxFrame->m_Data.m_Soa.m_le_bReqServiceTarget, (BYTE) 0);
|
||
|
}
|
||
|
|
||
|
// update frame (NMT state)
|
||
|
AmiSetByteToLe(&pTxFrame->m_Data.m_Soa.m_le_bNmtStatus, (BYTE) NmtState_p);
|
||
|
|
||
|
// send SoA frame
|
||
|
Ret = EdrvSendTxMsg(pTxBuffer);
|
||
|
}
|
||
|
|
||
|
Exit:
|
||
|
return Ret;
|
||
|
}
|
||
|
|
||
|
|
||
|
//---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: EplDllkMnSendSoc()
|
||
|
//
|
||
|
// Description: it updates and transmits the SoA.
|
||
|
//
|
||
|
// Parameters: (none)
|
||
|
//
|
||
|
// Returns: tEplKernel = error code
|
||
|
//
|
||
|
//
|
||
|
// State:
|
||
|
//
|
||
|
//---------------------------------------------------------------------------
|
||
|
|
||
|
static tEplKernel EplDllkMnSendSoc(void)
|
||
|
{
|
||
|
tEplKernel Ret = kEplSuccessful;
|
||
|
tEdrvTxBuffer* pTxBuffer = NULL;
|
||
|
tEplFrame* pTxFrame;
|
||
|
tEplEvent Event;
|
||
|
|
||
|
pTxBuffer = &EplDllkInstance_g.m_pTxBuffer[EPL_DLLK_TXFRAME_SOC];
|
||
|
if (pTxBuffer->m_pbBuffer != NULL)
|
||
|
{ // SoC does exist
|
||
|
pTxFrame = (tEplFrame *) pTxBuffer->m_pbBuffer;
|
||
|
|
||
|
// $$$ update NetTime
|
||
|
|
||
|
// send SoC frame
|
||
|
Ret = EdrvSendTxMsg(pTxBuffer);
|
||
|
if (Ret != kEplSuccessful)
|
||
|
{
|
||
|
goto Exit;
|
||
|
}
|
||
|
|
||
|
// trigger synchronous task
|
||
|
Event.m_EventSink = kEplEventSinkSync;
|
||
|
Event.m_EventType = kEplEventTypeSync;
|
||
|
Event.m_uiSize = 0;
|
||
|
Ret = EplEventkPost(&Event);
|
||
|
}
|
||
|
|
||
|
Exit:
|
||
|
return Ret;
|
||
|
}
|
||
|
|
||
|
|
||
|
//---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: EplDllkMnSendPreq()
|
||
|
//
|
||
|
// Description: it updates and transmits the PReq for the next isochronous CN
|
||
|
// or own PRes if enabled.
|
||
|
//
|
||
|
// Parameters: NmtState_p = current NMT state
|
||
|
// pDllStateProposed_p = proposed DLL state
|
||
|
//
|
||
|
// Returns: tEplKernel = error code
|
||
|
//
|
||
|
//
|
||
|
// State:
|
||
|
//
|
||
|
//---------------------------------------------------------------------------
|
||
|
|
||
|
static tEplKernel EplDllkMnSendPreq(tEplNmtState NmtState_p,
|
||
|
tEplDllState* pDllStateProposed_p)
|
||
|
{
|
||
|
tEplKernel Ret = kEplSuccessful;
|
||
|
tEdrvTxBuffer *pTxBuffer = NULL;
|
||
|
tEplFrame *pTxFrame;
|
||
|
BYTE bFlag1 = 0;
|
||
|
|
||
|
|
||
|
if (EplDllkInstance_g.m_pCurNodeInfo == NULL)
|
||
|
{ // start with first isochronous CN
|
||
|
EplDllkInstance_g.m_pCurNodeInfo = EplDllkInstance_g.m_pFirstNodeInfo;
|
||
|
}
|
||
|
else
|
||
|
{ // iterate to next isochronous CN
|
||
|
EplDllkInstance_g.m_pCurNodeInfo = EplDllkInstance_g.m_pCurNodeInfo->m_pNextNodeInfo;
|
||
|
}
|
||
|
|
||
|
if (EplDllkInstance_g.m_pCurNodeInfo == NULL)
|
||
|
{ // last isochronous CN reached
|
||
|
Ret = EplDllkMnSendSoa(NmtState_p, pDllStateProposed_p, TRUE);
|
||
|
goto Exit;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
pTxBuffer = EplDllkInstance_g.m_pCurNodeInfo->m_pPreqTxBuffer;
|
||
|
bFlag1 = EplDllkInstance_g.m_pCurNodeInfo->m_bSoaFlag1 & EPL_FRAME_FLAG1_EA;
|
||
|
*pDllStateProposed_p = kEplDllMsWaitPres;
|
||
|
|
||
|
// start PRes Timer
|
||
|
// $$$ d.k.: maybe move this call to CbFrameTransmitted(), because the time should run from there
|
||
|
#if EPL_TIMER_USE_HIGHRES != FALSE
|
||
|
Ret = EplTimerHighReskModifyTimerNs(&EplDllkInstance_g.m_TimerHdlResponse,
|
||
|
EplDllkInstance_g.m_pCurNodeInfo->m_dwPresTimeout,
|
||
|
EplDllkCbMnTimerResponse,
|
||
|
0L,
|
||
|
FALSE);
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
if (pTxBuffer == NULL)
|
||
|
{ // PReq does not exist
|
||
|
Ret = kEplDllTxBufNotReady;
|
||
|
goto Exit;
|
||
|
}
|
||
|
|
||
|
pTxFrame = (tEplFrame *) pTxBuffer->m_pbBuffer;
|
||
|
|
||
|
if (pTxFrame != NULL)
|
||
|
{ // PReq does exist
|
||
|
if (NmtState_p == kEplNmtMsOperational)
|
||
|
{ // leave RD flag untouched
|
||
|
bFlag1 |= AmiGetByteFromLe(&pTxFrame->m_Data.m_Preq.m_le_bFlag1) & EPL_FRAME_FLAG1_RD;
|
||
|
}
|
||
|
|
||
|
if (pTxBuffer == &EplDllkInstance_g.m_pTxBuffer[EPL_DLLK_TXFRAME_PRES])
|
||
|
{ // PRes of MN will be sent
|
||
|
// update NMT state
|
||
|
AmiSetByteToLe(&pTxFrame->m_Data.m_Pres.m_le_bNmtStatus, (BYTE) NmtState_p);
|
||
|
*pDllStateProposed_p = kEplDllMsWaitSoaTrig;
|
||
|
}
|
||
|
|
||
|
// $$$ d.k. set EPL_FRAME_FLAG1_MS if necessary
|
||
|
// update frame (Flag1)
|
||
|
AmiSetByteToLe(&pTxFrame->m_Data.m_Preq.m_le_bFlag1, bFlag1);
|
||
|
|
||
|
// calculate frame size from payload size
|
||
|
pTxBuffer->m_uiTxMsgLen = AmiGetWordFromLe(&pTxFrame->m_Data.m_Preq.m_le_wSize) + 24;
|
||
|
|
||
|
// send PReq frame
|
||
|
Ret = EdrvSendTxMsg(pTxBuffer);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
Ret = kEplDllTxFrameInvalid;
|
||
|
}
|
||
|
|
||
|
Exit:
|
||
|
return Ret;
|
||
|
}
|
||
|
|
||
|
|
||
|
//---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: EplDllkAsyncFrameNotReceived()
|
||
|
//
|
||
|
// Description: passes empty ASnd frame to receive FIFO.
|
||
|
// It will be called only for frames with registered AsndServiceIds
|
||
|
// (only kEplDllAsndFilterAny).
|
||
|
//
|
||
|
// Parameters: none
|
||
|
//
|
||
|
// Returns: tEplKernel = error code
|
||
|
//
|
||
|
//
|
||
|
// State:
|
||
|
//
|
||
|
//---------------------------------------------------------------------------
|
||
|
|
||
|
static tEplKernel EplDllkAsyncFrameNotReceived(tEplDllReqServiceId ReqServiceId_p, unsigned int uiNodeId_p)
|
||
|
{
|
||
|
tEplKernel Ret = kEplSuccessful;
|
||
|
BYTE abBuffer[18];
|
||
|
tEplFrame* pFrame = (tEplFrame*) abBuffer;
|
||
|
tEplFrameInfo FrameInfo;
|
||
|
|
||
|
// check if previous SoA invitation was not answered
|
||
|
switch (ReqServiceId_p)
|
||
|
{
|
||
|
case kEplDllReqServiceIdent:
|
||
|
case kEplDllReqServiceStatus:
|
||
|
// ASnd service registered?
|
||
|
if (EplDllkInstance_g.m_aAsndFilter[ReqServiceId_p] == kEplDllAsndFilterAny)
|
||
|
{ // ASnd service ID is registered
|
||
|
AmiSetByteToLe(&pFrame->m_le_bSrcNodeId, (BYTE) uiNodeId_p);
|
||
|
// EPL MsgType ASnd
|
||
|
AmiSetByteToLe(&pFrame->m_le_bMessageType, (BYTE) kEplMsgTypeAsnd);
|
||
|
// ASnd Service ID
|
||
|
AmiSetByteToLe(&pFrame->m_Data.m_Asnd.m_le_bServiceId, (BYTE) ReqServiceId_p);
|
||
|
// create frame info structure
|
||
|
FrameInfo.m_pFrame = pFrame;
|
||
|
FrameInfo.m_uiFrameSize = 18; // empty non existing ASnd frame
|
||
|
// forward frame via async receive FIFO to userspace
|
||
|
Ret = EplDllkCalAsyncFrameReceived(&FrameInfo);
|
||
|
}
|
||
|
break;
|
||
|
default:
|
||
|
// no invitation issued or it was successfully answered or it is uninteresting
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
return Ret;
|
||
|
}
|
||
|
|
||
|
|
||
|
#endif //(((EPL_MODULE_INTEGRATION) & (EPL_MODULE_NMT_MN)) != 0)
|
||
|
|
||
|
|
||
|
#endif // #if(((EPL_MODULE_INTEGRATION) & (EPL_MODULE_DLLK)) != 0)
|
||
|
// EOF
|
||
|
|