blob: f0a5299f391fc3de5789fad1ed2585a3605c0605 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2005 - 2015 ACIN, Profactor GmbH, fortiss GmbH
* 2020 Johannes Kepler University Linz
* 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
* Alois Zoitl - worked on reducing the jitter and overhead of timer handler
* Bug #568902
*******************************************************************************/
#include "timerha.h"
#include "../core/datatypes/forte_any_duration.h"
#include "../core/devexec.h"
#include "../core/esfb.h"
#include "../core/utils/criticalregion.h"
#include <algorithm>
#include <functional>
DEFINE_HANDLER(CTimerHandler)
CTimerHandler::CTimerHandler(CDeviceExecution& paDeviceExecution) : CExternalEventHandler(paDeviceExecution),
mForteTime(0) {
}
CTimerHandler::~CTimerHandler() = default;
void CTimerHandler::registerOneShotTimedFB(CEventSourceFB *const paTimedFB, const CIEC_TIME &paTimeInterval) {
TForteUInt32 interval = convertIntervalToTimerHandlerUnits(paTimeInterval);
addToAddFBList(STimedFBListEntry(paTimedFB, mForteTime + interval, scmOneShotIndicator));
}
void CTimerHandler::registerPeriodicTimedFB(CEventSourceFB *const paTimedFB, const CIEC_TIME &paTimeInterval) {
TForteUInt32 interval = convertIntervalToTimerHandlerUnits(paTimeInterval);
addToAddFBList(STimedFBListEntry(paTimedFB, mForteTime + interval, interval));
}
TForteUInt32 CTimerHandler::convertIntervalToTimerHandlerUnits(const CIEC_TIME &paTimeInterval){
CIEC_TIME::TValueType interval = static_cast<CIEC_TIME::TValueType>(paTimeInterval) / scmTimeToTimerUnit;
return interval > 0 ? static_cast<TForteUInt32>(interval) : 1U;
}
void CTimerHandler::addToAddFBList(const STimedFBListEntry& paTimerListEntry){
CCriticalRegion criticalRegion(mAddListSync);
mAddFBList.push_back(paTimerListEntry);
}
void CTimerHandler::addTimedFBEntry(const STimedFBListEntry& paTimerListEntry) {
auto it = std::lower_bound(mTimedFBList.begin(), mTimedFBList.end(), paTimerListEntry,
[](const STimedFBListEntry& entry1, const STimedFBListEntry& entry2) { return entry1.mTimeOut < entry2.mTimeOut; });
mTimedFBList.insert(it, paTimerListEntry);
}
void CTimerHandler::unregisterTimedFB(CEventSourceFB *paTimedFB) {
CCriticalRegion criticalRegion(mRemoveListSync);
mRemoveFBList.push_back(paTimedFB);
}
void CTimerHandler::removeTimedFB(CEventSourceFB *paTimedFB) {
auto it = std::remove_if(mTimedFBList.begin(), mTimedFBList.end(),
[&paTimedFB](const STimedFBListEntry& entry) { return entry.mTimedFB == paTimedFB; });
mTimedFBList.erase(it, mTimedFBList.end());
}
void CTimerHandler::nextTick() {
++mForteTime;
mDeviceExecution.notifyTime(mForteTime); //notify the device execution that one tick passed by.
if(!mRemoveFBList.empty()){
processRemoveList();
}
processTimedFBList();
if(!mAddFBList.empty()){
processAddList();
}
}
void CTimerHandler::processTimedFBList() {
for (auto it = mTimedFBList.begin(); it != mTimedFBList.end();) {
if (it->mTimeOut > mForteTime) {
break;
}
STimedFBListEntry entry = *it; // buffer entry
it = mTimedFBList.erase(it);
triggerTimedFB(entry);
}
}
void CTimerHandler::triggerTimedFB(STimedFBListEntry paTimerListEntry) {
mDeviceExecution.startNewEventChain(paTimerListEntry.mTimedFB);
if(paTimerListEntry.mInterval != scmOneShotIndicator){
paTimerListEntry.mTimeOut = mForteTime + paTimerListEntry.mInterval; // the next activation time of this FB
addTimedFBEntry(paTimerListEntry); //re-register the timed FB
}
}
void CTimerHandler::processAddList() {
CCriticalRegion criticalRegion(mAddListSync);
for (auto entry : mAddFBList) {
if(entry.mTimeOut < mForteTime) {
triggerTimedFB(entry);
} else {
addTimedFBEntry(entry);
}
}
mAddFBList.clear();
}
void CTimerHandler::processRemoveList() {
CCriticalRegion criticalRegion(mRemoveListSync);
std::for_each(mRemoveFBList.begin(), mRemoveFBList.end(), [this](CEventSourceFB *event) { removeTimedFB(event);} );
mRemoveFBList.clear();
}