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