added host osal #165

Merged
gaisser merged 10 commits from KSat/fsfw:mueller/hostosal into master 2020-09-15 15:33:53 +02:00
15 changed files with 1564 additions and 1564 deletions
Showing only changes of commit f13e7b4255 - Show all commits

View File

@ -1,227 +1,227 @@
#include <framework/serviceinterface/ServiceInterfaceStream.h> #include "../../serviceinterface/ServiceInterfaceStream.h"
#include <framework/timemanager/Clock.h> #include "../../timemanager/Clock.h"
#include <chrono> #include <chrono>
#if defined(WIN32) #if defined(WIN32)
#include <windows.h> #include <windows.h>
#elif defined(LINUX) #elif defined(LINUX)
#include <fstream> #include <fstream>
#endif #endif
uint16_t Clock::leapSeconds = 0; uint16_t Clock::leapSeconds = 0;
MutexIF* Clock::timeMutex = NULL; MutexIF* Clock::timeMutex = NULL;
using SystemClock = std::chrono::system_clock; using SystemClock = std::chrono::system_clock;
uint32_t Clock::getTicksPerSecond(void){ uint32_t Clock::getTicksPerSecond(void){
sif::warning << "Clock::getTicksPerSecond: not implemented yet" << std::endl; sif::warning << "Clock::getTicksPerSecond: not implemented yet" << std::endl;
return 0; return 0;
//return CLOCKS_PER_SEC; //return CLOCKS_PER_SEC;
//uint32_t ticks = sysconf(_SC_CLK_TCK); //uint32_t ticks = sysconf(_SC_CLK_TCK);
//return ticks; //return ticks;
} }
ReturnValue_t Clock::setClock(const TimeOfDay_t* time) { ReturnValue_t Clock::setClock(const TimeOfDay_t* time) {
// do some magic with chrono // do some magic with chrono
sif::warning << "Clock::setClock: not implemented yet" << std::endl; sif::warning << "Clock::setClock: not implemented yet" << std::endl;
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
} }
ReturnValue_t Clock::setClock(const timeval* time) { ReturnValue_t Clock::setClock(const timeval* time) {
// do some magic with chrono // do some magic with chrono
#if defined(WIN32) #if defined(WIN32)
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
#elif defined(LINUX) #elif defined(LINUX)
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
#else #else
#endif #endif
sif::warning << "Clock::getUptime: Not implemented for found OS" << std::endl; sif::warning << "Clock::getUptime: Not implemented for found OS" << std::endl;
return HasReturnvaluesIF::RETURN_FAILED; return HasReturnvaluesIF::RETURN_FAILED;
} }
ReturnValue_t Clock::getClock_timeval(timeval* time) { ReturnValue_t Clock::getClock_timeval(timeval* time) {
#if defined(WIN32) #if defined(WIN32)
auto now = std::chrono::system_clock::now(); auto now = std::chrono::system_clock::now();
auto secondsChrono = std::chrono::time_point_cast<std::chrono::seconds>(now); auto secondsChrono = std::chrono::time_point_cast<std::chrono::seconds>(now);
auto epoch = now.time_since_epoch(); auto epoch = now.time_since_epoch();
time->tv_sec = std::chrono::duration_cast<std::chrono::seconds>(epoch).count(); time->tv_sec = std::chrono::duration_cast<std::chrono::seconds>(epoch).count();
auto fraction = now - secondsChrono; auto fraction = now - secondsChrono;
time->tv_usec = std::chrono::duration_cast<std::chrono::microseconds>( time->tv_usec = std::chrono::duration_cast<std::chrono::microseconds>(
fraction).count(); fraction).count();
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
#elif defined(LINUX) #elif defined(LINUX)
timespec timeUnix; timespec timeUnix;
int status = clock_gettime(CLOCK_REALTIME,&timeUnix); int status = clock_gettime(CLOCK_REALTIME,&timeUnix);
if(status!=0){ if(status!=0){
return HasReturnvaluesIF::RETURN_FAILED; return HasReturnvaluesIF::RETURN_FAILED;
} }
time->tv_sec = timeUnix.tv_sec; time->tv_sec = timeUnix.tv_sec;
time->tv_usec = timeUnix.tv_nsec / 1000.0; time->tv_usec = timeUnix.tv_nsec / 1000.0;
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
#else #else
sif::warning << "Clock::getUptime: Not implemented for found OS" << std::endl; sif::warning << "Clock::getUptime: Not implemented for found OS" << std::endl;
return HasReturnvaluesIF::RETURN_FAILED; return HasReturnvaluesIF::RETURN_FAILED;
#endif #endif
} }
ReturnValue_t Clock::getClock_usecs(uint64_t* time) { ReturnValue_t Clock::getClock_usecs(uint64_t* time) {
// do some magic with chrono // do some magic with chrono
sif::warning << "Clock::gerClock_usecs: not implemented yet" << std::endl; sif::warning << "Clock::gerClock_usecs: not implemented yet" << std::endl;
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
} }
timeval Clock::getUptime() { timeval Clock::getUptime() {
timeval timeval; timeval timeval;
#if defined(WIN32) #if defined(WIN32)
auto uptime = std::chrono::milliseconds(GetTickCount64()); auto uptime = std::chrono::milliseconds(GetTickCount64());
auto secondsChrono = std::chrono::duration_cast<std::chrono::seconds>(uptime); auto secondsChrono = std::chrono::duration_cast<std::chrono::seconds>(uptime);
timeval.tv_sec = secondsChrono.count(); timeval.tv_sec = secondsChrono.count();
auto fraction = uptime - secondsChrono; auto fraction = uptime - secondsChrono;
timeval.tv_usec = std::chrono::duration_cast<std::chrono::microseconds>( timeval.tv_usec = std::chrono::duration_cast<std::chrono::microseconds>(
fraction).count(); fraction).count();
#elif defined(LINUX) #elif defined(LINUX)
double uptimeSeconds; double uptimeSeconds;
if (std::ifstream("/proc/uptime", std::ios::in) >> uptimeSeconds) if (std::ifstream("/proc/uptime", std::ios::in) >> uptimeSeconds)
{ {
// value is rounded down automatically // value is rounded down automatically
timeval.tv_sec = uptimeSeconds; timeval.tv_sec = uptimeSeconds;
timeval.tv_usec = uptimeSeconds *(double) 1e6 - (timeval.tv_sec *1e6); timeval.tv_usec = uptimeSeconds *(double) 1e6 - (timeval.tv_sec *1e6);
} }
#else #else
sif::warning << "Clock::getUptime: Not implemented for found OS" << std::endl; sif::warning << "Clock::getUptime: Not implemented for found OS" << std::endl;
#endif #endif
return timeval; return timeval;
} }
ReturnValue_t Clock::getUptime(timeval* uptime) { ReturnValue_t Clock::getUptime(timeval* uptime) {
*uptime = getUptime(); *uptime = getUptime();
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
} }
ReturnValue_t Clock::getUptime(uint32_t* uptimeMs) { ReturnValue_t Clock::getUptime(uint32_t* uptimeMs) {
timeval uptime = getUptime(); timeval uptime = getUptime();
*uptimeMs = uptime.tv_sec * 1000 + uptime.tv_usec / 1000; *uptimeMs = uptime.tv_sec * 1000 + uptime.tv_usec / 1000;
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
} }
ReturnValue_t Clock::getDateAndTime(TimeOfDay_t* time) { ReturnValue_t Clock::getDateAndTime(TimeOfDay_t* time) {
// do some magic with chrono (C++20!) // do some magic with chrono (C++20!)
// Right now, the library doesn't have the new features yet. // Right now, the library doesn't have the new features yet.
// so we work around that for now. // so we work around that for now.
auto now = SystemClock::now(); auto now = SystemClock::now();
auto seconds = std::chrono::time_point_cast<std::chrono::seconds>(now); auto seconds = std::chrono::time_point_cast<std::chrono::seconds>(now);
auto fraction = now - seconds; auto fraction = now - seconds;
time_t tt = SystemClock::to_time_t(now); time_t tt = SystemClock::to_time_t(now);
struct tm* timeInfo; struct tm* timeInfo;
timeInfo = gmtime(&tt); timeInfo = gmtime(&tt);
time->year = timeInfo->tm_year + 1900; time->year = timeInfo->tm_year + 1900;
time->month = timeInfo->tm_mon+1; time->month = timeInfo->tm_mon+1;
time->day = timeInfo->tm_mday; time->day = timeInfo->tm_mday;
time->hour = timeInfo->tm_hour; time->hour = timeInfo->tm_hour;
time->minute = timeInfo->tm_min; time->minute = timeInfo->tm_min;
time->second = timeInfo->tm_sec; time->second = timeInfo->tm_sec;
auto usecond = std::chrono::duration_cast<std::chrono::microseconds>(fraction); auto usecond = std::chrono::duration_cast<std::chrono::microseconds>(fraction);
time->usecond = usecond.count(); time->usecond = usecond.count();
//sif::warning << "Clock::getDateAndTime: not implemented yet" << std::endl; //sif::warning << "Clock::getDateAndTime: not implemented yet" << std::endl;
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
} }
ReturnValue_t Clock::convertTimeOfDayToTimeval(const TimeOfDay_t* from, ReturnValue_t Clock::convertTimeOfDayToTimeval(const TimeOfDay_t* from,
timeval* to) { timeval* to) {
struct tm time_tm; struct tm time_tm;
time_tm.tm_year = from->year - 1900; time_tm.tm_year = from->year - 1900;
time_tm.tm_mon = from->month - 1; time_tm.tm_mon = from->month - 1;
time_tm.tm_mday = from->day; time_tm.tm_mday = from->day;
time_tm.tm_hour = from->hour; time_tm.tm_hour = from->hour;
time_tm.tm_min = from->minute; time_tm.tm_min = from->minute;
time_tm.tm_sec = from->second; time_tm.tm_sec = from->second;
time_t seconds = mktime(&time_tm); time_t seconds = mktime(&time_tm);
to->tv_sec = seconds; to->tv_sec = seconds;
to->tv_usec = from->usecond; to->tv_usec = from->usecond;
//Fails in 2038.. //Fails in 2038..
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
sif::warning << "Clock::convertTimeBla: not implemented yet" << std::endl; sif::warning << "Clock::convertTimeBla: not implemented yet" << std::endl;
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
} }
ReturnValue_t Clock::convertTimevalToJD2000(timeval time, double* JD2000) { ReturnValue_t Clock::convertTimevalToJD2000(timeval time, double* JD2000) {
*JD2000 = (time.tv_sec - 946728000. + time.tv_usec / 1000000.) / 24. *JD2000 = (time.tv_sec - 946728000. + time.tv_usec / 1000000.) / 24.
/ 3600.; / 3600.;
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
} }
ReturnValue_t Clock::convertUTCToTT(timeval utc, timeval* tt) { ReturnValue_t Clock::convertUTCToTT(timeval utc, timeval* tt) {
//SHOULDDO: works not for dates in the past (might have less leap seconds) //SHOULDDO: works not for dates in the past (might have less leap seconds)
if (timeMutex == NULL) { if (timeMutex == NULL) {
return HasReturnvaluesIF::RETURN_FAILED; return HasReturnvaluesIF::RETURN_FAILED;
} }
uint16_t leapSeconds; uint16_t leapSeconds;
ReturnValue_t result = getLeapSeconds(&leapSeconds); ReturnValue_t result = getLeapSeconds(&leapSeconds);
if (result != HasReturnvaluesIF::RETURN_OK) { if (result != HasReturnvaluesIF::RETURN_OK) {
return result; return result;
} }
timeval leapSeconds_timeval = { 0, 0 }; timeval leapSeconds_timeval = { 0, 0 };
leapSeconds_timeval.tv_sec = leapSeconds; leapSeconds_timeval.tv_sec = leapSeconds;
//initial offset between UTC and TAI //initial offset between UTC and TAI
timeval UTCtoTAI1972 = { 10, 0 }; timeval UTCtoTAI1972 = { 10, 0 };
timeval TAItoTT = { 32, 184000 }; timeval TAItoTT = { 32, 184000 };
*tt = utc + leapSeconds_timeval + UTCtoTAI1972 + TAItoTT; *tt = utc + leapSeconds_timeval + UTCtoTAI1972 + TAItoTT;
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
} }
ReturnValue_t Clock::setLeapSeconds(const uint16_t leapSeconds_) { ReturnValue_t Clock::setLeapSeconds(const uint16_t leapSeconds_) {
if(checkOrCreateClockMutex()!=HasReturnvaluesIF::RETURN_OK){ if(checkOrCreateClockMutex()!=HasReturnvaluesIF::RETURN_OK){
return HasReturnvaluesIF::RETURN_FAILED; return HasReturnvaluesIF::RETURN_FAILED;
} }
ReturnValue_t result = timeMutex->lockMutex(MutexIF::BLOCKING); ReturnValue_t result = timeMutex->lockMutex(MutexIF::BLOCKING);
if (result != HasReturnvaluesIF::RETURN_OK) { if (result != HasReturnvaluesIF::RETURN_OK) {
return result; return result;
} }
leapSeconds = leapSeconds_; leapSeconds = leapSeconds_;
result = timeMutex->unlockMutex(); result = timeMutex->unlockMutex();
return result; return result;
} }
ReturnValue_t Clock::getLeapSeconds(uint16_t* leapSeconds_) { ReturnValue_t Clock::getLeapSeconds(uint16_t* leapSeconds_) {
if(timeMutex == nullptr){ if(timeMutex == nullptr){
return HasReturnvaluesIF::RETURN_FAILED; return HasReturnvaluesIF::RETURN_FAILED;
} }
ReturnValue_t result = timeMutex->lockMutex(MutexIF::BLOCKING); ReturnValue_t result = timeMutex->lockMutex(MutexIF::BLOCKING);
if (result != HasReturnvaluesIF::RETURN_OK) { if (result != HasReturnvaluesIF::RETURN_OK) {
return result; return result;
} }
*leapSeconds_ = leapSeconds; *leapSeconds_ = leapSeconds;
result = timeMutex->unlockMutex(); result = timeMutex->unlockMutex();
return result; return result;
} }
ReturnValue_t Clock::checkOrCreateClockMutex(){ ReturnValue_t Clock::checkOrCreateClockMutex(){
if(timeMutex == nullptr){ if(timeMutex == nullptr){
MutexFactory* mutexFactory = MutexFactory::instance(); MutexFactory* mutexFactory = MutexFactory::instance();
if (mutexFactory == nullptr) { if (mutexFactory == nullptr) {
return HasReturnvaluesIF::RETURN_FAILED; return HasReturnvaluesIF::RETURN_FAILED;
} }
timeMutex = mutexFactory->createMutex(); timeMutex = mutexFactory->createMutex();
if (timeMutex == nullptr) { if (timeMutex == nullptr) {
return HasReturnvaluesIF::RETURN_FAILED; return HasReturnvaluesIF::RETURN_FAILED;
} }
} }
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
} }

