//------------------------------------------------------------------------------ tOplkError edrvcyclic_startCycle(void) { tOplkError ret = kErrorOk; if (edrvcyclicInstance_l.cycleTimeUs == 0) { ret = kErrorEdrvInvalidCycleLen; goto Exit; } // clear Tx buffer list edrvcyclicInstance_l.curTxBufferList = 0; edrvcyclicInstance_l.curTxBufferEntry = 0; OPLK_MEMSET(edrvcyclicInstance_l.ppTxBufferList, 0, sizeof(*edrvcyclicInstance_l.ppTxBufferList) * edrvcyclicInstance_l.maxTxBufferCount * 2); ret = hrestimer_modifyTimer(&edrvcyclicInstance_l.timerHdlCycle, edrvcyclicInstance_l.cycleTimeUs * 1000ULL, timerHdlCycleCb, 0L, TRUE); #if (EDRV_USE_TTTX == TRUE) edrvcyclicInstance_l.fNextCycleValid = FALSE; #endif #if CONFIG_EDRV_CYCLIC_USE_DIAGNOSTICS != FALSE edrvcyclicInstance_l.lastSlotTimeStamp = 0; #endif Exit: return ret; }
//------------------------------------------------------------------------------ static tOplkError processStartReducedCycle(void) { tOplkError ret = kErrorOk; // 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 = dllkcal_clearAsyncQueues(); // reset cycle counter (every time a SoA is triggered in PreOp1 the counter is incremented // and when it reaches C_DLL_PREOP1_START_CYCLES the SoA may contain invitations) dllkInstance_g.cycleCount = 0; // remove any CN from isochronous phase while (dllkInstance_g.pFirstNodeInfo != NULL) { ret = dllknode_deleteNodeIsochronous(dllkInstance_g.pFirstNodeInfo); if (ret != kErrorOk) goto Exit; } while (dllkInstance_g.pFirstPrcNodeInfo != NULL) { ret = dllknode_deleteNodeIsochronous(dllkInstance_g.pFirstPrcNodeInfo); if (ret != kErrorOk) goto Exit; } // change state to NonCyclic, // hence changeState() will not ignore the next call dllkInstance_g.dllState = kDllMsNonCyclic; #if CONFIG_TIMER_USE_HIGHRES != FALSE if (dllkInstance_g.dllConfigParam.asyncSlotTimeout != 0) { ret = hrestimer_modifyTimer(&dllkInstance_g.timerHdlCycle, dllkInstance_g.dllConfigParam.asyncSlotTimeout, dllkframe_cbMnTimerCycle, 0L, FALSE); } #endif dllkInstance_g.curLastSoaReq = 0; dllkInstance_g.curTxBufferOffsetCycle = 0; Exit: return ret; }
//------------------------------------------------------------------------------ static tOplkError processTxBufferList(void) { tOplkError ret = kErrorOk; tEdrvTxBuffer* pTxBuffer = NULL; #if (EDRV_USE_TTTX == TRUE) BOOL fFirstPacket = TRUE; UINT64 launchTime; UINT64 cycleMin; UINT64 cycleMax; UINT64 currentMacTime = 0; #endif #if (EDRV_USE_TTTX == TRUE) edrv_getMacTime(¤tMacTime); if (!edrvcyclicInstance_l.fNextCycleValid) { edrvcyclicInstance_l.nextCycleTime = currentMacTime + EDRV_SHIFT; launchTime = edrvcyclicInstance_l.nextCycleTime; edrvcyclicInstance_l.fNextCycleValid = TRUE; } else { launchTime = edrvcyclicInstance_l.nextCycleTime; if (currentMacTime > launchTime) { ret = kErrorEdrvTxListNotFinishedYet; goto Exit; } } cycleMin = launchTime; cycleMax = launchTime + (edrvcyclicInstance_l.cycleTimeUs * 1000ULL); while ((pTxBuffer = edrvcyclicInstance_l.ppTxBufferList[edrvcyclicInstance_l.curTxBufferEntry]) != NULL) { if (pTxBuffer == NULL) { ret = kErrorEdrvBufNotExisting; goto Exit; } if (fFirstPacket) { pTxBuffer->launchTime = launchTime ; fFirstPacket = FALSE; } else { launchTime = launchTime + (UINT64)pTxBuffer->timeOffsetNs; pTxBuffer->launchTime = launchTime; } if ((pTxBuffer->launchTime - cycleMin) > (cycleMax - cycleMin)) { ret = kErrorEdrvTxListNotFinishedYet; goto Exit; } ret = edrv_sendTxBuffer(pTxBuffer); if (ret != kErrorOk) goto Exit; pTxBuffer->launchTime = 0; edrvcyclicInstance_l.curTxBufferEntry++; } #else while ((pTxBuffer = edrvcyclicInstance_l.ppTxBufferList[edrvcyclicInstance_l.curTxBufferEntry]) != NULL) { if (pTxBuffer->timeOffsetNs == 0) { ret = edrv_sendTxBuffer(pTxBuffer); if (ret != kErrorOk) { goto Exit; } } else { ret = hrestimer_modifyTimer(&edrvcyclicInstance_l.timerHdlSlot, pTxBuffer->timeOffsetNs, timerHdlSlotCb, 0L, FALSE); break; } edrvcyclicInstance_l.curTxBufferEntry++; } #endif Exit: if (ret != kErrorOk) { if (edrvcyclicInstance_l.pfnErrorCb != NULL) { ret = edrvcyclicInstance_l.pfnErrorCb(ret, pTxBuffer); } } 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 dllk_cbCyclicError(tOplkError errorCode_p, tEdrvTxBuffer* pTxBuffer_p) { tOplkError ret = kErrorOk; tNmtState nmtState; UINT handle = 0; UINT32 arg; tEventDllError dllEvent; TGT_DLLK_DECLARE_FLAGS; UNUSED_PARAMETER(pTxBuffer_p); TGT_DLLK_ENTER_CRITICAL_SECTION(); nmtState = dllkInstance_g.nmtState; if (!NMT_IF_MN(nmtState)) { #if defined(CONFIG_INCLUDE_NMT_RMN) if (errorCode_p == kErrorEdrvCurTxListEmpty) { switch (dllkInstance_g.nmtEventGoToStandby) { case kNmtEventGoToStandby: hrestimer_modifyTimer(&dllkInstance_g.timerHdlSwitchOver, (dllkInstance_g.dllConfigParam.switchOverTimeMn - dllkInstance_g.dllConfigParam.cycleLen) * 1000ULL, dllk_cbTimerSwitchOver, 0L, FALSE); dllkInstance_g.nmtEventGoToStandby = kNmtEventNoEvent; break; case kNmtEventGoToStandbyDelayed: hrestimer_modifyTimer(&dllkInstance_g.timerHdlSwitchOver, (dllkInstance_g.dllConfigParam.delayedSwitchOverTimeMn - dllkInstance_g.dllConfigParam.cycleLen) * 1000ULL, dllk_cbTimerSwitchOver, 0L, FALSE); dllkInstance_g.nmtEventGoToStandby = kNmtEventNoEvent; break; default: break; } } #endif // ignore errors if not MN goto Exit; } if (pTxBuffer_p != NULL) { handle = (UINT)(pTxBuffer_p - dllkInstance_g.pTxBuffer); } BENCHMARK_MOD_02_TOGGLE(7); switch (errorCode_p) { case kErrorEdrvCurTxListEmpty: case kErrorEdrvTxListNotFinishedYet: case kErrorEdrvNoFreeTxDesc: dllEvent.dllErrorEvents = DLL_ERR_MN_CYCTIMEEXCEED; dllEvent.nodeId = handle; dllEvent.nmtState = nmtState; dllEvent.oplkError = errorCode_p; ret = errhndk_postError(&dllEvent); break; default: arg = dllkInstance_g.dllState | (handle << 16); // Error event for API layer ret = eventk_postError(kEventSourceDllk, errorCode_p, sizeof(arg), &arg); break; } Exit: TGT_DLLK_LEAVE_CRITICAL_SECTION(); return ret; }