//------------------------------------------------------------------------------ tOplkError edrvcyclic_stopCycle(void) { tOplkError ret = kErrorOk; ret = hrestimer_deleteTimer(&edrvcyclicInstance_l.timerHdlCycle); #if (EDRV_USE_TTTX == FALSE) ret = hrestimer_deleteTimer(&edrvcyclicInstance_l.timerHdlSlot); #endif #if CONFIG_EDRV_CYCLIC_USE_DIAGNOSTICS != FALSE edrvcyclicInstance_l.startCycleTimeStamp = 0; #endif return ret; }
//------------------------------------------------------------------------------ tOplkError edrvcyclic_stopCycle(BOOL fKeepCycle_p) { tOplkError ret = kErrorOk; if (!fKeepCycle_p) { ret = hrestimer_deleteTimer(&edrvcyclicInstance_l.timerHdlCycle); } #if (EDRV_USE_TTTX == FALSE) ret = hrestimer_deleteTimer(&edrvcyclicInstance_l.timerHdlSlot); #endif // clear current and next Tx buffer list OPLK_MEMSET(edrvcyclicInstance_l.ppTxBufferList, 0, sizeof(*edrvcyclicInstance_l.ppTxBufferList) * edrvcyclicInstance_l.maxTxBufferCount * 2); #if CONFIG_EDRV_CYCLIC_USE_DIAGNOSTICS != FALSE edrvcyclicInstance_l.startCycleTimeStamp = 0; #endif return ret; }
//------------------------------------------------------------------------------ static tOplkError processNmtStateChange(tNmtState newNmtState_p, tNmtState oldNmtState_p, tNmtEvent nmtEvent_p) { tOplkError ret = kErrorOk; #if !defined(CONFIG_INCLUDE_NMT_RMN) UNUSED_PARAMETER(nmtEvent_p); #endif switch (newNmtState_p) { case kNmtGsOff: case kNmtGsInitialising: dllkInstance_g.socTime.relTime = 0; // set EC flag in Flag 1, so the MN can detect a reboot and // will initialize the Error Signaling. dllkInstance_g.flag1 = PLK_FRAME_FLAG1_EC; dllkInstance_g.nmtState = newNmtState_p; if (oldNmtState_p > kNmtGsResetConfiguration) { ret = dllknode_cleanupLocalNode(oldNmtState_p); // deinitialize DLL and destroy frames } break; case kNmtGsResetApplication: case kNmtGsResetCommunication: case kNmtGsResetConfiguration: // at first, update NMT state in instance structure to disable frame processing dllkInstance_g.nmtState = newNmtState_p; if (oldNmtState_p > kNmtGsResetConfiguration) { ret = dllknode_cleanupLocalNode(oldNmtState_p); // deinitialize DLL and destroy frames } break; // node listens for POWERLINK frames and check timeout case kNmtMsNotActive: case kNmtCsNotActive: case kNmtRmsNotActive: if (oldNmtState_p <= kNmtGsResetConfiguration) { // setup DLL and create frames ret = dllknode_setupLocalNode(newNmtState_p); } break; // node processes only async frames case kNmtCsPreOperational1: #if CONFIG_TIMER_USE_HIGHRES != FALSE if ((ret = hrestimer_deleteTimer(&dllkInstance_g.timerHdlCycle)) != kErrorOk) return ret; #endif #if defined(CONFIG_INCLUDE_NMT_RMN) if (dllkInstance_g.fRedundancy) { ret = edrvcyclic_stopCycle(FALSE); if (ret != kErrorOk) return ret; hrestimer_modifyTimer(&dllkInstance_g.timerHdlSwitchOver, dllkInstance_g.dllConfigParam.reducedSwitchOverTimeMn * 1000ULL, dllk_cbTimerSwitchOver, 0L, FALSE); } #endif // deactivate sync generation if ((ret = controlTimeSync(FALSE)) != kErrorOk) return ret; #if (CONFIG_DLL_PROCESS_SYNC == DLL_PROCESS_SYNC_ON_TIMER) if ((ret = synctimer_stopSync()) != kErrorOk) return ret; #endif #if CONFIG_DLL_PRES_CHAINING_CN != FALSE if ((ret = dllkframe_presChainingDisable()) != kErrorOk) return ret; #endif // update IdentRes and StatusRes ret = dllkframe_updateFrameStatusRes(&dllkInstance_g.pTxBuffer[DLLK_TXFRAME_STATUSRES + dllkInstance_g.curTxBufferOffsetStatusRes], newNmtState_p); if (ret != kErrorOk) return ret; ret = dllkframe_updateFrameIdentRes(&dllkInstance_g.pTxBuffer[DLLK_TXFRAME_IDENTRES + dllkInstance_g.curTxBufferOffsetIdentRes], newNmtState_p); if (ret != kErrorOk) return ret; // enable IdentRes and StatusRes #if (CONFIG_EDRV_AUTO_RESPONSE != FALSE) // enable corresponding Rx filter dllkInstance_g.aFilter[DLLK_FILTER_SOA_STATREQ].fEnable = TRUE; ret = edrv_changeRxFilter(dllkInstance_g.aFilter, DLLK_FILTER_COUNT, DLLK_FILTER_SOA_STATREQ, EDRV_FILTER_CHANGE_STATE); if (ret != kErrorOk) return ret; // enable corresponding Rx filter dllkInstance_g.aFilter[DLLK_FILTER_SOA_IDREQ].fEnable = TRUE; ret = edrv_changeRxFilter(dllkInstance_g.aFilter, DLLK_FILTER_COUNT, DLLK_FILTER_SOA_IDREQ, EDRV_FILTER_CHANGE_STATE); if (ret != kErrorOk) return ret; #if CONFIG_DLL_PRES_CHAINING_CN != FALSE // enable SyncReq Rx filter dllkInstance_g.aFilter[DLLK_FILTER_SOA_SYNCREQ].fEnable = TRUE; ret = edrv_changeRxFilter(dllkInstance_g.aFilter, DLLK_FILTER_COUNT, DLLK_FILTER_SOA_SYNCREQ, EDRV_FILTER_CHANGE_STATE); if (ret != kErrorOk) return ret; #endif #endif // update PRes (for sudden changes to PreOp2) ret = dllkframe_updateFramePres(&dllkInstance_g.pTxBuffer[DLLK_TXFRAME_PRES + (dllkInstance_g.curTxBufferOffsetCycle ^ 1)], kNmtCsPreOperational2); if (ret != kErrorOk) return ret; ret = dllkframe_updateFramePres(&dllkInstance_g.pTxBuffer[DLLK_TXFRAME_PRES + dllkInstance_g.curTxBufferOffsetCycle], kNmtCsPreOperational2); if (ret != kErrorOk) return ret; // enable PRes (for sudden changes to PreOp2) #if (CONFIG_EDRV_AUTO_RESPONSE != FALSE) // enable corresponding Rx filter dllkInstance_g.aFilter[DLLK_FILTER_PREQ].fEnable = TRUE; dllkInstance_g.aFilter[DLLK_FILTER_PREQ].pTxBuffer = &dllkInstance_g.pTxBuffer[DLLK_TXFRAME_PRES]; ret = edrv_changeRxFilter(dllkInstance_g.aFilter, DLLK_FILTER_COUNT, DLLK_FILTER_PREQ, EDRV_FILTER_CHANGE_STATE | EDRV_FILTER_CHANGE_AUTO_RESPONSE); if (ret != kErrorOk) return ret; #endif break; // node processes isochronous and asynchronous frames case kNmtCsPreOperational2: // signal update of IdentRes and StatusRes on SoA dllkInstance_g.updateTxFrame = DLLK_UPDATE_BOTH; // enable PRes (necessary if coming from Stopped) #if (CONFIG_EDRV_AUTO_RESPONSE != FALSE) // enable corresponding Rx filter dllkInstance_g.aFilter[DLLK_FILTER_PREQ].fEnable = TRUE; dllkInstance_g.aFilter[DLLK_FILTER_PREQ].pTxBuffer = &dllkInstance_g.pTxBuffer[DLLK_TXFRAME_PRES]; ret = edrv_changeRxFilter(dllkInstance_g.aFilter, DLLK_FILTER_COUNT, DLLK_FILTER_PREQ, EDRV_FILTER_CHANGE_STATE | EDRV_FILTER_CHANGE_AUTO_RESPONSE); if (ret != kErrorOk) return ret; #endif break; #if defined (CONFIG_INCLUDE_NMT_MN) case kNmtMsPreOperational1: #if CONFIG_TIMER_USE_HIGHRES != FALSE ret = hrestimer_deleteTimer(&dllkInstance_g.timerHdlCycle); if (ret != kErrorOk) return ret; #endif /// deactivate sync generation if ((ret = controlTimeSync(FALSE)) != kErrorOk) return ret; ret = edrvcyclic_stopCycle(FALSE); if (ret != kErrorOk) return ret; #if defined(CONFIG_INCLUDE_NMT_RMN) if (dllkInstance_g.fRedundancy) { if ((ret = hrestimer_deleteTimer(&dllkInstance_g.timerHdlSwitchOver)) != kErrorOk) return ret; if (oldNmtState_p == kNmtRmsNotActive) { // send AMNI ret = edrv_sendTxBuffer(&dllkInstance_g.pTxBuffer[DLLK_TXFRAME_AMNI]); if (ret != kErrorOk) return ret; } // initialize cycle counter if (dllkInstance_g.dllConfigParam.fAsyncOnly == FALSE) { dllkInstance_g.cycleCount = 0; } else { // it is an async-only CN -> fool changeState() to think that PRes was not expected dllkInstance_g.cycleCount = 1; } } #endif // update IdentRes and StatusRes ret = dllkframe_updateFrameIdentRes(&dllkInstance_g.pTxBuffer[DLLK_TXFRAME_IDENTRES + dllkInstance_g.curTxBufferOffsetIdentRes], newNmtState_p); if (ret != kErrorOk) return ret; ret = dllkframe_updateFrameStatusRes(&dllkInstance_g.pTxBuffer[DLLK_TXFRAME_STATUSRES + dllkInstance_g.curTxBufferOffsetStatusRes], newNmtState_p); break; case kNmtMsReadyToOperate: /// activate sync generation if ((ret = controlTimeSync(TRUE)) != kErrorOk) return ret; break; case kNmtMsPreOperational2: case kNmtMsOperational: // signal update of IdentRes and StatusRes on SoA dllkInstance_g.updateTxFrame = DLLK_UPDATE_BOTH; #if defined(CONFIG_INCLUDE_NMT_RMN) if (dllkInstance_g.fRedundancy && (oldNmtState_p == kNmtCsOperational)) { dllkInstance_g.dllState = kDllMsWaitSocTrig; if ((ret = hrestimer_deleteTimer(&dllkInstance_g.timerHdlSwitchOver)) != kErrorOk) return ret; dllkInstance_g.socTime.relTime += dllkInstance_g.dllConfigParam.cycleLen; // initialize SoAReq number for ProcessSync (cycle preparation) dllkInstance_g.syncLastSoaReq = dllkInstance_g.curLastSoaReq; // trigger synchronous task for cycle preparation dllkInstance_g.fSyncProcessed = TRUE; ret = dllk_postEvent(kEventTypeSync); } #endif break; #endif case kNmtCsReadyToOperate: /// activate sync generation if ((ret = controlTimeSync(TRUE)) != kErrorOk) return ret; // signal update of IdentRes and StatusRes on SoA dllkInstance_g.updateTxFrame = DLLK_UPDATE_BOTH; break; case kNmtCsOperational: // signal update of IdentRes and StatusRes on SoA dllkInstance_g.updateTxFrame = DLLK_UPDATE_BOTH; #if defined(CONFIG_INCLUDE_NMT_RMN) if (dllkInstance_g.fRedundancy && (oldNmtState_p == kNmtMsOperational)) { dllkInstance_g.dllState = kDllCsWaitSoc; ret = edrvcyclic_stopCycle(TRUE); if (ret != kErrorOk) return ret; hrestimer_modifyTimer(&dllkInstance_g.timerHdlSwitchOver, dllkInstance_g.dllConfigParam.switchOverTimeMn * 1000ULL, dllk_cbTimerSwitchOver, 0L, FALSE); if ((nmtEvent_p == kNmtEventGoToStandby) || (nmtEvent_p == kNmtEventGoToStandbyDelayed)) { // save event, so cbCyclicError can start switch-over timeout // appropriately dllkInstance_g.nmtEventGoToStandby = nmtEvent_p; } } #endif break; // node stopped by MN case kNmtCsStopped: // signal update of IdentRes and StatusRes on SoA dllkInstance_g.updateTxFrame = DLLK_UPDATE_BOTH; #if (CONFIG_EDRV_AUTO_RESPONSE != FALSE) // disable auto-response for PRes filter dllkInstance_g.aFilter[DLLK_FILTER_PREQ].pTxBuffer = NULL; ret = edrv_changeRxFilter(dllkInstance_g.aFilter, DLLK_FILTER_COUNT, DLLK_FILTER_PREQ, EDRV_FILTER_CHANGE_AUTO_RESPONSE); if (ret != kErrorOk) return ret; #endif // update PRes ret = dllkframe_updateFramePres(&dllkInstance_g.pTxBuffer[DLLK_TXFRAME_PRES + (dllkInstance_g.curTxBufferOffsetCycle ^ 1)], newNmtState_p); if (ret != kErrorOk) return ret; ret = dllkframe_updateFramePres(&dllkInstance_g.pTxBuffer[DLLK_TXFRAME_PRES + dllkInstance_g.curTxBufferOffsetCycle], newNmtState_p); if (ret != kErrorOk) return ret; break; // no POWERLINK cycle -> normal ethernet communication case kNmtMsBasicEthernet: case kNmtCsBasicEthernet: // Fill Async Tx Buffer, because state BasicEthernet was entered ret = processFillTx(kDllAsyncReqPrioGeneric, newNmtState_p); if (ret != kErrorOk) return ret; break; default: return kErrorNmtInvalidState; break; } // update NMT state in instance structure. This is done after updating all // Tx frames, so no frame will be transmitted by callback function, when it // is not up to date yet. dllkInstance_g.nmtState = newNmtState_p; return ret; }
//------------------------------------------------------------------------------ tOplkError dllknode_cleanupLocalNode(tNmtState oldNmtState_p) { tOplkError ret = kErrorOk; BYTE aMulticastMac[6]; #if NMT_MAX_NODE_ID > 0 UINT index; #endif #if defined(CONFIG_INCLUDE_NMT_MN) UINT handle; #else UNUSED_PARAMETER(oldNmtState_p); #endif // remove all filters from Edrv ret = edrv_changeRxFilter(NULL, 0, 0, 0); // delete timer #if CONFIG_TIMER_USE_HIGHRES != FALSE if ((ret = hrestimer_deleteTimer(&dllkInstance_g.timerHdlCycle)) != kErrorOk) return ret; #if defined(CONFIG_INCLUDE_NMT_RMN) if ((ret = hrestimer_deleteTimer(&dllkInstance_g.timerHdlSwitchOver)) != kErrorOk) return ret; #endif #endif #if defined(CONFIG_INCLUDE_NMT_MN) if ((ret = edrvcyclic_stopCycle(FALSE)) != kErrorOk) return ret; if ((ret = edrvcyclic_regSyncHandler(NULL)) != kErrorOk) return ret; #endif #if (CONFIG_DLL_PROCESS_SYNC == DLL_PROCESS_SYNC_ON_TIMER) if ((ret = synctimer_stopSync()) != kErrorOk) return ret; #endif #if defined(CONFIG_INCLUDE_NMT_MN) // destroy all data structures OPLK_FREE(dllkInstance_g.ppTxBufferList); dllkInstance_g.ppTxBufferList = NULL; #endif // delete Tx frames if ((ret = dllkframe_deleteTxFrame(DLLK_TXFRAME_IDENTRES)) != kErrorOk) return ret; if ((ret = dllkframe_deleteTxFrame(DLLK_TXFRAME_STATUSRES)) != kErrorOk) return ret; if ((ret = dllkframe_deleteTxFrame(DLLK_TXFRAME_PRES)) != kErrorOk) return ret; #if defined(CONFIG_INCLUDE_NMT_RMN) if (dllkInstance_g.fRedundancy) { if ((ret = dllkframe_deleteTxFrame(DLLK_TXFRAME_AMNI)) != kErrorOk) return ret; } #endif dllkInstance_g.aTxBufferStateNmtReq[0] = kDllkTxBufEmpty; dllkInstance_g.aTxBufferStateNmtReq[1] = kDllkTxBufEmpty; if ((ret = dllkframe_deleteTxFrame(DLLK_TXFRAME_NMTREQ)) != kErrorOk) return ret; #if CONFIG_DLL_PRES_CHAINING_CN != FALSE if ((ret = dllkframe_deleteTxFrame(DLLK_TXFRAME_SYNCRES)) != kErrorOk) return ret; #endif dllkInstance_g.aTxBufferStateNonPlk[0] = kDllkTxBufEmpty; dllkInstance_g.aTxBufferStateNonPlk[1] = kDllkTxBufEmpty; if ((ret = dllkframe_deleteTxFrame(DLLK_TXFRAME_NONPLK)) != kErrorOk) return ret; #if defined(CONFIG_INCLUDE_NMT_MN) #if !defined(CONFIG_INCLUDE_NMT_RMN) if (NMT_IF_MN_OR_RMN(oldNmtState_p)) #else if (NMT_IF_MN_OR_RMN(oldNmtState_p) || (dllkInstance_g.fRedundancy)) #endif { // local node was MN if ((ret = dllkframe_deleteTxFrame(DLLK_TXFRAME_SOC)) != kErrorOk) return ret; if ((ret = dllkframe_deleteTxFrame(DLLK_TXFRAME_SOA)) != kErrorOk) return ret; for (index = 0; index < tabentries (dllkInstance_g.aNodeInfo); index++) { if (dllkInstance_g.aNodeInfo[index].pPreqTxBuffer != NULL) { handle = (UINT)(dllkInstance_g.aNodeInfo[index].pPreqTxBuffer - dllkInstance_g.pTxBuffer); dllkInstance_g.aNodeInfo[index].pPreqTxBuffer = NULL; if (handle != DLLK_TXFRAME_PRES) { if ((ret = dllkframe_deleteTxFrame(handle)) != kErrorOk) return ret; } } // disable PReq and PRes for this node dllkInstance_g.aNodeInfo[index].preqPayloadLimit = 0; dllkInstance_g.aNodeInfo[index].presPayloadLimit = 0; } } else { // local node was CN for (index = 0; index < tabentries(dllkInstance_g.aNodeInfo); index++) { // disable PReq and PRes for this node dllkInstance_g.aNodeInfo[index].presPayloadLimit = 0; dllkInstance_g.aNodeInfo[index].preqPayloadLimit = 0; } } #else // must be CN, because MN part is not compiled! #if NMT_MAX_NODE_ID > 0 for (index = 0; index < tabentries(dllkInstance_g.aNodeInfo); index++) { // disable PRes for this node dllkInstance_g.aNodeInfo[index].presPayloadLimit = 0; } #endif #endif // de-register multicast MACs in Ethernet driver ami_setUint48Be(&aMulticastMac[0], C_DLL_MULTICAST_SOC); ret = edrv_clearRxMulticastMacAddr(aMulticastMac); ami_setUint48Be(&aMulticastMac[0], C_DLL_MULTICAST_SOA); ret = edrv_clearRxMulticastMacAddr(aMulticastMac); ami_setUint48Be(&aMulticastMac[0], C_DLL_MULTICAST_PRES); ret = edrv_clearRxMulticastMacAddr(aMulticastMac); ami_setUint48Be(&aMulticastMac[0], C_DLL_MULTICAST_ASND); ret = edrv_clearRxMulticastMacAddr(aMulticastMac); return ret; }