View File

@ -1,191 +1,191 @@
#include <framework/osal/host/FixedTimeslotTask.h> #include "../../osal/host/FixedTimeslotTask.h"
#include <framework/ipc/MutexFactory.h> #include "../../ipc/MutexFactory.h"
#include <framework/osal/host/Mutex.h> #include "../../osal/host/Mutex.h"
#include <framework/osal/host/FixedTimeslotTask.h> #include "../../osal/host/FixedTimeslotTask.h"
#include <framework/serviceinterface/ServiceInterfaceStream.h> #include "../../serviceinterface/ServiceInterfaceStream.h"
#include <framework/tasks/ExecutableObjectIF.h> #include "../../tasks/ExecutableObjectIF.h"
#include <thread> #include <thread>
#include <chrono> #include <chrono>
#if defined(WIN32) #if defined(WIN32)
#include <windows.h> #include <windows.h>
#elif defined(LINUX) #elif defined(LINUX)
#include <pthread.h> #include <pthread.h>
#endif #endif
FixedTimeslotTask::FixedTimeslotTask(const char *name, TaskPriority setPriority, FixedTimeslotTask::FixedTimeslotTask(const char *name, TaskPriority setPriority,
TaskStackSize setStack, TaskPeriod setPeriod, TaskStackSize setStack, TaskPeriod setPeriod,
void (*setDeadlineMissedFunc)()) : void (*setDeadlineMissedFunc)()) :
started(false), pollingSeqTable(setPeriod*1000), taskName(name), started(false), pollingSeqTable(setPeriod*1000), taskName(name),
period(setPeriod), deadlineMissedFunc(setDeadlineMissedFunc) { period(setPeriod), deadlineMissedFunc(setDeadlineMissedFunc) {
// It is propably possible to set task priorities by using the native // It is propably possible to set task priorities by using the native
// task handles for Windows / Linux // task handles for Windows / Linux
mainThread = std::thread(&FixedTimeslotTask::taskEntryPoint, this, this); mainThread = std::thread(&FixedTimeslotTask::taskEntryPoint, this, this);
#if defined(WIN32) #if defined(WIN32)
/* List of possible priority classes: /* List of possible priority classes:
* https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/ * https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/
* nf-processthreadsapi-setpriorityclass * nf-processthreadsapi-setpriorityclass
* And respective thread priority numbers: * And respective thread priority numbers:
* https://docs.microsoft.com/en-us/windows/ * https://docs.microsoft.com/en-us/windows/
* win32/procthread/scheduling-priorities */ * win32/procthread/scheduling-priorities */
int result = SetPriorityClass( int result = SetPriorityClass(
reinterpret_cast<HANDLE>(mainThread.native_handle()), reinterpret_cast<HANDLE>(mainThread.native_handle()),
ABOVE_NORMAL_PRIORITY_CLASS); ABOVE_NORMAL_PRIORITY_CLASS);
if(result != 0) { if(result != 0) {
sif::error << "FixedTimeslotTask: Windows SetPriorityClass failed with code " sif::error << "FixedTimeslotTask: Windows SetPriorityClass failed with code "
<< GetLastError() << std::endl; << GetLastError() << std::endl;
} }
result = SetThreadPriority( result = SetThreadPriority(
reinterpret_cast<HANDLE>(mainThread.native_handle()), reinterpret_cast<HANDLE>(mainThread.native_handle()),
THREAD_PRIORITY_NORMAL); THREAD_PRIORITY_NORMAL);
if(result != 0) { if(result != 0) {
sif::error << "FixedTimeslotTask: Windows SetPriorityClass failed with code " sif::error << "FixedTimeslotTask: Windows SetPriorityClass failed with code "
<< GetLastError() << std::endl; << GetLastError() << std::endl;
} }
#elif defined(LINUX) #elif defined(LINUX)
// we can just copy and paste the code from linux here. // we can just copy and paste the code from linux here.
#endif #endif
} }
FixedTimeslotTask::~FixedTimeslotTask(void) { FixedTimeslotTask::~FixedTimeslotTask(void) {
//Do not delete objects, we were responsible for ptrs only. //Do not delete objects, we were responsible for ptrs only.
terminateThread = true; terminateThread = true;
if(mainThread.joinable()) { if(mainThread.joinable()) {
mainThread.join(); mainThread.join();
} }
delete this; delete this;
} }
void FixedTimeslotTask::taskEntryPoint(void* argument) { void FixedTimeslotTask::taskEntryPoint(void* argument) {
FixedTimeslotTask *originalTask(reinterpret_cast<FixedTimeslotTask*>(argument)); FixedTimeslotTask *originalTask(reinterpret_cast<FixedTimeslotTask*>(argument));
if (not originalTask->started) { if (not originalTask->started) {
// we have to suspend/block here until the task is started. // we have to suspend/block here until the task is started.
// if semaphores are implemented, use them here. // if semaphores are implemented, use them here.
std::unique_lock<std::mutex> lock(initMutex); std::unique_lock<std::mutex> lock(initMutex);
initCondition.wait(lock); initCondition.wait(lock);
} }
this->taskFunctionality(); this->taskFunctionality();
sif::debug << "FixedTimeslotTask::taskEntryPoint: " sif::debug << "FixedTimeslotTask::taskEntryPoint: "
"Returned from taskFunctionality." << std::endl; "Returned from taskFunctionality." << std::endl;
} }
ReturnValue_t FixedTimeslotTask::startTask() { ReturnValue_t FixedTimeslotTask::startTask() {
started = true; started = true;
// Notify task to start. // Notify task to start.
std::lock_guard<std::mutex> lock(initMutex); std::lock_guard<std::mutex> lock(initMutex);
initCondition.notify_one(); initCondition.notify_one();
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
} }
ReturnValue_t FixedTimeslotTask::sleepFor(uint32_t ms) { ReturnValue_t FixedTimeslotTask::sleepFor(uint32_t ms) {
std::this_thread::sleep_for(std::chrono::milliseconds(ms)); std::this_thread::sleep_for(std::chrono::milliseconds(ms));
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
} }
void FixedTimeslotTask::taskFunctionality() { void FixedTimeslotTask::taskFunctionality() {
// A local iterator for the Polling Sequence Table is created to // A local iterator for the Polling Sequence Table is created to
// find the start time for the first entry. // find the start time for the first entry.
FixedSlotSequence::SlotListIter slotListIter = pollingSeqTable.current; FixedSlotSequence::SlotListIter slotListIter = pollingSeqTable.current;
// Get start time for first entry. // Get start time for first entry.
chron_ms interval(slotListIter->pollingTimeMs); chron_ms interval(slotListIter->pollingTimeMs);
auto currentStartTime { auto currentStartTime {
std::chrono::duration_cast<chron_ms>( std::chrono::duration_cast<chron_ms>(
std::chrono::system_clock::now().time_since_epoch()) std::chrono::system_clock::now().time_since_epoch())
}; };
if(interval.count() > 0) { if(interval.count() > 0) {
delayForInterval(&currentStartTime, interval); delayForInterval(&currentStartTime, interval);
} }
/* Enter the loop that defines the task behavior. */ /* Enter the loop that defines the task behavior. */
for (;;) { for (;;) {
if(terminateThread.load()) { if(terminateThread.load()) {
break; break;
} }
//The component for this slot is executed and the next one is chosen. //The component for this slot is executed and the next one is chosen.
this->pollingSeqTable.executeAndAdvance(); this->pollingSeqTable.executeAndAdvance();
if (not pollingSeqTable.slotFollowsImmediately()) { if (not pollingSeqTable.slotFollowsImmediately()) {
// we need to wait before executing the current slot // we need to wait before executing the current slot
//this gives us the time to wait: //this gives us the time to wait:
interval = chron_ms(this->pollingSeqTable.getIntervalToPreviousSlotMs()); interval = chron_ms(this->pollingSeqTable.getIntervalToPreviousSlotMs());
delayForInterval(&currentStartTime, interval); delayForInterval(&currentStartTime, interval);
//TODO deadline missed check //TODO deadline missed check
} }
} }
} }
ReturnValue_t FixedTimeslotTask::addSlot(object_id_t componentId, ReturnValue_t FixedTimeslotTask::addSlot(object_id_t componentId,
uint32_t slotTimeMs, int8_t executionStep) { uint32_t slotTimeMs, int8_t executionStep) {
if (objectManager->get<ExecutableObjectIF>(componentId) != nullptr) { if (objectManager->get<ExecutableObjectIF>(componentId) != nullptr) {
pollingSeqTable.addSlot(componentId, slotTimeMs, executionStep, this); pollingSeqTable.addSlot(componentId, slotTimeMs, executionStep, this);
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
} }
sif::error << "Component " << std::hex << componentId << sif::error << "Component " << std::hex << componentId <<
" not found, not adding it to pst" << std::endl; " not found, not adding it to pst" << std::endl;
return HasReturnvaluesIF::RETURN_FAILED; return HasReturnvaluesIF::RETURN_FAILED;
} }
ReturnValue_t FixedTimeslotTask::checkSequence() const { ReturnValue_t FixedTimeslotTask::checkSequence() const {
return pollingSeqTable.checkSequence(); return pollingSeqTable.checkSequence();
} }
uint32_t FixedTimeslotTask::getPeriodMs() const { uint32_t FixedTimeslotTask::getPeriodMs() const {
return period * 1000; return period * 1000;
} }
bool FixedTimeslotTask::delayForInterval(chron_ms * previousWakeTimeMs, bool FixedTimeslotTask::delayForInterval(chron_ms * previousWakeTimeMs,
const chron_ms interval) { const chron_ms interval) {
bool shouldDelay = false; bool shouldDelay = false;
//Get current wakeup time //Get current wakeup time
auto currentStartTime = auto currentStartTime =
std::chrono::duration_cast<chron_ms>( std::chrono::duration_cast<chron_ms>(
std::chrono::system_clock::now().time_since_epoch()); std::chrono::system_clock::now().time_since_epoch());
/* Generate the tick time at which the task wants to wake. */ /* Generate the tick time at which the task wants to wake. */
auto nextTimeToWake_ms = (*previousWakeTimeMs) + interval; auto nextTimeToWake_ms = (*previousWakeTimeMs) + interval;
if (currentStartTime < *previousWakeTimeMs) { if (currentStartTime < *previousWakeTimeMs) {
/* The tick count has overflowed since this function was /* The tick count has overflowed since this function was
lasted called. In this case the only time we should ever lasted called. In this case the only time we should ever
actually delay is if the wake time has also overflowed, actually delay is if the wake time has also overflowed,
and the wake time is greater than the tick time. When this and the wake time is greater than the tick time. When this
is the case it is as if neither time had overflowed. */ is the case it is as if neither time had overflowed. */
if ((nextTimeToWake_ms < *previousWakeTimeMs) if ((nextTimeToWake_ms < *previousWakeTimeMs)
&& (nextTimeToWake_ms > currentStartTime)) { && (nextTimeToWake_ms > currentStartTime)) {
shouldDelay = true; shouldDelay = true;
} }
} else { } else {
/* The tick time has not overflowed. In this case we will /* The tick time has not overflowed. In this case we will
delay if either the wake time has overflowed, and/or the delay if either the wake time has overflowed, and/or the
tick time is less than the wake time. */ tick time is less than the wake time. */
if ((nextTimeToWake_ms < *previousWakeTimeMs) if ((nextTimeToWake_ms < *previousWakeTimeMs)
|| (nextTimeToWake_ms > currentStartTime)) { || (nextTimeToWake_ms > currentStartTime)) {
shouldDelay = true; shouldDelay = true;
} }
} }
/* Update the wake time ready for the next call. */ /* Update the wake time ready for the next call. */
(*previousWakeTimeMs) = nextTimeToWake_ms; (*previousWakeTimeMs) = nextTimeToWake_ms;
if (shouldDelay) { if (shouldDelay) {
auto sleepTime = std::chrono::duration_cast<chron_ms>( auto sleepTime = std::chrono::duration_cast<chron_ms>(
nextTimeToWake_ms - currentStartTime); nextTimeToWake_ms - currentStartTime);
std::this_thread::sleep_for(sleepTime); std::this_thread::sleep_for(sleepTime);
return true; return true;
} }
//We are shifting the time in case the deadline was missed like rtems //We are shifting the time in case the deadline was missed like rtems
(*previousWakeTimeMs) = currentStartTime; (*previousWakeTimeMs) = currentStartTime;
return false; return false;
} }

