| /******************************************************************************* |
| * Copyright (c) 2005 - 2015 ACIN, Profactor GmbH, fortiss GmbH |
| * This program and the accompanying materials are made available under the |
| * terms of the Eclipse Public License 2.0 which is available at |
| * http://www.eclipse.org/legal/epl-2.0. |
| * |
| * SPDX-License-Identifier: EPL-2.0 |
| * |
| * Contributors: |
| * Alois Zoitl, Rene Smodic, Thomas Strasser, Ingo Hegny |
| * - initial API and implementation and/or initial documentation |
| *******************************************************************************/ |
| #include "timerha.h" |
| #include "../core/datatypes/forte_time.h" |
| #include "../core/devexec.h" |
| #include "../core/esfb.h" |
| #include "../core/utils/criticalregion.h" |
| |
| DEFINE_HANDLER(CTimerHandler) |
| |
| CTimerHandler::CTimerHandler(CDeviceExecution& paDeviceExecution) : CExternalEventHandler(paDeviceExecution), |
| mForteTime(0), mTimedFBList(0){ |
| } |
| |
| CTimerHandler::~CTimerHandler(){ |
| } |
| |
| void CTimerHandler::registerTimedFB(STimedFBListEntry *paTimerListEntry, const CIEC_TIME &paTimeInterval) { |
| //calculate the correct interval based on time-base and timer ticks per seconds |
| paTimerListEntry->mInterval = static_cast<TForteUInt32>((paTimeInterval * getTicksPerSecond()) / cgForteTimeBaseUnitsPerSecond); |
| { |
| CCriticalRegion criticalRegion(mSync); |
| addTimedFBEntry(paTimerListEntry); |
| } |
| } |
| |
| void CTimerHandler::addTimedFBEntry(STimedFBListEntry *paTimerListEntry) { |
| paTimerListEntry->mTimeOut = mForteTime + paTimerListEntry->mInterval; // the next activation time of this FB |
| paTimerListEntry->mNext = 0; |
| |
| // Correct null intervals that can lead to event queue overflow to 10 ms |
| if(paTimerListEntry->mInterval == 0) { |
| paTimerListEntry->mTimeOut += (getTicksPerSecond() > 100) ? getTicksPerSecond() / 100 : 1; |
| } |
| if (0 == mTimedFBList) { |
| mTimedFBList = paTimerListEntry; |
| } else { |
| if (mTimedFBList->mTimeOut > paTimerListEntry->mTimeOut) { |
| paTimerListEntry->mNext = mTimedFBList; |
| mTimedFBList = paTimerListEntry; |
| } else { |
| STimedFBListEntry *runner = mTimedFBList; |
| while (0 != runner->mNext) { |
| if (runner->mNext->mTimeOut > paTimerListEntry->mTimeOut) { |
| paTimerListEntry->mNext = runner->mNext; |
| runner->mNext = paTimerListEntry; |
| break; |
| } |
| runner = runner->mNext; |
| } |
| runner->mNext = paTimerListEntry; |
| } |
| } |
| } |
| |
| void CTimerHandler::unregisterTimedFB(CEventSourceFB *paTimedFB) { |
| CCriticalRegion criticalRegion(mSync); |
| if (0 != mTimedFBList) { |
| STimedFBListEntry *buffer = 0; |
| if (mTimedFBList->mTimedFB == paTimedFB) { |
| buffer = mTimedFBList; |
| mTimedFBList = mTimedFBList->mNext; |
| buffer->mNext = 0; |
| buffer->mTimeOut = 0; |
| } else { |
| STimedFBListEntry *runner = mTimedFBList; |
| while (0 != runner->mNext) { |
| if (runner->mNext->mTimedFB == paTimedFB) { |
| buffer = runner->mNext; |
| runner->mNext = runner->mNext->mNext; |
| buffer->mNext = 0; |
| buffer->mTimeOut = 0; |
| break; |
| } |
| runner = runner->mNext; |
| } |
| } |
| } |
| } |
| |
| void CTimerHandler::nextTick(void) { |
| ++mForteTime; |
| mDeviceExecution.notifyTime(mForteTime); //notify the device execution that one tick passed by. |
| if(0 != mTimedFBList){ |
| //only check the list if there are entries in the list |
| CCriticalRegion criticalRegion(mSync); |
| while (0 != mTimedFBList) { |
| if (mTimedFBList->mTimeOut > mForteTime) { |
| break; |
| } |
| mDeviceExecution.startNewEventChain(mTimedFBList->mTimedFB); |
| STimedFBListEntry *buffer = mTimedFBList; |
| mTimedFBList = mTimedFBList->mNext; |
| |
| switch (buffer->mType) { |
| case e_Periodic: |
| addTimedFBEntry(buffer); //re-register the timed FB |
| break; |
| case e_SingleShot: |
| // nothing special is to do up to now |
| default: |
| buffer->mNext = 0; |
| buffer->mTimeOut = 0; |
| break; |
| } |
| } |
| } |
| } |
| |