fsfw/osal/FreeRTOS/PeriodicTask.cpp

137 lines
4.5 KiB
C++
Raw Normal View History

2020-06-19 14:45:29 +02:00
#include "PeriodicTask.h"
2018-07-13 15:56:37 +02:00
#include <framework/serviceinterface/ServiceInterfaceStream.h>
#include <framework/tasks/ExecutableObjectIF.h>
PeriodicTask::PeriodicTask(const char *name, TaskPriority setPriority,
TaskStackSize setStack, TaskPeriod setPeriod,
void (*setDeadlineMissedFunc)()) :
started(false), handle(NULL), period(setPeriod), deadlineMissedFunc(
2020-06-19 14:45:29 +02:00
setDeadlineMissedFunc)
{
BaseType_t status = xTaskCreate(taskEntryPoint, name,
setStack, this, setPriority, &handle);
if(status != pdPASS){
2020-06-19 14:45:29 +02:00
sif::debug << "PeriodicTask Insufficient heap memory remaining. "
"Status: " << status << std::endl;
}
2018-07-13 15:56:37 +02:00
}
PeriodicTask::~PeriodicTask(void) {
//Do not delete objects, we were responsible for ptrs only.
}
void PeriodicTask::taskEntryPoint(void* argument) {
2020-06-19 14:45:29 +02:00
// The argument is re-interpreted as PeriodicTask. The Task object is
// global, so it is found from any place.
2018-07-13 15:56:37 +02:00
PeriodicTask *originalTask(reinterpret_cast<PeriodicTask*>(argument));
2020-06-19 14:45:29 +02:00
/* Task should not start until explicitly requested,
* but in FreeRTOS, tasks start as soon as they are created if the scheduler
* is running but not if the scheduler is not running.
* To be able to accommodate both cases we check a member which is set in
* #startTask(). If it is not set and we get here, the scheduler was started
* before #startTask() was called and we need to suspend if it is set,
* the scheduler was not running before #startTask() was called and we
* can continue */
if (not originalTask->started) {
2018-07-13 15:56:37 +02:00
vTaskSuspend(NULL);
}
originalTask->taskFunctionality();
sif::debug << "Polling task " << originalTask->handle
2018-07-13 15:56:37 +02:00
<< " returned from taskFunctionality." << std::endl;
}
ReturnValue_t PeriodicTask::startTask() {
started = true;
// We must not call resume if scheduler is not started yet
if (xTaskGetSchedulerState() != taskSCHEDULER_NOT_STARTED) {
vTaskResume(handle);
}
return HasReturnvaluesIF::RETURN_OK;
}
ReturnValue_t PeriodicTask::sleepFor(uint32_t ms) {
vTaskDelay(pdMS_TO_TICKS(ms));
return HasReturnvaluesIF::RETURN_OK;
}
void PeriodicTask::taskFunctionality() {
TickType_t xLastWakeTime;
const TickType_t xPeriod = pdMS_TO_TICKS(this->period * 1000.);
/* The xLastWakeTime variable needs to be initialized with the current tick
2020-06-19 14:45:29 +02:00
count. Note that this is the only time the variable is written to
explicitly. After this assignment, xLastWakeTime is updated automatically
internally within vTaskDelayUntil(). */
2018-07-13 15:56:37 +02:00
xLastWakeTime = xTaskGetTickCount();
/* Enter the loop that defines the task behavior. */
for (;;) {
2020-06-23 01:14:28 +02:00
for (auto const& object: objectList) {
object->performOperation();
2018-07-13 15:56:37 +02:00
}
2020-06-19 14:45:29 +02:00
2020-06-23 01:14:28 +02:00
checkMissedDeadline(xLastWakeTime, xPeriod);
2020-06-19 14:45:29 +02:00
2018-07-13 15:56:37 +02:00
vTaskDelayUntil(&xLastWakeTime, xPeriod);
2020-06-19 14:45:29 +02:00
2018-07-13 15:56:37 +02:00
}
}
2020-06-23 01:14:28 +02:00
ReturnValue_t PeriodicTask::addComponent(object_id_t object, bool setTaskIF) {
2018-07-13 15:56:37 +02:00
ExecutableObjectIF* newObject = objectManager->get<ExecutableObjectIF>(
object);
2020-06-23 01:14:28 +02:00
if (newObject == nullptr) {
sif::error << "PeriodicTask::addComponent: Invalid object. Make sure"
2020-06-24 12:06:08 +02:00
"it implements ExecutableObjectIF!" << std::endl;
2018-07-13 15:56:37 +02:00
return HasReturnvaluesIF::RETURN_FAILED;
}
objectList.push_back(newObject);
2020-06-23 01:14:28 +02:00
if(setTaskIF) {
newObject->setTaskIF(this);
}
2018-07-13 15:56:37 +02:00
return HasReturnvaluesIF::RETURN_OK;
}
uint32_t PeriodicTask::getPeriodMs() const {
return period * 1000;
}
2020-06-23 01:14:28 +02:00
void PeriodicTask::checkMissedDeadline(const TickType_t xLastWakeTime,
const TickType_t interval) {
/* Check whether deadline was missed while also taking overflows
* into account. Drawing this on paper with a timeline helps to understand
* it. */
TickType_t currentTickCount = xTaskGetTickCount();
TickType_t timeToWake = xLastWakeTime + interval;
// Tick count has overflown
if(currentTickCount < xLastWakeTime) {
// Time to wake has overflown as well. If the tick count
// is larger than the time to wake, a deadline was missed.
if(timeToWake < xLastWakeTime and
currentTickCount > timeToWake) {
handleMissedDeadline();
}
}
// No tick count overflow. If the timeToWake has not overflown
// and the current tick count is larger than the time to wake,
// a deadline was missed.
else if(timeToWake > xLastWakeTime and currentTickCount > timeToWake) {
handleMissedDeadline();
}
}
void PeriodicTask::handleMissedDeadline() {
#ifdef DEBUG
sif::warning << "PeriodicTask: " << pcTaskGetName(NULL) <<
" missed deadline!\n" << std::flush;
#endif
if(deadlineMissedFunc != nullptr) {
this->deadlineMissedFunc();
}
}