View File

@ -1,130 +1,130 @@
#ifndef FRAMEWORK_OSAL_HOST_FIXEDTIMESLOTTASK_H_ #ifndef FRAMEWORK_OSAL_HOST_FIXEDTIMESLOTTASK_H_
#define FRAMEWORK_OSAL_HOST_FIXEDTIMESLOTTASK_H_ #define FRAMEWORK_OSAL_HOST_FIXEDTIMESLOTTASK_H_
#include <framework/objectmanager/ObjectManagerIF.h> #include "../../objectmanager/ObjectManagerIF.h"
#include <framework/tasks/FixedSlotSequence.h> #include "../../tasks/FixedSlotSequence.h"
#include <framework/tasks/FixedTimeslotTaskIF.h> #include "../../tasks/FixedTimeslotTaskIF.h"
#include <framework/tasks/Typedef.h> #include "../../tasks/Typedef.h"
#include <vector> #include <vector>
#include <thread> #include <thread>
#include <condition_variable> #include <condition_variable>
#include <atomic> #include <atomic>
class ExecutableObjectIF; class ExecutableObjectIF;
/** /**
* @brief This class represents a task for periodic activities with multiple * @brief This class represents a task for periodic activities with multiple
* steps and strict timeslot requirements for these steps. * steps and strict timeslot requirements for these steps.
* @details * @details
* @ingroup task_handling * @ingroup task_handling
*/ */
class FixedTimeslotTask: public FixedTimeslotTaskIF { class FixedTimeslotTask: public FixedTimeslotTaskIF {
public: public:
/** /**
* @brief Standard constructor of the class. * @brief Standard constructor of the class.
* @details * @details
* The class is initialized without allocated objects. These need to be * The class is initialized without allocated objects. These need to be
* added with #addComponent. * added with #addComponent.
* @param priority * @param priority
* @param stack_size * @param stack_size
* @param setPeriod * @param setPeriod
* @param setDeadlineMissedFunc * @param setDeadlineMissedFunc
* The function pointer to the deadline missed function that shall be * The function pointer to the deadline missed function that shall be
* assigned. * assigned.
*/ */
FixedTimeslotTask(const char *name, TaskPriority setPriority, FixedTimeslotTask(const char *name, TaskPriority setPriority,
TaskStackSize setStack, TaskPeriod setPeriod, TaskStackSize setStack, TaskPeriod setPeriod,
void (*setDeadlineMissedFunc)()); void (*setDeadlineMissedFunc)());
/** /**
* @brief Currently, the executed object's lifetime is not coupled with * @brief Currently, the executed object's lifetime is not coupled with
* the task object's lifetime, so the destructor is empty. * the task object's lifetime, so the destructor is empty.
*/ */
virtual ~FixedTimeslotTask(void); virtual ~FixedTimeslotTask(void);
/** /**
* @brief The method to start the task. * @brief The method to start the task.
* @details The method starts the task with the respective system call. * @details The method starts the task with the respective system call.
* Entry point is the taskEntryPoint method described below. * Entry point is the taskEntryPoint method described below.
* The address of the task object is passed as an argument * The address of the task object is passed as an argument
* to the system call. * to the system call.
*/ */
ReturnValue_t startTask(void); ReturnValue_t startTask(void);
/** /**
* Add timeslot to the polling sequence table. * Add timeslot to the polling sequence table.
* @param componentId * @param componentId
* @param slotTimeMs * @param slotTimeMs
* @param executionStep * @param executionStep
* @return * @return
*/ */
ReturnValue_t addSlot(object_id_t componentId, ReturnValue_t addSlot(object_id_t componentId,
uint32_t slotTimeMs, int8_t executionStep); uint32_t slotTimeMs, int8_t executionStep);
ReturnValue_t checkSequence() const; ReturnValue_t checkSequence() const;
uint32_t getPeriodMs() const; uint32_t getPeriodMs() const;
ReturnValue_t sleepFor(uint32_t ms); ReturnValue_t sleepFor(uint32_t ms);
protected: protected:
using chron_ms = std::chrono::milliseconds; using chron_ms = std::chrono::milliseconds;
bool started; bool started;
//!< Typedef for the List of objects. //!< Typedef for the List of objects.
typedef std::vector<ExecutableObjectIF*> ObjectList; typedef std::vector<ExecutableObjectIF*> ObjectList;
std::thread mainThread; std::thread mainThread;
std::atomic<bool> terminateThread = false; std::atomic<bool> terminateThread = false;
//! Polling sequence table which contains the object to execute //! Polling sequence table which contains the object to execute
//! and information like the timeslots and the passed execution step. //! and information like the timeslots and the passed execution step.
FixedSlotSequence pollingSeqTable; FixedSlotSequence pollingSeqTable;
std::condition_variable initCondition; std::condition_variable initCondition;
std::mutex initMutex; std::mutex initMutex;
std::string taskName; std::string taskName;
/** /**
* @brief The period of the task. * @brief The period of the task.
* @details * @details
* The period determines the frequency of the task's execution. * The period determines the frequency of the task's execution.
* It is expressed in clock ticks. * It is expressed in clock ticks.
*/ */
TaskPeriod period; TaskPeriod period;
/** /**
* @brief The pointer to the deadline-missed function. * @brief The pointer to the deadline-missed function.
* @details * @details
* This pointer stores the function that is executed if the task's deadline * This pointer stores the function that is executed if the task's deadline
* is missed. So, each may react individually on a timing failure. * is missed. So, each may react individually on a timing failure.
* The pointer may be NULL, then nothing happens on missing the deadline. * The pointer may be NULL, then nothing happens on missing the deadline.
* The deadline is equal to the next execution of the periodic task. * The deadline is equal to the next execution of the periodic task.
*/ */
void (*deadlineMissedFunc)(void); void (*deadlineMissedFunc)(void);
/** /**
* @brief This is the function executed in the new task's context. * @brief This is the function executed in the new task's context.
* @details * @details
* It converts the argument back to the thread object type and copies the * It converts the argument back to the thread object type and copies the
* class instance to the task context. * class instance to the task context.
* The taskFunctionality method is called afterwards. * The taskFunctionality method is called afterwards.
* @param A pointer to the task object itself is passed as argument. * @param A pointer to the task object itself is passed as argument.
*/ */
void taskEntryPoint(void* argument); void taskEntryPoint(void* argument);
/** /**
* @brief The function containing the actual functionality of the task. * @brief The function containing the actual functionality of the task.
* @details * @details
* The method sets and starts the task's period, then enters a loop that is * The method sets and starts the task's period, then enters a loop that is
* repeated as long as the isRunning attribute is true. Within the loop, * repeated as long as the isRunning attribute is true. Within the loop,
* all performOperation methods of the added objects are called. Afterwards * all performOperation methods of the added objects are called. Afterwards
* the checkAndRestartPeriod system call blocks the task until the next * the checkAndRestartPeriod system call blocks the task until the next
* period. On missing the deadline, the deadlineMissedFunction is executed. * period. On missing the deadline, the deadlineMissedFunction is executed.
*/ */
void taskFunctionality(void); void taskFunctionality(void);
bool delayForInterval(chron_ms * previousWakeTimeMs, bool delayForInterval(chron_ms * previousWakeTimeMs,
const chron_ms interval); const chron_ms interval);
}; };
#endif /* FRAMEWORK_OSAL_HOST_FIXEDTIMESLOTTASK_H_ */ #endif /* FRAMEWORK_OSAL_HOST_FIXEDTIMESLOTTASK_H_ */

View File

