Logo Search packages:      
Sourcecode: linux-fsl-imx51 version File versions  Download package

EplDllk.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 TgtDbgSignalTracePoint(u8 bTracePointNumber_p);
void TgtDbgPostTraceValue(u32 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;

00197 typedef struct {
      u8 m_be_abSrcMac[6];
      tEdrvTxBuffer *m_pTxBuffer;   // Buffers for Tx-Frames
      unsigned int m_uiMaxTxFrames;
      u8 m_bFlag1;            // Flag 1 with EN, EC for PRes, StatusRes
      u8 m_bMnFlag1;    // Flag 1 with EA, ER from PReq, SoA of MN
      u8 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 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 EplDllkCbMnTimerCycle(tEplTimerEventArg *pEventArg_p);

static tEplKernel 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,
                         (u8) 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,
                                           (u8)
                                           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,
                               (u8) EPL_C_ADR_BROADCAST);
                  // reset Flags
                  //AmiSetByteToLe(&pTxFrame->m_Data.m_Soc.m_le_bFlag1, (u8) 0);
                  //AmiSetByteToLe(&pTxFrame->m_Data.m_Soc.m_le_bFlag2, (u8) 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,
                               (u8) EPL_C_ADR_BROADCAST);
                  // reset Flags
                  //AmiSetByteToLe(&pTxFrame->m_Data.m_Soa.m_le_bFlag1, (u8) 0);
                  //AmiSetByteToLe(&pTxFrame->m_Data.m_Soa.m_le_bFlag2, (u8) 0);
                  // EPL profile version
                  AmiSetByteToLe(&pTxFrame->m_Data.m_Soa.m_le_bEplVersion,
                               (u8) 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,
                               (u8) EPL_C_ADR_BROADCAST);
                  // reset Flags
                  //AmiSetByteToLe(&pTxFrame->m_Data.m_Pres.m_le_bFlag1, (u8) 0);
                  //AmiSetByteToLe(&pTxFrame->m_Data.m_Pres.m_le_bFlag2, (u8) 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, (u8) 0);
                  //AmiSetByteToLe(&pTxFrame->m_Data.m_Preq.m_le_bFlag2, (u8) 0);
                  // PDO size
                  //AmiSetWordToLe(&pTxFrame->m_Data.m_Preq.m_le_wSize, 0);
                  break;

            default:
                  break;
            }
            // EPL message type
            AmiSetByteToLe(&pTxFrame->m_le_bMessageType, (u8) 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;
      u8 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,
                               (u8) 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,
                               (u16) EplDllkInstance_g.
                               m_DllConfigParam.m_uiAsyncMtu);
                  // PollInSize
                  AmiSetWordToLe(&pTxFrame->m_Data.m_Asnd.m_Payload.
                               m_IdentResponse.m_le_wPollInSize,
                               (u16) EplDllkInstance_g.
                               m_DllConfigParam.
                               m_uiPreqActPayloadLimit);
                  // PollOutSize
                  AmiSetWordToLe(&pTxFrame->m_Data.m_Asnd.m_Payload.
                               m_IdentResponse.m_le_wPollOutSize,
                               (u16) 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 =
                                  (u16) 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 =
                                  (u8) (((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,
                                           (u8) 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, u8 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,
                         (u8) 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;
      u8 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,
                                           (u8) 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,
                                           (u8) 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,
                                     (u8) 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,
                                                 (u8) 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,
                                                 (u8) 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) {
            u32 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,
                                           (u8) 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,
                                           (u8) 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)
                                         == (u8) kEplMsgTypeAsnd)
                                        &&
                                        (AmiGetByteFromLe
                                         (&pTxFrame->m_Data.m_Asnd.
                                          m_le_bServiceId)
                                         == (u8) 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) {
            u32 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;
      u16 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,
                               (u8) 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,
                                     (u8) 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 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) {
            u32 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 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) {
            u32 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 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) {
            u32 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,
                               (u8) EplDllkInstance_g.
                               m_LastReqServiceId);
                  AmiSetByteToLe(&pTxFrame->m_Data.m_Soa.
                               m_le_bReqServiceTarget,
                               (u8) EplDllkInstance_g.
                               m_uiLastTargetNodeId);

            } else {    // invite nobody
                  // update frame (target)
                  AmiSetByteToLe(&pTxFrame->m_Data.m_Soa.
                               m_le_bReqServiceId, (u8) 0);
                  AmiSetByteToLe(&pTxFrame->m_Data.m_Soa.
                               m_le_bReqServiceTarget, (u8) 0);
            }

            // update frame (NMT state)
            AmiSetByteToLe(&pTxFrame->m_Data.m_Soa.m_le_bNmtStatus,
                         (u8) 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;
      u8 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,
                               (u8) 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;
      u8 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,
                               (u8) uiNodeId_p);
                  // EPL MsgType ASnd
                  AmiSetByteToLe(&pFrame->m_le_bMessageType,
                               (u8) kEplMsgTypeAsnd);
                  // ASnd Service ID
                  AmiSetByteToLe(&pFrame->m_Data.m_Asnd.m_le_bServiceId,
                               (u8) 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

Generated by  Doxygen 1.6.0   Back to index