//------------------------------------------------------------------------------ tOplkError dllk_cbTimerSwitchOver(tTimerEventArg* pEventArg_p) { tOplkError ret = kErrorOk; tNmtState nmtState; UINT32 arg; tNmtEvent nmtEvent; tEvent event; TGT_DLLK_DECLARE_FLAGS; TGT_DLLK_ENTER_CRITICAL_SECTION(); #if CONFIG_TIMER_USE_HIGHRES != FALSE if (pEventArg_p->timerHdl != dllkInstance_g.timerHdlSwitchOver) { // zombie callback - just exit goto Exit; } #endif nmtState = dllkInstance_g.nmtState; if (!NMT_IF_ACTIVE_CN(nmtState)) goto Exit; ret = edrv_sendTxBuffer(&dllkInstance_g.pTxBuffer[DLLK_TXFRAME_AMNI]); if (ret != kErrorOk) goto Exit; // increment relativeTime for missing SoC dllkInstance_g.relativeTime += dllkInstance_g.dllConfigParam.cycleLen; nmtEvent = kNmtEventDllReSwitchOverTimeout; event.eventSink = kEventSinkNmtk; event.eventType = kEventTypeNmtEvent; event.eventArgSize = sizeof(nmtEvent); event.pEventArg = &nmtEvent; ret = eventk_postEvent(&event); Exit: if (ret != kErrorOk) { BENCHMARK_MOD_02_TOGGLE(7); arg = dllkInstance_g.dllState | (kNmtEventDllReSwitchOverTimeout << 8); // Error event for API layer ret = eventk_postError(kEventSourceDllk, ret, sizeof(arg), &arg); } TGT_DLLK_LEAVE_CRITICAL_SECTION(); return ret; }
//------------------------------------------------------------------------------ static tOplkError timerHdlSlotCb(tTimerEventArg* pEventArg_p) { tOplkError ret = kErrorOk; tEdrvTxBuffer* pTxBuffer = NULL; if (pEventArg_p->timerHdl != edrvcyclicInstance_l.timerHdlSlot) { // zombie callback // just exit goto Exit; } #if CONFIG_EDRV_CYCLIC_USE_DIAGNOSTICS != FALSE edrvcyclicInstance_l.lastSlotTimeStamp = target_getCurrentTimestamp(); #endif pTxBuffer = edrvcyclicInstance_l.ppTxBufferList[edrvcyclicInstance_l.curTxBufferEntry]; ret = edrv_sendTxBuffer(pTxBuffer); if (ret != kErrorOk) { goto Exit; } edrvcyclicInstance_l.curTxBufferEntry++; ret = processTxBufferList(); Exit: if (ret != kErrorOk) { if (edrvcyclicInstance_l.pfnErrorCb != NULL) { ret = edrvcyclicInstance_l.pfnErrorCb(ret, pTxBuffer); } } 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 processFillTx(tDllAsyncReqPriority asyncReqPriority_p, tNmtState nmtState_p) { tOplkError ret = kErrorOk; tPlkFrame * pTxFrame; tEdrvTxBuffer* pTxBuffer; UINT frameSize; UINT frameCount; UINT nextTxBufferOffset; tDllkTxBufState* pTxBufferState = NULL; #if (CONFIG_EDRV_AUTO_RESPONSE != FALSE) UINT filterEntry; #endif // fill TxBuffer of specified priority with new frame if empty pTxFrame = NULL; switch (asyncReqPriority_p) { case kDllAsyncReqPrioNmt: // NMT request priority nextTxBufferOffset = dllkInstance_g.curTxBufferOffsetNmtReq; pTxBuffer = &dllkInstance_g.pTxBuffer[DLLK_TXFRAME_NMTREQ + nextTxBufferOffset]; pTxBufferState = &dllkInstance_g.aTxBufferStateNmtReq[nextTxBufferOffset]; #if (CONFIG_EDRV_AUTO_RESPONSE != FALSE) filterEntry = DLLK_FILTER_SOA_NMTREQ; #endif break; default: // generic priority nextTxBufferOffset = dllkInstance_g.curTxBufferOffsetNonPlk; pTxBuffer = &dllkInstance_g.pTxBuffer[DLLK_TXFRAME_NONPLK + nextTxBufferOffset]; pTxBufferState = &dllkInstance_g.aTxBufferStateNonPlk[nextTxBufferOffset]; #if (CONFIG_EDRV_AUTO_RESPONSE != FALSE) filterEntry = DLLK_FILTER_SOA_NONPLK; #endif break; } if (pTxBuffer->pBuffer != NULL) { // NmtRequest or non-POWERLINK frame does exist // check if frame is empty and not being filled if (*pTxBufferState == kDllkTxBufEmpty) { *pTxBufferState = kDllkTxBufFilling; // mark Tx buffer as filling is in process frameSize = pTxBuffer->maxBufferSize; // set max buffer size as input parameter // copy frame from shared loop buffer to Tx buffer ret = dllkcal_getAsyncTxFrame(pTxBuffer->pBuffer, &frameSize, asyncReqPriority_p); if (ret == kErrorOk) { pTxFrame = (tPlkFrame*)pTxBuffer->pBuffer; ret = dllkframe_checkFrame(pTxFrame, frameSize); if (ret != kErrorOk) goto Exit; pTxBuffer->txFrameSize = frameSize; // set buffer valid *pTxBufferState = kDllkTxBufReady; #if (CONFIG_EDRV_AUTO_RESPONSE != FALSE) if ((nmtState_p & (NMT_TYPE_MASK | NMT_SUPERSTATE_MASK)) == (NMT_TYPE_CS | NMT_CS_PLKMODE)) { ret = edrv_updateTxBuffer(pTxBuffer); // enable corresponding Rx filter dllkInstance_g.aFilter[filterEntry].fEnable = TRUE; ret = edrv_changeRxFilter(dllkInstance_g.aFilter, DLLK_FILTER_COUNT, filterEntry, EDRV_FILTER_CHANGE_STATE); if (ret != kErrorOk) goto Exit; } #endif } else if (ret == kErrorDllAsyncTxBufferEmpty) { // empty Tx buffer is not a real problem so just ignore it ret = kErrorOk; *pTxBufferState = kDllkTxBufEmpty; // mark Tx buffer as empty #if (CONFIG_EDRV_AUTO_RESPONSE != FALSE) if ((nmtState_p & (NMT_TYPE_MASK | NMT_SUPERSTATE_MASK)) == (NMT_TYPE_CS | NMT_CS_PLKMODE)) { // disable corresponding Rx filter dllkInstance_g.aFilter[filterEntry].fEnable = FALSE; ret = edrv_changeRxFilter(dllkInstance_g.aFilter, DLLK_FILTER_COUNT, filterEntry, EDRV_FILTER_CHANGE_STATE); if (ret != kErrorOk) goto Exit; } #endif } else { goto Exit; } } } if ((nmtState_p == kNmtCsBasicEthernet) || (nmtState_p == kNmtMsBasicEthernet)) { // send frame immediately if (pTxFrame != NULL) { // frame is present - padding is done by Edrv or ethernet controller *pTxBufferState = kDllkTxBufSending; ret = edrv_sendTxBuffer(pTxBuffer); } else { // no frame moved to TxBuffer // check if TxBuffers contain unsent frames if (dllkInstance_g.aTxBufferStateNmtReq[dllkInstance_g.curTxBufferOffsetNmtReq] == kDllkTxBufReady) { // NMT request Tx buffer contains a frame dllkInstance_g.aTxBufferStateNmtReq[dllkInstance_g.curTxBufferOffsetNmtReq] = kDllkTxBufSending; ret = edrv_sendTxBuffer(&dllkInstance_g.pTxBuffer[DLLK_TXFRAME_NMTREQ + dllkInstance_g.curTxBufferOffsetNmtReq]); } else if (dllkInstance_g.aTxBufferStateNonPlk[dllkInstance_g.curTxBufferOffsetNonPlk] == kDllkTxBufReady) { // non-POWERLINK Tx buffer contains a frame dllkInstance_g.aTxBufferStateNonPlk[dllkInstance_g.curTxBufferOffsetNonPlk] = kDllkTxBufSending; ret = edrv_sendTxBuffer(&dllkInstance_g.pTxBuffer[DLLK_TXFRAME_NONPLK + dllkInstance_g.curTxBufferOffsetNonPlk]); } if (ret == kErrorInvalidOperation) { // ignore error if caused by already active transmission ret = kErrorOk; } } dllkInstance_g.flag2 = 0; // reset PRes flag 2 } else { // update Flag 2 (PR, RS) ret = dllkcal_getAsyncTxCount(&asyncReqPriority_p, &frameCount); if (asyncReqPriority_p == kDllAsyncReqPrioNmt) { // non-empty FIFO with hightest priority is for NMT requests if (dllkInstance_g.aTxBufferStateNmtReq[dllkInstance_g.curTxBufferOffsetNmtReq] == kDllkTxBufReady) { // NMT request Tx buffer contains a frame // add one more frame frameCount++; } } else { // non-empty FIFO with highest priority is for generic frames if (dllkInstance_g.aTxBufferStateNmtReq[dllkInstance_g.curTxBufferOffsetNmtReq] == kDllkTxBufReady) { // NMT request Tx buffer contains a frame // use NMT request FIFO, because of higher priority frameCount = 1; asyncReqPriority_p = kDllAsyncReqPrioNmt; } else if (dllkInstance_g.aTxBufferStateNonPlk[dllkInstance_g.curTxBufferOffsetNonPlk] == kDllkTxBufReady) { // non-POWERLINK Tx buffer contains a frame // use NMT request FIFO, because of higher priority // add one more frame frameCount++; } } if (frameCount > 7) { // limit frame request to send counter to 7 frameCount = 7; } if (frameCount > 0) { dllkInstance_g.flag2 = (UINT8)(((asyncReqPriority_p << PLK_FRAME_FLAG2_PR_SHIFT) & PLK_FRAME_FLAG2_PR) | (frameCount & PLK_FRAME_FLAG2_RS)); } else { dllkInstance_g.flag2 = 0; } dllkInstance_g.updateTxFrame = DLLK_UPDATE_BOTH; } Exit: 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; }