@ -1,155 +1,155 @@
#include <framework/osal/host/MessageQueue.h> #include "../../osal/host/MessageQueue.h"
#include <framework/serviceinterface/ServiceInterfaceStream.h> #include "../../serviceinterface/ServiceInterfaceStream.h"
#include <framework/osal/host/QueueMapManager.h> #include "../../osal/host/QueueMapManager.h"
#include <framework/ipc/MutexFactory.h> #include "../../ipc/MutexFactory.h"
#include <framework/ipc/MutexHelper.h> #include "../../ipc/MutexHelper.h"
MessageQueue::MessageQueue(size_t messageDepth, size_t maxMessageSize): MessageQueue::MessageQueue(size_t messageDepth, size_t maxMessageSize):
messageSize(maxMessageSize), messageDepth(messageDepth) { messageSize(maxMessageSize), messageDepth(messageDepth) {
queueLock = MutexFactory::instance()->createMutex(); queueLock = MutexFactory::instance()->createMutex();
auto result = QueueMapManager::instance()->addMessageQueue(this, &mqId); auto result = QueueMapManager::instance()->addMessageQueue(this, &mqId);
if(result != HasReturnvaluesIF::RETURN_OK) { if(result != HasReturnvaluesIF::RETURN_OK) {
sif::error << "MessageQueue: Could not be created" << std::endl; sif::error << "MessageQueue: Could not be created" << std::endl;
} }
} }
MessageQueue::~MessageQueue() { MessageQueue::~MessageQueue() {
MutexFactory::instance()->deleteMutex(queueLock); MutexFactory::instance()->deleteMutex(queueLock);
} }
ReturnValue_t MessageQueue::sendMessage(MessageQueueId_t sendTo, ReturnValue_t MessageQueue::sendMessage(MessageQueueId_t sendTo,
MessageQueueMessageIF* message, bool ignoreFault) { MessageQueueMessageIF* message, bool ignoreFault) {
return sendMessageFrom(sendTo, message, this->getId(), ignoreFault); return sendMessageFrom(sendTo, message, this->getId(), ignoreFault);
} }
ReturnValue_t MessageQueue::sendToDefault(MessageQueueMessageIF* message) { ReturnValue_t MessageQueue::sendToDefault(MessageQueueMessageIF* message) {
return sendToDefaultFrom(message, this->getId()); return sendToDefaultFrom(message, this->getId());
} }
ReturnValue_t MessageQueue::sendToDefaultFrom(MessageQueueMessageIF* message, ReturnValue_t MessageQueue::sendToDefaultFrom(MessageQueueMessageIF* message,
MessageQueueId_t sentFrom, bool ignoreFault) { MessageQueueId_t sentFrom, bool ignoreFault) {
return sendMessageFrom(defaultDestination,message,sentFrom,ignoreFault); return sendMessageFrom(defaultDestination,message,sentFrom,ignoreFault);
} }
ReturnValue_t MessageQueue::reply(MessageQueueMessageIF* message) { ReturnValue_t MessageQueue::reply(MessageQueueMessageIF* message) {
if (this->lastPartner != 0) { if (this->lastPartner != 0) {
return sendMessageFrom(this->lastPartner, message, this->getId()); return sendMessageFrom(this->lastPartner, message, this->getId());
} else { } else {
return MessageQueueIF::NO_REPLY_PARTNER; return MessageQueueIF::NO_REPLY_PARTNER;
} }
} }
ReturnValue_t MessageQueue::sendMessageFrom(MessageQueueId_t sendTo, ReturnValue_t MessageQueue::sendMessageFrom(MessageQueueId_t sendTo,
MessageQueueMessageIF* message, MessageQueueId_t sentFrom, MessageQueueMessageIF* message, MessageQueueId_t sentFrom,
bool ignoreFault) { bool ignoreFault) {
return sendMessageFromMessageQueue(sendTo, message, sentFrom, return sendMessageFromMessageQueue(sendTo, message, sentFrom,
ignoreFault); ignoreFault);
} }
ReturnValue_t MessageQueue::receiveMessage(MessageQueueMessageIF* message, ReturnValue_t MessageQueue::receiveMessage(MessageQueueMessageIF* message,
MessageQueueId_t* receivedFrom) { MessageQueueId_t* receivedFrom) {
ReturnValue_t status = this->receiveMessage(message); ReturnValue_t status = this->receiveMessage(message);
if(status == HasReturnvaluesIF::RETURN_OK) { if(status == HasReturnvaluesIF::RETURN_OK) {
*receivedFrom = this->lastPartner; *receivedFrom = this->lastPartner;
} }
return status; return status;
} }
ReturnValue_t MessageQueue::receiveMessage(MessageQueueMessageIF* message) { ReturnValue_t MessageQueue::receiveMessage(MessageQueueMessageIF* message) {
if(messageQueue.empty()) { if(messageQueue.empty()) {
return MessageQueueIF::EMPTY; return MessageQueueIF::EMPTY;
} }
// not sure this will work.. // not sure this will work..
//*message = std::move(messageQueue.front()); //*message = std::move(messageQueue.front());
MutexHelper mutexLock(queueLock, 20); MutexHelper mutexLock(queueLock, 20);
MessageQueueMessage* currentMessage = &messageQueue.front(); MessageQueueMessage* currentMessage = &messageQueue.front();
std::copy(currentMessage->getBuffer(), std::copy(currentMessage->getBuffer(),
currentMessage->getBuffer() + messageSize, message->getBuffer()); currentMessage->getBuffer() + messageSize, message->getBuffer());
messageQueue.pop(); messageQueue.pop();
// The last partner is the first uint32_t field in the message // The last partner is the first uint32_t field in the message
this->lastPartner = message->getSender(); this->lastPartner = message->getSender();
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
} }
MessageQueueId_t MessageQueue::getLastPartner() const { MessageQueueId_t MessageQueue::getLastPartner() const {
return lastPartner; return lastPartner;
} }
ReturnValue_t MessageQueue::flush(uint32_t* count) { ReturnValue_t MessageQueue::flush(uint32_t* count) {
*count = messageQueue.size(); *count = messageQueue.size();
// Clears the queue. // Clears the queue.
messageQueue = std::queue<MessageQueueMessage>(); messageQueue = std::queue<MessageQueueMessage>();
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
} }
MessageQueueId_t MessageQueue::getId() const { MessageQueueId_t MessageQueue::getId() const {
return mqId; return mqId;
} }
void MessageQueue::setDefaultDestination(MessageQueueId_t defaultDestination) { void MessageQueue::setDefaultDestination(MessageQueueId_t defaultDestination) {
defaultDestinationSet = true; defaultDestinationSet = true;
this->defaultDestination = defaultDestination; this->defaultDestination = defaultDestination;
} }
MessageQueueId_t MessageQueue::getDefaultDestination() const { MessageQueueId_t MessageQueue::getDefaultDestination() const {
return defaultDestination; return defaultDestination;
} }
bool MessageQueue::isDefaultDestinationSet() const { bool MessageQueue::isDefaultDestinationSet() const {
return defaultDestinationSet; return defaultDestinationSet;
} }
// static core function to send messages. // static core function to send messages.
ReturnValue_t MessageQueue::sendMessageFromMessageQueue(MessageQueueId_t sendTo, ReturnValue_t MessageQueue::sendMessageFromMessageQueue(MessageQueueId_t sendTo,
MessageQueueMessageIF* message, MessageQueueId_t sentFrom, MessageQueueMessageIF* message, MessageQueueId_t sentFrom,
bool ignoreFault) { bool ignoreFault) {
if(message->getMessageSize() > message->getMaximumMessageSize()) { if(message->getMessageSize() > message->getMaximumMessageSize()) {
// Actually, this should never happen or an error will be emitted // Actually, this should never happen or an error will be emitted
// in MessageQueueMessage. // in MessageQueueMessage.
// But I will still return a failure here. // But I will still return a failure here.
return HasReturnvaluesIF::RETURN_FAILED; return HasReturnvaluesIF::RETURN_FAILED;
} }
MessageQueue* targetQueue = dynamic_cast<MessageQueue*>( MessageQueue* targetQueue = dynamic_cast<MessageQueue*>(
QueueMapManager::instance()->getMessageQueue(sendTo)); QueueMapManager::instance()->getMessageQueue(sendTo));
if(targetQueue == nullptr) { if(targetQueue == nullptr) {
if(not ignoreFault) { if(not ignoreFault) {
InternalErrorReporterIF* internalErrorReporter = InternalErrorReporterIF* internalErrorReporter =
objectManager->get<InternalErrorReporterIF>( objectManager->get<InternalErrorReporterIF>(
objects::INTERNAL_ERROR_REPORTER); objects::INTERNAL_ERROR_REPORTER);
if (internalErrorReporter != nullptr) { if (internalErrorReporter != nullptr) {
internalErrorReporter->queueMessageNotSent(); internalErrorReporter->queueMessageNotSent();
} }
} }
// TODO: Better returnvalue // TODO: Better returnvalue
return HasReturnvaluesIF::RETURN_FAILED; return HasReturnvaluesIF::RETURN_FAILED;
} }
if(targetQueue->messageQueue.size() < targetQueue->messageDepth) { if(targetQueue->messageQueue.size() < targetQueue->messageDepth) {
MutexHelper mutexLock(targetQueue->queueLock, 20); MutexHelper mutexLock(targetQueue->queueLock, 20);
// not ideal, works for now though. // not ideal, works for now though.
MessageQueueMessage* mqmMessage = MessageQueueMessage* mqmMessage =
dynamic_cast<MessageQueueMessage*>(message); dynamic_cast<MessageQueueMessage*>(message);
if(message != nullptr) { if(message != nullptr) {
targetQueue->messageQueue.push(*mqmMessage); targetQueue->messageQueue.push(*mqmMessage);
} }
else { else {
sif::error << "MessageQueue::sendMessageFromMessageQueue: Message" sif::error << "MessageQueue::sendMessageFromMessageQueue: Message"
"is not MessageQueueMessage!" << std::endl; "is not MessageQueueMessage!" << std::endl;
} }
} }
else { else {
return MessageQueueIF::FULL; return MessageQueueIF::FULL;
} }
message->setSender(sentFrom); message->setSender(sentFrom);
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
} }
ReturnValue_t MessageQueue::lockQueue(dur_millis_t lockTimeout) { ReturnValue_t MessageQueue::lockQueue(dur_millis_t lockTimeout) {
return queueLock->lockMutex(lockTimeout); return queueLock->lockMutex(lockTimeout);
} }
ReturnValue_t MessageQueue::unlockQueue() { ReturnValue_t MessageQueue::unlockQueue() {
return queueLock->unlockMutex(); return queueLock->unlockMutex();
} }

View File

