blob: 78b47491868462d2962e8262c9944c99ce34c8c3 [file] [log] [blame]
/*******************************************************************************
* 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;
}
}
}
}