@ -1,230 +1,230 @@
#ifndef FRAMEWORK_OSAL_HOST_MESSAGEQUEUE_H_ #ifndef FRAMEWORK_OSAL_HOST_MESSAGEQUEUE_H_
#define FRAMEWORK_OSAL_HOST_MESSAGEQUEUE_H_ #define FRAMEWORK_OSAL_HOST_MESSAGEQUEUE_H_
#include <framework/internalError/InternalErrorReporterIF.h> #include "../../internalError/InternalErrorReporterIF.h"
#include <framework/ipc/MessageQueueIF.h> #include "../../ipc/MessageQueueIF.h"
#include <framework/ipc/MessageQueueMessage.h> #include "../../ipc/MessageQueueMessage.h"
#include <framework/ipc/MutexIF.h> #include "../../ipc/MutexIF.h"
#include <framework/timemanager/Clock.h> #include "../../timemanager/Clock.h"
#include <queue> #include <queue>
#include <memory> #include <memory>
/** /**
* @brief This class manages sending and receiving of * @brief This class manages sending and receiving of
* message queue messages. * message queue messages.
* @details * @details
* Message queues are used to pass asynchronous messages between processes. * Message queues are used to pass asynchronous messages between processes.
* They work like post boxes, where all incoming messages are stored in FIFO * They work like post boxes, where all incoming messages are stored in FIFO
* order. This class creates a new receiving queue and provides methods to fetch * order. This class creates a new receiving queue and provides methods to fetch
* received messages. Being a child of MessageQueueSender, this class also * received messages. Being a child of MessageQueueSender, this class also
* provides methods to send a message to a user-defined or a default destination. * provides methods to send a message to a user-defined or a default destination.
* In addition it also provides a reply method to answer to the queue it * In addition it also provides a reply method to answer to the queue it
* received its last message from. * received its last message from.
* *
* The MessageQueue should be used as "post box" for a single owning object. * The MessageQueue should be used as "post box" for a single owning object.
* So all message queue communication is "n-to-one". * So all message queue communication is "n-to-one".
* For creating the queue, as well as sending and receiving messages, the class * For creating the queue, as well as sending and receiving messages, the class
* makes use of the operating system calls provided. * makes use of the operating system calls provided.
* *
* Please keep in mind that FreeRTOS offers different calls for message queue * Please keep in mind that FreeRTOS offers different calls for message queue
* operations if called from an ISR. * operations if called from an ISR.
* For now, the system context needs to be switched manually. * For now, the system context needs to be switched manually.
* @ingroup osal * @ingroup osal
* @ingroup message_queue * @ingroup message_queue
*/ */
class MessageQueue : public MessageQueueIF { class MessageQueue : public MessageQueueIF {
friend class MessageQueueSenderIF; friend class MessageQueueSenderIF;
public: public:
/** /**
* @brief The constructor initializes and configures the message queue. * @brief The constructor initializes and configures the message queue.
* @details * @details
* By making use of the according operating system call, a message queue is * By making use of the according operating system call, a message queue is
* created and initialized. The message depth - the maximum number of * created and initialized. The message depth - the maximum number of
* messages to be buffered - may be set with the help of a parameter, * messages to be buffered - may be set with the help of a parameter,
* whereas the message size is automatically set to the maximum message * whereas the message size is automatically set to the maximum message
* queue message size. The operating system sets the message queue id, or * queue message size. The operating system sets the message queue id, or
* in case of failure, it is set to zero. * in case of failure, it is set to zero.
* @param message_depth * @param message_depth
* The number of messages to be buffered before passing an error to the * The number of messages to be buffered before passing an error to the
* sender. Default is three. * sender. Default is three.
* @param max_message_size * @param max_message_size
* With this parameter, the maximum message size can be adjusted. * With this parameter, the maximum message size can be adjusted.
* This should be left default. * This should be left default.
*/ */
MessageQueue(size_t messageDepth = 3, MessageQueue(size_t messageDepth = 3,
size_t maxMessageSize = MessageQueueMessage::MAX_MESSAGE_SIZE); size_t maxMessageSize = MessageQueueMessage::MAX_MESSAGE_SIZE);
/** Copying message queues forbidden */ /** Copying message queues forbidden */
MessageQueue(const MessageQueue&) = delete; MessageQueue(const MessageQueue&) = delete;
MessageQueue& operator=(const MessageQueue&) = delete; MessageQueue& operator=(const MessageQueue&) = delete;
/** /**
* @brief The destructor deletes the formerly created message queue. * @brief The destructor deletes the formerly created message queue.
* @details This is accomplished by using the delete call provided * @details This is accomplished by using the delete call provided
* by the operating system. * by the operating system.
*/ */
virtual ~MessageQueue(); virtual ~MessageQueue();
/** /**
* @brief This operation sends a message to the given destination. * @brief This operation sends a message to the given destination.
* @details It directly uses the sendMessage call of the MessageQueueSender * @details It directly uses the sendMessage call of the MessageQueueSender
* parent, but passes its queue id as "sentFrom" parameter. * parent, but passes its queue id as "sentFrom" parameter.
* @param sendTo This parameter specifies the message queue id of the * @param sendTo This parameter specifies the message queue id of the
* destination message queue. * destination message queue.
* @param message A pointer to a previously created message, which is sent. * @param message A pointer to a previously created message, which is sent.
* @param ignoreFault If set to true, the internal software fault counter * @param ignoreFault If set to true, the internal software fault counter
* is not incremented if queue is full. * is not incremented if queue is full.
*/ */
ReturnValue_t sendMessage(MessageQueueId_t sendTo, ReturnValue_t sendMessage(MessageQueueId_t sendTo,
MessageQueueMessageIF* message, bool ignoreFault = false) override; MessageQueueMessageIF* message, bool ignoreFault = false) override;
/** /**
* @brief This operation sends a message to the default destination. * @brief This operation sends a message to the default destination.
* @details As in the sendMessage method, this function uses the * @details As in the sendMessage method, this function uses the
* sendToDefault call of the MessageQueueSender parent class and adds its * sendToDefault call of the MessageQueueSender parent class and adds its
* queue id as "sentFrom" information. * queue id as "sentFrom" information.
* @param message A pointer to a previously created message, which is sent. * @param message A pointer to a previously created message, which is sent.
*/ */
ReturnValue_t sendToDefault(MessageQueueMessageIF* message) override; ReturnValue_t sendToDefault(MessageQueueMessageIF* message) override;
/** /**
* @brief This operation sends a message to the last communication partner. * @brief This operation sends a message to the last communication partner.
* @details This operation simplifies answering an incoming message by using * @details This operation simplifies answering an incoming message by using
* the stored lastPartner information as destination. If there was no * the stored lastPartner information as destination. If there was no
* message received yet (i.e. lastPartner is zero), an error code is returned. * message received yet (i.e. lastPartner is zero), an error code is returned.
* @param message A pointer to a previously created message, which is sent. * @param message A pointer to a previously created message, which is sent.
*/ */
ReturnValue_t reply(MessageQueueMessageIF* message) override; ReturnValue_t reply(MessageQueueMessageIF* message) override;
/** /**
* @brief With the sendMessage call, a queue message is sent to a * @brief With the sendMessage call, a queue message is sent to a
* receiving queue. * receiving queue.
* @details * @details
* This method takes the message provided, adds the sentFrom information and * This method takes the message provided, adds the sentFrom information and
* passes it on to the destination provided with an operating system call. * passes it on to the destination provided with an operating system call.
* The OS's return value is returned. * The OS's return value is returned.
* @param sendTo This parameter specifies the message queue id to send * @param sendTo This parameter specifies the message queue id to send
* the message to. * the message to.
* @param message This is a pointer to a previously created message, * @param message This is a pointer to a previously created message,
* which is sent. * which is sent.
* @param sentFrom The sentFrom information can be set to inject the * @param sentFrom The sentFrom information can be set to inject the
* sender's queue id into the message. This variable is set to zero by * sender's queue id into the message. This variable is set to zero by
* default. * default.
* @param ignoreFault If set to true, the internal software fault counter * @param ignoreFault If set to true, the internal software fault counter
* is not incremented if queue is full. * is not incremented if queue is full.
*/ */
virtual ReturnValue_t sendMessageFrom( MessageQueueId_t sendTo, virtual ReturnValue_t sendMessageFrom( MessageQueueId_t sendTo,
MessageQueueMessageIF* message, MessageQueueId_t sentFrom = NO_QUEUE, MessageQueueMessageIF* message, MessageQueueId_t sentFrom = NO_QUEUE,
bool ignoreFault = false) override; bool ignoreFault = false) override;
/** /**
* @brief The sendToDefault method sends a queue message to the default * @brief The sendToDefault method sends a queue message to the default
* destination. * destination.
* @details * @details
* In all other aspects, it works identical to the sendMessage method. * In all other aspects, it works identical to the sendMessage method.
* @param message This is a pointer to a previously created message, * @param message This is a pointer to a previously created message,
* which is sent. * which is sent.
* @param sentFrom The sentFrom information can be set to inject the * @param sentFrom The sentFrom information can be set to inject the
* sender's queue id into the message. This variable is set to zero by * sender's queue id into the message. This variable is set to zero by
* default. * default.
*/ */
virtual ReturnValue_t sendToDefaultFrom( MessageQueueMessageIF* message, virtual ReturnValue_t sendToDefaultFrom( MessageQueueMessageIF* message,
MessageQueueId_t sentFrom = NO_QUEUE, MessageQueueId_t sentFrom = NO_QUEUE,
bool ignoreFault = false) override; bool ignoreFault = false) override;
/** /**
* @brief This function reads available messages from the message queue * @brief This function reads available messages from the message queue
* and returns the sender. * and returns the sender.
* @details * @details
* It works identically to the other receiveMessage call, but in addition * It works identically to the other receiveMessage call, but in addition
* returns the sender's queue id. * returns the sender's queue id.
* @param message A pointer to a message in which the received data is stored. * @param message A pointer to a message in which the received data is stored.
* @param receivedFrom A pointer to a queue id in which the sender's id is stored. * @param receivedFrom A pointer to a queue id in which the sender's id is stored.
*/ */
ReturnValue_t receiveMessage(MessageQueueMessageIF* message, ReturnValue_t receiveMessage(MessageQueueMessageIF* message,
MessageQueueId_t *receivedFrom) override; MessageQueueId_t *receivedFrom) override;
/** /**
* @brief This function reads available messages from the message queue. * @brief This function reads available messages from the message queue.
* @details * @details
* If data is available it is stored in the passed message pointer. * If data is available it is stored in the passed message pointer.
* The message's original content is overwritten and the sendFrom * The message's original content is overwritten and the sendFrom
* information is stored in the lastPartner attribute. Else, the lastPartner * information is stored in the lastPartner attribute. Else, the lastPartner
* information remains untouched, the message's content is cleared and the * information remains untouched, the message's content is cleared and the
* function returns immediately. * function returns immediately.
* @param message A pointer to a message in which the received data is stored. * @param message A pointer to a message in which the received data is stored.
*/ */
ReturnValue_t receiveMessage(MessageQueueMessageIF* message) override; ReturnValue_t receiveMessage(MessageQueueMessageIF* message) override;
/** /**
* Deletes all pending messages in the queue. * Deletes all pending messages in the queue.
* @param count The number of flushed messages. * @param count The number of flushed messages.
* @return RETURN_OK on success. * @return RETURN_OK on success.
*/ */
ReturnValue_t flush(uint32_t* count) override; ReturnValue_t flush(uint32_t* count) override;
/** /**
* @brief This method returns the message queue id of the last * @brief This method returns the message queue id of the last
* communication partner. * communication partner.
*/ */
MessageQueueId_t getLastPartner() const override; MessageQueueId_t getLastPartner() const override;
/** /**
* @brief This method returns the message queue id of this class's * @brief This method returns the message queue id of this class's
* message queue. * message queue.
*/ */
MessageQueueId_t getId() const override; MessageQueueId_t getId() const override;
/** /**
* @brief This method is a simple setter for the default destination. * @brief This method is a simple setter for the default destination.
*/ */
void setDefaultDestination(MessageQueueId_t defaultDestination) override; void setDefaultDestination(MessageQueueId_t defaultDestination) override;
/** /**
* @brief This method is a simple getter for the default destination. * @brief This method is a simple getter for the default destination.
*/ */
MessageQueueId_t getDefaultDestination() const override; MessageQueueId_t getDefaultDestination() const override;
bool isDefaultDestinationSet() const override; bool isDefaultDestinationSet() const override;
ReturnValue_t lockQueue(dur_millis_t lockTimeout); ReturnValue_t lockQueue(dur_millis_t lockTimeout);
ReturnValue_t unlockQueue(); ReturnValue_t unlockQueue();
protected: protected:
/** /**
* @brief Implementation to be called from any send Call within * @brief Implementation to be called from any send Call within
* MessageQueue and MessageQueueSenderIF. * MessageQueue and MessageQueueSenderIF.
* @details * @details
* This method takes the message provided, adds the sentFrom information and * This method takes the message provided, adds the sentFrom information and
* passes it on to the destination provided with an operating system call. * passes it on to the destination provided with an operating system call.
* The OS's return value is returned. * The OS's return value is returned.
* @param sendTo * @param sendTo
* This parameter specifies the message queue id to send the message to. * This parameter specifies the message queue id to send the message to.
* @param message * @param message
* This is a pointer to a previously created message, which is sent. * This is a pointer to a previously created message, which is sent.
* @param sentFrom * @param sentFrom
* The sentFrom information can be set to inject the sender's queue id into * The sentFrom information can be set to inject the sender's queue id into
* the message. This variable is set to zero by default. * the message. This variable is set to zero by default.
* @param ignoreFault * @param ignoreFault
* If set to true, the internal software fault counter is not incremented * If set to true, the internal software fault counter is not incremented
* if queue is full. * if queue is full.
* @param context Specify whether call is made from task or from an ISR. * @param context Specify whether call is made from task or from an ISR.
*/ */
static ReturnValue_t sendMessageFromMessageQueue(MessageQueueId_t sendTo, static ReturnValue_t sendMessageFromMessageQueue(MessageQueueId_t sendTo,
MessageQueueMessageIF* message, MessageQueueId_t sentFrom = NO_QUEUE, MessageQueueMessageIF* message, MessageQueueId_t sentFrom = NO_QUEUE,
bool ignoreFault=false); bool ignoreFault=false);
//static ReturnValue_t handleSendResult(BaseType_t result, bool ignoreFault); //static ReturnValue_t handleSendResult(BaseType_t result, bool ignoreFault);
private: private:
std::queue<MessageQueueMessage> messageQueue; std::queue<MessageQueueMessage> messageQueue;
/** /**
* @brief The class stores the queue id it got assigned. * @brief The class stores the queue id it got assigned.
* If initialization fails, the queue id is set to zero. * If initialization fails, the queue id is set to zero.
*/ */
MessageQueueId_t mqId = 0; MessageQueueId_t mqId = 0;
size_t messageSize = 0; size_t messageSize = 0;
size_t messageDepth = 0; size_t messageDepth = 0;
MutexIF* queueLock; MutexIF* queueLock;
bool defaultDestinationSet = false; bool defaultDestinationSet = false;
MessageQueueId_t defaultDestination = 0; MessageQueueId_t defaultDestination = 0;
MessageQueueId_t lastPartner = 0; MessageQueueId_t lastPartner = 0;
}; };
#endif /* FRAMEWORK_OSAL_HOST_MESSAGEQUEUE_H_ */ #endif /* FRAMEWORK_OSAL_HOST_MESSAGEQUEUE_H_ */

View File

@ -1,40 +1,40 @@
#include <framework/osal/host/Mutex.h> #include "../../osal/host/Mutex.h"
#include <framework/serviceinterface/ServiceInterfaceStream.h> #include "../../serviceinterface/ServiceInterfaceStream.h"
const uint32_t MutexIF::POLLING = 0; const uint32_t MutexIF::POLLING = 0;
const uint32_t MutexIF::BLOCKING = 0xffffffff; const uint32_t MutexIF::BLOCKING = 0xffffffff;
ReturnValue_t Mutex::lockMutex(uint32_t timeoutMs) { ReturnValue_t Mutex::lockMutex(uint32_t timeoutMs) {
if(timeoutMs == MutexIF::BLOCKING) { if(timeoutMs == MutexIF::BLOCKING) {
mutex.lock(); mutex.lock();
locked = true; locked = true;
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
} }
else if(timeoutMs == MutexIF::POLLING) { else if(timeoutMs == MutexIF::POLLING) {
if(mutex.try_lock()) { if(mutex.try_lock()) {
locked = true; locked = true;
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
} }
} }
else if(timeoutMs > MutexIF::POLLING){ else if(timeoutMs > MutexIF::POLLING){
auto chronoMs = std::chrono::milliseconds(timeoutMs); auto chronoMs = std::chrono::milliseconds(timeoutMs);
if(mutex.try_lock_for(chronoMs)) { if(mutex.try_lock_for(chronoMs)) {
locked = true; locked = true;
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
} }
} }
return MutexIF::MUTEX_TIMEOUT; return MutexIF::MUTEX_TIMEOUT;
} }
ReturnValue_t Mutex::unlockMutex() { ReturnValue_t Mutex::unlockMutex() {
if(not locked) { if(not locked) {
return MutexIF::CURR_THREAD_DOES_NOT_OWN_MUTEX; return MutexIF::CURR_THREAD_DOES_NOT_OWN_MUTEX;
} }
mutex.unlock(); mutex.unlock();
locked = false; locked = false;
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
} }
std::timed_mutex* Mutex::getMutexHandle() { std::timed_mutex* Mutex::getMutexHandle() {
return &mutex; return &mutex;
} }

View File

@ -1,28 +1,28 @@
#ifndef FRAMEWORK_OSAL_FREERTOS_MUTEX_H_ #ifndef FRAMEWORK_OSAL_FREERTOS_MUTEX_H_
#define FRAMEWORK_OSAL_FREERTOS_MUTEX_H_ #define FRAMEWORK_OSAL_FREERTOS_MUTEX_H_
#include <framework/ipc/MutexIF.h> #include "../../ipc/MutexIF.h"
#include <mutex> #include <mutex>
/** /**
* @brief OS component to implement MUTual EXclusion * @brief OS component to implement MUTual EXclusion
* *
* @details * @details
* Mutexes are binary semaphores which include a priority inheritance mechanism. * Mutexes are binary semaphores which include a priority inheritance mechanism.
* Documentation: https://www.freertos.org/Real-time-embedded-RTOS-mutexes.html * Documentation: https://www.freertos.org/Real-time-embedded-RTOS-mutexes.html
* @ingroup osal * @ingroup osal
*/ */
class Mutex : public MutexIF { class Mutex : public MutexIF {
public: public:
Mutex() = default; Mutex() = default;
ReturnValue_t lockMutex(uint32_t timeoutMs = MutexIF::BLOCKING) override; ReturnValue_t lockMutex(uint32_t timeoutMs = MutexIF::BLOCKING) override;
ReturnValue_t unlockMutex() override; ReturnValue_t unlockMutex() override;
std::timed_mutex* getMutexHandle(); std::timed_mutex* getMutexHandle();
private: private:
bool locked = false; bool locked = false;
std::timed_mutex mutex; std::timed_mutex mutex;
}; };
#endif /* FRAMEWORK_FREERTOS_MUTEX_H_ */ #endif /* FRAMEWORK_FREERTOS_MUTEX_H_ */

View File

@ -1,28 +1,28 @@
#include <framework/ipc/MutexFactory.h> #include "../../ipc/MutexFactory.h"
#include <framework/osal/host/Mutex.h> #include "../../osal/host/Mutex.h"
//TODO: Different variant than the lazy loading in QueueFactory. //TODO: Different variant than the lazy loading in QueueFactory.
//What's better and why? -> one is on heap the other on bss/data //What's better and why? -> one is on heap the other on bss/data
//MutexFactory* MutexFactory::factoryInstance = new MutexFactory(); //MutexFactory* MutexFactory::factoryInstance = new MutexFactory();
MutexFactory* MutexFactory::factoryInstance = nullptr; MutexFactory* MutexFactory::factoryInstance = nullptr;
MutexFactory::MutexFactory() { MutexFactory::MutexFactory() {
} }
MutexFactory::~MutexFactory() { MutexFactory::~MutexFactory() {
} }
MutexFactory* MutexFactory::instance() { MutexFactory* MutexFactory::instance() {
if (factoryInstance == nullptr){ if (factoryInstance == nullptr){
factoryInstance = new MutexFactory(); factoryInstance = new MutexFactory();
} }
return MutexFactory::factoryInstance; return MutexFactory::factoryInstance;
} }
MutexIF* MutexFactory::createMutex() { MutexIF* MutexFactory::createMutex() {
return new Mutex(); return new Mutex();
} }
void MutexFactory::deleteMutex(MutexIF* mutex) { void MutexFactory::deleteMutex(MutexIF* mutex) {
delete mutex; delete mutex;
} }

View File

@ -1,176 +1,176 @@
#include <framework/ipc/MutexFactory.h> #include "../../ipc/MutexFactory.h"
#include <framework/osal/host/Mutex.h> #include "../../osal/host/Mutex.h"
#include <framework/osal/host/PeriodicTask.h> #include "../../osal/host/PeriodicTask.h"
#include <framework/serviceinterface/ServiceInterfaceStream.h> #include "../../serviceinterface/ServiceInterfaceStream.h"
#include <framework/tasks/ExecutableObjectIF.h> #include "../../tasks/ExecutableObjectIF.h"
#include <thread> #include <thread>
#include <chrono> #include <chrono>
#if defined(WIN32) #if defined(WIN32)
#include <windows.h> #include <windows.h>
#elif defined(LINUX) #elif defined(LINUX)
#include <pthread.h> #include <pthread.h>
#endif #endif
PeriodicTask::PeriodicTask(const char *name, TaskPriority setPriority, PeriodicTask::PeriodicTask(const char *name, TaskPriority setPriority,
TaskStackSize setStack, TaskPeriod setPeriod, TaskStackSize setStack, TaskPeriod setPeriod,
void (*setDeadlineMissedFunc)()) : void (*setDeadlineMissedFunc)()) :
started(false), taskName(name), period(setPeriod), started(false), taskName(name), period(setPeriod),
deadlineMissedFunc(setDeadlineMissedFunc) { deadlineMissedFunc(setDeadlineMissedFunc) {
// It is propably possible to set task priorities by using the native // It is propably possible to set task priorities by using the native
// task handles for Windows / Linux // task handles for Windows / Linux
mainThread = std::thread(&PeriodicTask::taskEntryPoint, this, this); mainThread = std::thread(&PeriodicTask::taskEntryPoint, this, this);
#if defined(WIN32) #if defined(WIN32)
/* List of possible priority classes: /* List of possible priority classes:
* https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/ * https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/
* nf-processthreadsapi-setpriorityclass * nf-processthreadsapi-setpriorityclass
* And respective thread priority numbers: * And respective thread priority numbers:
* https://docs.microsoft.com/en-us/windows/ * https://docs.microsoft.com/en-us/windows/
* win32/procthread/scheduling-priorities */ * win32/procthread/scheduling-priorities */
int result = SetPriorityClass( int result = SetPriorityClass(
reinterpret_cast<HANDLE>(mainThread.native_handle()), reinterpret_cast<HANDLE>(mainThread.native_handle()),
ABOVE_NORMAL_PRIORITY_CLASS); ABOVE_NORMAL_PRIORITY_CLASS);
if(result != 0) { if(result != 0) {
sif::error << "PeriodicTask: Windows SetPriorityClass failed with code " sif::error << "PeriodicTask: Windows SetPriorityClass failed with code "
<< GetLastError() << std::endl; << GetLastError() << std::endl;
} }
result = SetThreadPriority( result = SetThreadPriority(
reinterpret_cast<HANDLE>(mainThread.native_handle()), reinterpret_cast<HANDLE>(mainThread.native_handle()),
THREAD_PRIORITY_NORMAL); THREAD_PRIORITY_NORMAL);
if(result != 0) { if(result != 0) {
sif::error << "PeriodicTask: Windows SetPriorityClass failed with code " sif::error << "PeriodicTask: Windows SetPriorityClass failed with code "
<< GetLastError() << std::endl; << GetLastError() << std::endl;
} }
#elif defined(LINUX) #elif defined(LINUX)
// we can just copy and paste the code from linux here. // we can just copy and paste the code from linux here.
#endif #endif
} }
PeriodicTask::~PeriodicTask(void) { PeriodicTask::~PeriodicTask(void) {
//Do not delete objects, we were responsible for ptrs only. //Do not delete objects, we were responsible for ptrs only.
terminateThread = true; terminateThread = true;
if(mainThread.joinable()) { if(mainThread.joinable()) {
mainThread.join(); mainThread.join();
} }
delete this; delete this;
} }
void PeriodicTask::taskEntryPoint(void* argument) { void PeriodicTask::taskEntryPoint(void* argument) {
PeriodicTask *originalTask(reinterpret_cast<PeriodicTask*>(argument)); PeriodicTask *originalTask(reinterpret_cast<PeriodicTask*>(argument));
if (not originalTask->started) { if (not originalTask->started) {
// we have to suspend/block here until the task is started. // we have to suspend/block here until the task is started.
// if semaphores are implemented, use them here. // if semaphores are implemented, use them here.
std::unique_lock<std::mutex> lock(initMutex); std::unique_lock<std::mutex> lock(initMutex);
initCondition.wait(lock); initCondition.wait(lock);
} }
this->taskFunctionality(); this->taskFunctionality();
sif::debug << "PeriodicTask::taskEntryPoint: " sif::debug << "PeriodicTask::taskEntryPoint: "
"Returned from taskFunctionality." << std::endl; "Returned from taskFunctionality." << std::endl;
} }
ReturnValue_t PeriodicTask::startTask() { ReturnValue_t PeriodicTask::startTask() {
started = true; started = true;
// Notify task to start. // Notify task to start.
std::lock_guard<std::mutex> lock(initMutex); std::lock_guard<std::mutex> lock(initMutex);
initCondition.notify_one(); initCondition.notify_one();
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
} }
ReturnValue_t PeriodicTask::sleepFor(uint32_t ms) { ReturnValue_t PeriodicTask::sleepFor(uint32_t ms) {
std::this_thread::sleep_for(std::chrono::milliseconds(ms)); std::this_thread::sleep_for(std::chrono::milliseconds(ms));
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
} }
void PeriodicTask::taskFunctionality() { void PeriodicTask::taskFunctionality() {
std::chrono::milliseconds periodChrono(static_cast<uint32_t>(period*1000)); std::chrono::milliseconds periodChrono(static_cast<uint32_t>(period*1000));
auto currentStartTime { auto currentStartTime {
std::chrono::duration_cast<std::chrono::milliseconds>( std::chrono::duration_cast<std::chrono::milliseconds>(
std::chrono::system_clock::now().time_since_epoch()) std::chrono::system_clock::now().time_since_epoch())
}; };
auto nextStartTime{ currentStartTime }; auto nextStartTime{ currentStartTime };
/* Enter the loop that defines the task behavior. */ /* Enter the loop that defines the task behavior. */
for (;;) { for (;;) {
if(terminateThread.load()) { if(terminateThread.load()) {
break; break;
} }
for (ObjectList::iterator it = objectList.begin(); for (ObjectList::iterator it = objectList.begin();
it != objectList.end(); ++it) { it != objectList.end(); ++it) {
(*it)->performOperation(); (*it)->performOperation();
} }
if(not delayForInterval(&currentStartTime, periodChrono)) { if(not delayForInterval(&currentStartTime, periodChrono)) {
sif::warning << "PeriodicTask: " << taskName << sif::warning << "PeriodicTask: " << taskName <<
" missed deadline!\n" << std::flush; " missed deadline!\n" << std::flush;
if(deadlineMissedFunc != nullptr) { if(deadlineMissedFunc != nullptr) {
this->deadlineMissedFunc(); this->deadlineMissedFunc();
} }
} }
} }
} }
ReturnValue_t PeriodicTask::addComponent(object_id_t object) { ReturnValue_t PeriodicTask::addComponent(object_id_t object) {
ExecutableObjectIF* newObject = objectManager->get<ExecutableObjectIF>( ExecutableObjectIF* newObject = objectManager->get<ExecutableObjectIF>(
object); object);
if (newObject == nullptr) { if (newObject == nullptr) {
return HasReturnvaluesIF::RETURN_FAILED; return HasReturnvaluesIF::RETURN_FAILED;
} }
objectList.push_back(newObject); objectList.push_back(newObject);
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
} }
uint32_t PeriodicTask::getPeriodMs() const { uint32_t PeriodicTask::getPeriodMs() const {
return period * 1000; return period * 1000;
} }
bool PeriodicTask::delayForInterval(chron_ms* previousWakeTimeMs, bool PeriodicTask::delayForInterval(chron_ms* previousWakeTimeMs,
const chron_ms interval) { const chron_ms interval) {
bool shouldDelay = false; bool shouldDelay = false;
//Get current wakeup time //Get current wakeup time
auto currentStartTime = auto currentStartTime =
std::chrono::duration_cast<std::chrono::milliseconds>( std::chrono::duration_cast<std::chrono::milliseconds>(
std::chrono::system_clock::now().time_since_epoch()); std::chrono::system_clock::now().time_since_epoch());
/* Generate the tick time at which the task wants to wake. */ /* Generate the tick time at which the task wants to wake. */
auto nextTimeToWake_ms = (*previousWakeTimeMs) + interval; auto nextTimeToWake_ms = (*previousWakeTimeMs) + interval;
if (currentStartTime < *previousWakeTimeMs) { if (currentStartTime < *previousWakeTimeMs) {
/* The tick count has overflowed since this function was /* The tick count has overflowed since this function was
lasted called. In this case the only time we should ever lasted called. In this case the only time we should ever
actually delay is if the wake time has also overflowed, actually delay is if the wake time has also overflowed,
and the wake time is greater than the tick time. When this and the wake time is greater than the tick time. When this
is the case it is as if neither time had overflowed. */ is the case it is as if neither time had overflowed. */
if ((nextTimeToWake_ms < *previousWakeTimeMs) if ((nextTimeToWake_ms < *previousWakeTimeMs)
&& (nextTimeToWake_ms > currentStartTime)) { && (nextTimeToWake_ms > currentStartTime)) {
shouldDelay = true; shouldDelay = true;
} }
} else { } else {
/* The tick time has not overflowed. In this case we will /* The tick time has not overflowed. In this case we will
delay if either the wake time has overflowed, and/or the delay if either the wake time has overflowed, and/or the
tick time is less than the wake time. */ tick time is less than the wake time. */
if ((nextTimeToWake_ms < *previousWakeTimeMs) if ((nextTimeToWake_ms < *previousWakeTimeMs)
|| (nextTimeToWake_ms > currentStartTime)) { || (nextTimeToWake_ms > currentStartTime)) {
shouldDelay = true; shouldDelay = true;
} }
} }
/* Update the wake time ready for the next call. */ /* Update the wake time ready for the next call. */
(*previousWakeTimeMs) = nextTimeToWake_ms; (*previousWakeTimeMs) = nextTimeToWake_ms;
if (shouldDelay) { if (shouldDelay) {
auto sleepTime = std::chrono::duration_cast<std::chrono::milliseconds>( auto sleepTime = std::chrono::duration_cast<std::chrono::milliseconds>(
nextTimeToWake_ms - currentStartTime); nextTimeToWake_ms - currentStartTime);
std::this_thread::sleep_for(sleepTime); std::this_thread::sleep_for(sleepTime);
return true; return true;
} }
//We are shifting the time in case the deadline was missed like rtems //We are shifting the time in case the deadline was missed like rtems
(*previousWakeTimeMs) = currentStartTime; (*previousWakeTimeMs) = currentStartTime;
return false; return false;
} }

View File

@ -1,123 +1,123 @@
#ifndef FRAMEWORK_OSAL_HOST_PERIODICTASK_H_ #ifndef FRAMEWORK_OSAL_HOST_PERIODICTASK_H_
#define FRAMEWORK_OSAL_HOST_PERIODICTASK_H_ #define FRAMEWORK_OSAL_HOST_PERIODICTASK_H_
#include <framework/objectmanager/ObjectManagerIF.h> #include "../../objectmanager/ObjectManagerIF.h"
#include <framework/tasks/PeriodicTaskIF.h> #include "../../tasks/PeriodicTaskIF.h"
#include <framework/tasks/Typedef.h> #include "../../tasks/Typedef.h"
#include <vector> #include <vector>
#include <thread> #include <thread>
#include <condition_variable> #include <condition_variable>
#include <atomic> #include <atomic>
class ExecutableObjectIF; class ExecutableObjectIF;
/** /**
* @brief This class represents a specialized task for * @brief This class represents a specialized task for
* periodic activities of multiple objects. * periodic activities of multiple objects.
* @details * @details
* *
* @ingroup task_handling * @ingroup task_handling
*/ */
class PeriodicTask: public PeriodicTaskIF { class PeriodicTask: public PeriodicTaskIF {
public: public:
/** /**
* @brief Standard constructor of the class. * @brief Standard constructor of the class.
* @details * @details
* The class is initialized without allocated objects. These need to be * The class is initialized without allocated objects. These need to be
* added with #addComponent. * added with #addComponent.
* @param priority * @param priority
* @param stack_size * @param stack_size
* @param setPeriod * @param setPeriod
* @param setDeadlineMissedFunc * @param setDeadlineMissedFunc
* The function pointer to the deadline missed function that shall be * The function pointer to the deadline missed function that shall be
* assigned. * assigned.
*/ */
PeriodicTask(const char *name, TaskPriority setPriority, TaskStackSize setStack, PeriodicTask(const char *name, TaskPriority setPriority, TaskStackSize setStack,
TaskPeriod setPeriod,void (*setDeadlineMissedFunc)()); TaskPeriod setPeriod,void (*setDeadlineMissedFunc)());
/** /**
* @brief Currently, the executed object's lifetime is not coupled with * @brief Currently, the executed object's lifetime is not coupled with
* the task object's lifetime, so the destructor is empty. * the task object's lifetime, so the destructor is empty.
*/ */
virtual ~PeriodicTask(void); virtual ~PeriodicTask(void);
/** /**
* @brief The method to start the task. * @brief The method to start the task.
* @details The method starts the task with the respective system call. * @details The method starts the task with the respective system call.
* Entry point is the taskEntryPoint method described below. * Entry point is the taskEntryPoint method described below.
* The address of the task object is passed as an argument * The address of the task object is passed as an argument
* to the system call. * to the system call.
*/ */
ReturnValue_t startTask(void); ReturnValue_t startTask(void);
/** /**
* Adds an object to the list of objects to be executed. * Adds an object to the list of objects to be executed.
* The objects are executed in the order added. * The objects are executed in the order added.
* @param object Id of the object to add. * @param object Id of the object to add.
* @return * @return
* -@c RETURN_OK on success * -@c RETURN_OK on success
* -@c RETURN_FAILED if the object could not be added. * -@c RETURN_FAILED if the object could not be added.
*/ */
ReturnValue_t addComponent(object_id_t object); ReturnValue_t addComponent(object_id_t object);
uint32_t getPeriodMs() const; uint32_t getPeriodMs() const;
ReturnValue_t sleepFor(uint32_t ms); ReturnValue_t sleepFor(uint32_t ms);
protected: protected:
using chron_ms = std::chrono::milliseconds; using chron_ms = std::chrono::milliseconds;
bool started; bool started;
//!< Typedef for the List of objects. //!< Typedef for the List of objects.
typedef std::vector<ExecutableObjectIF*> ObjectList; typedef std::vector<ExecutableObjectIF*> ObjectList;
std::thread mainThread; std::thread mainThread;
std::atomic<bool> terminateThread = false; std::atomic<bool> terminateThread = false;
/** /**
* @brief This attribute holds a list of objects to be executed. * @brief This attribute holds a list of objects to be executed.
*/ */
ObjectList objectList; ObjectList objectList;
std::condition_variable initCondition; std::condition_variable initCondition;
std::mutex initMutex; std::mutex initMutex;
std::string taskName; std::string taskName;
/** /**
* @brief The period of the task. * @brief The period of the task.
* @details * @details
* The period determines the frequency of the task's execution. * The period determines the frequency of the task's execution.
* It is expressed in clock ticks. * It is expressed in clock ticks.
*/ */
TaskPeriod period; TaskPeriod period;
/** /**
* @brief The pointer to the deadline-missed function. * @brief The pointer to the deadline-missed function.
* @details * @details
* This pointer stores the function that is executed if the task's deadline * This pointer stores the function that is executed if the task's deadline
* is missed. So, each may react individually on a timing failure. * is missed. So, each may react individually on a timing failure.
* The pointer may be NULL, then nothing happens on missing the deadline. * The pointer may be NULL, then nothing happens on missing the deadline.
* The deadline is equal to the next execution of the periodic task. * The deadline is equal to the next execution of the periodic task.
*/ */
void (*deadlineMissedFunc)(void); void (*deadlineMissedFunc)(void);
/** /**
* @brief This is the function executed in the new task's context. * @brief This is the function executed in the new task's context.
* @details * @details
* It converts the argument back to the thread object type and copies the * It converts the argument back to the thread object type and copies the
* class instance to the task context. * class instance to the task context.
* The taskFunctionality method is called afterwards. * The taskFunctionality method is called afterwards.
* @param A pointer to the task object itself is passed as argument. * @param A pointer to the task object itself is passed as argument.
*/ */
void taskEntryPoint(void* argument); void taskEntryPoint(void* argument);
/** /**
* @brief The function containing the actual functionality of the task. * @brief The function containing the actual functionality of the task.
* @details * @details
* The method sets and starts the task's period, then enters a loop that is * The method sets and starts the task's period, then enters a loop that is
* repeated as long as the isRunning attribute is true. Within the loop, * repeated as long as the isRunning attribute is true. Within the loop,
* all performOperation methods of the added objects are called. Afterwards * all performOperation methods of the added objects are called. Afterwards
* the checkAndRestartPeriod system call blocks the task until the next * the checkAndRestartPeriod system call blocks the task until the next
* period. On missing the deadline, the deadlineMissedFunction is executed. * period. On missing the deadline, the deadlineMissedFunction is executed.
*/ */
void taskFunctionality(void); void taskFunctionality(void);
bool delayForInterval(chron_ms * previousWakeTimeMs, bool delayForInterval(chron_ms * previousWakeTimeMs,
const chron_ms interval); const chron_ms interval);
}; };
#endif /* PERIODICTASK_H_ */ #endif /* PERIODICTASK_H_ */

View File

@ -1,41 +1,41 @@
#include <framework/ipc/QueueFactory.h> #include "../../ipc/QueueFactory.h"
#include <framework/osal/host/MessageQueue.h> #include "../../osal/host/MessageQueue.h"
#include <framework/serviceinterface/ServiceInterfaceStream.h> #include "../../serviceinterface/ServiceInterfaceStream.h"
#include <cstring> #include <cstring>
QueueFactory* QueueFactory::factoryInstance = nullptr; QueueFactory* QueueFactory::factoryInstance = nullptr;
ReturnValue_t MessageQueueSenderIF::sendMessage(MessageQueueId_t sendTo, ReturnValue_t MessageQueueSenderIF::sendMessage(MessageQueueId_t sendTo,
MessageQueueMessageIF* message, MessageQueueId_t sentFrom, MessageQueueMessageIF* message, MessageQueueId_t sentFrom,
bool ignoreFault) { bool ignoreFault) {
return MessageQueue::sendMessageFromMessageQueue(sendTo,message, return MessageQueue::sendMessageFromMessageQueue(sendTo,message,
sentFrom,ignoreFault); sentFrom,ignoreFault);
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
} }
QueueFactory* QueueFactory::instance() { QueueFactory* QueueFactory::instance() {
if (factoryInstance == nullptr) { if (factoryInstance == nullptr) {
factoryInstance = new QueueFactory; factoryInstance = new QueueFactory;
} }
return factoryInstance; return factoryInstance;
} }
QueueFactory::QueueFactory() { QueueFactory::QueueFactory() {
} }
QueueFactory::~QueueFactory() { QueueFactory::~QueueFactory() {
} }
MessageQueueIF* QueueFactory::createMessageQueue(uint32_t messageDepth, MessageQueueIF* QueueFactory::createMessageQueue(uint32_t messageDepth,
size_t maxMessageSize) { size_t maxMessageSize) {
// A thread-safe queue can be implemented by using a combination // A thread-safe queue can be implemented by using a combination
// of std::queue and std::mutex. This uses dynamic memory allocation // of std::queue and std::mutex. This uses dynamic memory allocation
// which could be alleviated by using a custom allocator, external library // which could be alleviated by using a custom allocator, external library
// (etl::queue) or simply using std::queue, we're on a host machine anyway. // (etl::queue) or simply using std::queue, we're on a host machine anyway.
return new MessageQueue(messageDepth, maxMessageSize); return new MessageQueue(messageDepth, maxMessageSize);
} }
void QueueFactory::deleteMessageQueue(MessageQueueIF* queue) { void QueueFactory::deleteMessageQueue(MessageQueueIF* queue) {
delete queue; delete queue;
} }

View File

@ -1,51 +1,51 @@
#include <framework/ipc/MutexFactory.h> #include "../../ipc/MutexFactory.h"
#include <framework/ipc/MutexHelper.h> #include "../../ipc/MutexHelper.h"
#include <framework/osal/host/QueueMapManager.h> #include "../../osal/host/QueueMapManager.h"
QueueMapManager* QueueMapManager::mqManagerInstance = nullptr; QueueMapManager* QueueMapManager::mqManagerInstance = nullptr;
QueueMapManager::QueueMapManager() { QueueMapManager::QueueMapManager() {
mapLock = MutexFactory::instance()->createMutex(); mapLock = MutexFactory::instance()->createMutex();
} }
QueueMapManager* QueueMapManager::instance() { QueueMapManager* QueueMapManager::instance() {
if (mqManagerInstance == nullptr){ if (mqManagerInstance == nullptr){
mqManagerInstance = new QueueMapManager(); mqManagerInstance = new QueueMapManager();
} }
return QueueMapManager::mqManagerInstance; return QueueMapManager::mqManagerInstance;
} }
ReturnValue_t QueueMapManager::addMessageQueue( ReturnValue_t QueueMapManager::addMessageQueue(
MessageQueueIF* queueToInsert, MessageQueueId_t* id) { MessageQueueIF* queueToInsert, MessageQueueId_t* id) {
// Not thread-safe, but it is assumed all message queues are created // Not thread-safe, but it is assumed all message queues are created
// at software initialization now. If this is to be made thread-safe in // at software initialization now. If this is to be made thread-safe in
// the future, it propably would be sufficient to lock the increment // the future, it propably would be sufficient to lock the increment
// operation here // operation here
uint32_t currentId = queueCounter++; uint32_t currentId = queueCounter++;
auto returnPair = queueMap.emplace(currentId, queueToInsert); auto returnPair = queueMap.emplace(currentId, queueToInsert);
if(not returnPair.second) { if(not returnPair.second) {
// this should never happen for the atomic variable. // this should never happen for the atomic variable.
sif::error << "QueueMapManager: This ID is already inside the map!" sif::error << "QueueMapManager: This ID is already inside the map!"
<< std::endl; << std::endl;
return HasReturnvaluesIF::RETURN_FAILED; return HasReturnvaluesIF::RETURN_FAILED;
} }
if (id != nullptr) { if (id != nullptr) {
*id = currentId; *id = currentId;
} }
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
} }
MessageQueueIF* QueueMapManager::getMessageQueue( MessageQueueIF* QueueMapManager::getMessageQueue(
MessageQueueId_t messageQueueId) const { MessageQueueId_t messageQueueId) const {
MutexHelper(mapLock, 50); MutexHelper(mapLock, 50);
auto queueIter = queueMap.find(messageQueueId); auto queueIter = queueMap.find(messageQueueId);
if(queueIter != queueMap.end()) { if(queueIter != queueMap.end()) {
return queueIter->second; return queueIter->second;
} }
else { else {
sif::warning << "QueueMapManager::getQueueHandle: The ID" << sif::warning << "QueueMapManager::getQueueHandle: The ID" <<
messageQueueId << " does not exists in the map" << std::endl; messageQueueId << " does not exists in the map" << std::endl;
return nullptr; return nullptr;
} }
} }

View File

@ -1,47 +1,47 @@
#ifndef FRAMEWORK_OSAL_HOST_QUEUEMAP_H_ #ifndef FRAMEWORK_OSAL_HOST_QUEUEMAP_H_
#define FRAMEWORK_OSAL_HOST_QUEUEMAP_H_ #define FRAMEWORK_OSAL_HOST_QUEUEMAP_H_
#include <framework/ipc/MessageQueueSenderIF.h> #include "../../ipc/MessageQueueSenderIF.h"
#include <framework/osal/host/MessageQueue.h> #include "../../osal/host/MessageQueue.h"
#include <unordered_map> #include <unordered_map>
#include <atomic> #include <atomic>
using QueueMap = std::unordered_map<MessageQueueId_t, MessageQueueIF*>; using QueueMap = std::unordered_map<MessageQueueId_t, MessageQueueIF*>;
/** /**
* An internal map to map message queue IDs to message queues. * An internal map to map message queue IDs to message queues.
* This propably should be a singleton.. * This propably should be a singleton..
*/ */
class QueueMapManager { class QueueMapManager {
public: public:
//! Returns the single instance of SemaphoreFactory. //! Returns the single instance of SemaphoreFactory.
static QueueMapManager* instance(); static QueueMapManager* instance();
/** /**
* Insert a message queue into the map and returns a message queue ID * Insert a message queue into the map and returns a message queue ID
* @param queue The message queue to insert. * @param queue The message queue to insert.
* @param id The passed value will be set unless a nullptr is passed * @param id The passed value will be set unless a nullptr is passed
* @return * @return
*/ */
ReturnValue_t addMessageQueue(MessageQueueIF* queue, MessageQueueId_t* ReturnValue_t addMessageQueue(MessageQueueIF* queue, MessageQueueId_t*
id = nullptr); id = nullptr);
/** /**
* Get the message queue handle by providing a message queue ID. * Get the message queue handle by providing a message queue ID.
* @param messageQueueId * @param messageQueueId
* @return * @return
*/ */
MessageQueueIF* getMessageQueue(MessageQueueId_t messageQueueId) const; MessageQueueIF* getMessageQueue(MessageQueueId_t messageQueueId) const;
private: private:
//! External instantiation is forbidden. //! External instantiation is forbidden.
QueueMapManager(); QueueMapManager();
uint32_t queueCounter = 1; uint32_t queueCounter = 1;
MutexIF* mapLock; MutexIF* mapLock;
QueueMap queueMap; QueueMap queueMap;
static QueueMapManager* mqManagerInstance; static QueueMapManager* mqManagerInstance;
}; };
#endif /* FRAMEWORK_OSAL_HOST_QUEUEMAP_H_ */ #endif /* FRAMEWORK_OSAL_HOST_QUEUEMAP_H_ */

View File

@ -1,42 +1,42 @@
#include <framework/tasks/SemaphoreFactory.h> #include "../../tasks/SemaphoreFactory.h"
#include <framework/osal/linux/BinarySemaphore.h> #include "../../osal/linux/BinarySemaphore.h"
#include <framework/osal/linux/CountingSemaphore.h> #include "../../osal/linux/CountingSemaphore.h"
#include <framework/serviceinterface/ServiceInterfaceStream.h> #include "../../serviceinterface/ServiceInterfaceStream.h"
const uint32_t SemaphoreIF::POLLING = 0; const uint32_t SemaphoreIF::POLLING = 0;
const uint32_t SemaphoreIF::BLOCKING = 0xFFFFFFFF; const uint32_t SemaphoreIF::BLOCKING = 0xFFFFFFFF;
SemaphoreFactory* SemaphoreFactory::factoryInstance = nullptr; SemaphoreFactory* SemaphoreFactory::factoryInstance = nullptr;
SemaphoreFactory::SemaphoreFactory() { SemaphoreFactory::SemaphoreFactory() {
} }
SemaphoreFactory::~SemaphoreFactory() { SemaphoreFactory::~SemaphoreFactory() {
delete factoryInstance; delete factoryInstance;
} }
SemaphoreFactory* SemaphoreFactory::instance() { SemaphoreFactory* SemaphoreFactory::instance() {
if (factoryInstance == nullptr){ if (factoryInstance == nullptr){
factoryInstance = new SemaphoreFactory(); factoryInstance = new SemaphoreFactory();
} }
return SemaphoreFactory::factoryInstance; return SemaphoreFactory::factoryInstance;
} }
SemaphoreIF* SemaphoreFactory::createBinarySemaphore(uint32_t arguments) { SemaphoreIF* SemaphoreFactory::createBinarySemaphore(uint32_t arguments) {
// Just gonna wait for full C++20 for now. // Just gonna wait for full C++20 for now.
sif::error << "SemaphoreFactory: Binary Semaphore not implemented yet." sif::error << "SemaphoreFactory: Binary Semaphore not implemented yet."
" Returning nullptr!\n" << std::flush; " Returning nullptr!\n" << std::flush;
return nullptr; return nullptr;
} }
SemaphoreIF* SemaphoreFactory::createCountingSemaphore(const uint8_t maxCount, SemaphoreIF* SemaphoreFactory::createCountingSemaphore(const uint8_t maxCount,
uint8_t initCount, uint32_t arguments) { uint8_t initCount, uint32_t arguments) {
// Just gonna wait for full C++20 for now. // Just gonna wait for full C++20 for now.
sif::error << "SemaphoreFactory: Counting Semaphore not implemented yet." sif::error << "SemaphoreFactory: Counting Semaphore not implemented yet."
" Returning nullptr!\n" << std::flush; " Returning nullptr!\n" << std::flush;
return nullptr; return nullptr;
} }
void SemaphoreFactory::deleteSemaphore(SemaphoreIF* semaphore) { void SemaphoreFactory::deleteSemaphore(SemaphoreIF* semaphore) {
delete semaphore; delete semaphore;
} }

View File

@ -1,55 +1,55 @@
#include <framework/osal/host/FixedTimeslotTask.h> #include "../../osal/host/FixedTimeslotTask.h"
#include <framework/osal/host/PeriodicTask.h> #include "../../osal/host/PeriodicTask.h"
#include <framework/tasks/TaskFactory.h> #include "../../tasks/TaskFactory.h"
#include <framework/returnvalues/HasReturnvaluesIF.h> #include "../../returnvalues/HasReturnvaluesIF.h"
#include <framework/tasks/PeriodicTaskIF.h> #include "../../tasks/PeriodicTaskIF.h"
#include <chrono> #include <chrono>
TaskFactory* TaskFactory::factoryInstance = new TaskFactory(); TaskFactory* TaskFactory::factoryInstance = new TaskFactory();
// Will propably not be used for hosted implementation // Will propably not be used for hosted implementation
const size_t PeriodicTaskIF::MINIMUM_STACK_SIZE = 0; const size_t PeriodicTaskIF::MINIMUM_STACK_SIZE = 0;
TaskFactory::TaskFactory() { TaskFactory::TaskFactory() {
} }
TaskFactory::~TaskFactory() { TaskFactory::~TaskFactory() {
} }
TaskFactory* TaskFactory::instance() { TaskFactory* TaskFactory::instance() {
return TaskFactory::factoryInstance; return TaskFactory::factoryInstance;
} }
PeriodicTaskIF* TaskFactory::createPeriodicTask(TaskName name_, PeriodicTaskIF* TaskFactory::createPeriodicTask(TaskName name_,
TaskPriority taskPriority_,TaskStackSize stackSize_, TaskPriority taskPriority_,TaskStackSize stackSize_,
TaskPeriod periodInSeconds_, TaskPeriod periodInSeconds_,
TaskDeadlineMissedFunction deadLineMissedFunction_) { TaskDeadlineMissedFunction deadLineMissedFunction_) {
// This is going to be interesting. Time now learn the C++ threading library // This is going to be interesting. Time now learn the C++ threading library
// :-) // :-)
return new PeriodicTask(name_, taskPriority_, stackSize_, periodInSeconds_, return new PeriodicTask(name_, taskPriority_, stackSize_, periodInSeconds_,
deadLineMissedFunction_); deadLineMissedFunction_);
} }
FixedTimeslotTaskIF* TaskFactory::createFixedTimeslotTask(TaskName name_, FixedTimeslotTaskIF* TaskFactory::createFixedTimeslotTask(TaskName name_,
TaskPriority taskPriority_,TaskStackSize stackSize_, TaskPriority taskPriority_,TaskStackSize stackSize_,
TaskPeriod periodInSeconds_, TaskPeriod periodInSeconds_,
TaskDeadlineMissedFunction deadLineMissedFunction_) { TaskDeadlineMissedFunction deadLineMissedFunction_) {
// This is going to be interesting. Time now learn the C++ threading library // This is going to be interesting. Time now learn the C++ threading library
// :-) // :-)
return new FixedTimeslotTask(name_, taskPriority_, stackSize_, return new FixedTimeslotTask(name_, taskPriority_, stackSize_,
periodInSeconds_, deadLineMissedFunction_); periodInSeconds_, deadLineMissedFunction_);
} }
ReturnValue_t TaskFactory::deleteTask(PeriodicTaskIF* task) { ReturnValue_t TaskFactory::deleteTask(PeriodicTaskIF* task) {
// This might block for some time! // This might block for some time!
delete task; delete task;
return HasReturnvaluesIF::RETURN_FAILED; return HasReturnvaluesIF::RETURN_FAILED;
} }
ReturnValue_t TaskFactory::delayTask(uint32_t delayMs){ ReturnValue_t TaskFactory::delayTask(uint32_t delayMs){
std::this_thread::sleep_for(std::chrono::milliseconds(delayMs)); std::this_thread::sleep_for(std::chrono::milliseconds(delayMs));
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
} }