renormalizing pull request step1

This commit is contained in:
Robin Müller 2020-09-04 13:52:02 +02:00
parent 7ad5274803
commit 5eaf6cfd1f
2 changed files with 272 additions and 267 deletions

View File

@ -1,166 +1,171 @@
#include "FixedTimeslotTask.h" #include "FixedTimeslotTask.h"
#include "../../serviceinterface/ServiceInterfaceStream.h" #include "../../serviceinterface/ServiceInterfaceStream.h"
uint32_t FixedTimeslotTask::deadlineMissedCount = 0; uint32_t FixedTimeslotTask::deadlineMissedCount = 0;
const size_t PeriodicTaskIF::MINIMUM_STACK_SIZE = configMINIMAL_STACK_SIZE; const size_t PeriodicTaskIF::MINIMUM_STACK_SIZE = configMINIMAL_STACK_SIZE;
FixedTimeslotTask::FixedTimeslotTask(TaskName name, TaskPriority setPriority, FixedTimeslotTask::FixedTimeslotTask(TaskName name, TaskPriority setPriority,
TaskStackSize setStack, TaskPeriod overallPeriod, TaskStackSize setStack, TaskPeriod overallPeriod,
void (*setDeadlineMissedFunc)()) : void (*setDeadlineMissedFunc)()) :
started(false), handle(nullptr), pst(overallPeriod * 1000) { started(false), handle(nullptr), pst(overallPeriod * 1000) {
configSTACK_DEPTH_TYPE stackSize = setStack / sizeof(configSTACK_DEPTH_TYPE); configSTACK_DEPTH_TYPE stackSize = setStack / sizeof(configSTACK_DEPTH_TYPE);
xTaskCreate(taskEntryPoint, name, stackSize, this, setPriority, &handle); xTaskCreate(taskEntryPoint, name, stackSize, this, setPriority, &handle);
// All additional attributes are applied to the object. // All additional attributes are applied to the object.
this->deadlineMissedFunc = setDeadlineMissedFunc; this->deadlineMissedFunc = setDeadlineMissedFunc;
} }
FixedTimeslotTask::~FixedTimeslotTask() { FixedTimeslotTask::~FixedTimeslotTask() {
} }
void FixedTimeslotTask::taskEntryPoint(void* argument) { void FixedTimeslotTask::taskEntryPoint(void* argument) {
// The argument is re-interpreted as FixedTimeslotTask. The Task object is // The argument is re-interpreted as FixedTimeslotTask. The Task object is
// global, so it is found from any place. // global, so it is found from any place.
FixedTimeslotTask *originalTask(reinterpret_cast<FixedTimeslotTask*>(argument)); FixedTimeslotTask *originalTask(reinterpret_cast<FixedTimeslotTask*>(argument));
/* Task should not start until explicitly requested, /* Task should not start until explicitly requested,
* but in FreeRTOS, tasks start as soon as they are created if the scheduler * but in FreeRTOS, tasks start as soon as they are created if the scheduler
* is running but not if the scheduler is not running. * 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 * 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 * #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, * before #startTask() was called and we need to suspend if it is set,
* the scheduler was not running before #startTask() was called and we * the scheduler was not running before #startTask() was called and we
* can continue */ * can continue */
if (not originalTask->started) { if (not originalTask->started) {
vTaskSuspend(NULL); vTaskSuspend(NULL);
} }
originalTask->taskFunctionality(); originalTask->taskFunctionality();
sif::debug << "Polling task " << originalTask->handle sif::debug << "Polling task " << originalTask->handle
<< " returned from taskFunctionality." << std::endl; << " returned from taskFunctionality." << std::endl;
} }
void FixedTimeslotTask::missedDeadlineCounter() { void FixedTimeslotTask::missedDeadlineCounter() {
FixedTimeslotTask::deadlineMissedCount++; FixedTimeslotTask::deadlineMissedCount++;
if (FixedTimeslotTask::deadlineMissedCount % 10 == 0) { if (FixedTimeslotTask::deadlineMissedCount % 10 == 0) {
sif::error << "PST missed " << FixedTimeslotTask::deadlineMissedCount sif::error << "PST missed " << FixedTimeslotTask::deadlineMissedCount
<< " deadlines." << std::endl; << " deadlines." << std::endl;
} }
} }
ReturnValue_t FixedTimeslotTask::startTask() { ReturnValue_t FixedTimeslotTask::startTask() {
started = true; started = true;
// We must not call resume if scheduler is not started yet // We must not call resume if scheduler is not started yet
if (xTaskGetSchedulerState() != taskSCHEDULER_NOT_STARTED) { if (xTaskGetSchedulerState() != taskSCHEDULER_NOT_STARTED) {
vTaskResume(handle); vTaskResume(handle);
} }
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
} }
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) {
ExecutableObjectIF* handler = ExecutableObjectIF* handler =
objectManager->get<ExecutableObjectIF>(componentId); objectManager->get<ExecutableObjectIF>(componentId);
if (handler != nullptr) { if (handler != nullptr) {
pst.addSlot(componentId, slotTimeMs, executionStep, handler, this); pst.addSlot(componentId, slotTimeMs, executionStep, handler, 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;
} }
uint32_t FixedTimeslotTask::getPeriodMs() const { uint32_t FixedTimeslotTask::getPeriodMs() const {
return pst.getLengthMs(); return pst.getLengthMs();
} }
ReturnValue_t FixedTimeslotTask::checkSequence() const { ReturnValue_t FixedTimeslotTask::checkSequence() const {
return pst.checkSequence(); return pst.checkSequence();
} }
void FixedTimeslotTask::taskFunctionality() { void FixedTimeslotTask::taskFunctionality() {
// A local iterator for the Polling Sequence Table is created to find the // A local iterator for the Polling Sequence Table is created to find the
// start time for the first entry. // start time for the first entry.
auto slotListIter = pst.current; auto slotListIter = pst.current;
pst.intializeSequenceAfterTaskCreation(); pst.intializeSequenceAfterTaskCreation();
//The start time for the first entry is read. //The start time for the first entry is read.
uint32_t intervalMs = slotListIter->pollingTimeMs; uint32_t intervalMs = slotListIter->pollingTimeMs;
TickType_t interval = pdMS_TO_TICKS(intervalMs); TickType_t interval = pdMS_TO_TICKS(intervalMs);
TickType_t xLastWakeTime; TickType_t xLastWakeTime;
/* The xLastWakeTime variable needs to be initialized with the current tick /* The xLastWakeTime variable needs to be initialized with the current tick
count. Note that this is the only time the variable is written to count. Note that this is the only time the variable is written to
explicitly. After this assignment, xLastWakeTime is updated automatically explicitly. After this assignment, xLastWakeTime is updated automatically
internally within vTaskDelayUntil(). */ internally within vTaskDelayUntil(). */
xLastWakeTime = xTaskGetTickCount(); xLastWakeTime = xTaskGetTickCount();
// wait for first entry's start time // wait for first entry's start time
if(interval > 0) { if(interval > 0) {
vTaskDelayUntil(&xLastWakeTime, interval); vTaskDelayUntil(&xLastWakeTime, interval);
} }
/* Enter the loop that defines the task behavior. */ /* Enter the loop that defines the task behavior. */
for (;;) { for (;;) {
//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->pst.executeAndAdvance(); this->pst.executeAndAdvance();
if (not pst.slotFollowsImmediately()) { if (not pst.slotFollowsImmediately()) {
// Get the interval till execution of the next slot. // Get the interval till execution of the next slot.
intervalMs = this->pst.getIntervalToPreviousSlotMs(); intervalMs = this->pst.getIntervalToPreviousSlotMs();
interval = pdMS_TO_TICKS(intervalMs); interval = pdMS_TO_TICKS(intervalMs);
checkMissedDeadline(xLastWakeTime, interval); checkMissedDeadline(xLastWakeTime, interval);
// Wait for the interval. This exits immediately if a deadline was // Wait for the interval. This exits immediately if a deadline was
// missed while also updating the last wake time. // missed while also updating the last wake time.
vTaskDelayUntil(&xLastWakeTime, interval); vTaskDelayUntil(&xLastWakeTime, interval);
} }
} }
} }
void FixedTimeslotTask::checkMissedDeadline(const TickType_t xLastWakeTime, void FixedTimeslotTask::checkMissedDeadline(const TickType_t xLastWakeTime,
const TickType_t interval) { const TickType_t interval) {
/* Check whether deadline was missed while also taking overflows /* Check whether deadline was missed while also taking overflows
* into account. Drawing this on paper with a timeline helps to understand * into account. Drawing this on paper with a timeline helps to understand
* it. */ * it. */
TickType_t currentTickCount = xTaskGetTickCount(); TickType_t currentTickCount = xTaskGetTickCount();
TickType_t timeToWake = xLastWakeTime + interval; TickType_t timeToWake = xLastWakeTime + interval;
// Time to wake has not overflown. // Time to wake has not overflown.
if(timeToWake > xLastWakeTime) { if(timeToWake > xLastWakeTime) {
/* If the current time has overflown exclusively or the current /* If the current time has overflown exclusively or the current
* tick count is simply larger than the time to wake, a deadline was * tick count is simply larger than the time to wake, a deadline was
* missed */ * missed */
if((currentTickCount < xLastWakeTime) or (currentTickCount > timeToWake)) { if((currentTickCount < xLastWakeTime) or (currentTickCount > timeToWake)) {
handleMissedDeadline(); handleMissedDeadline();
} }
} }
/* Time to wake has overflown. A deadline was missed if the current time /* Time to wake has overflown. A deadline was missed if the current time
* is larger than the time to wake */ * is larger than the time to wake */
else if((timeToWake < xLastWakeTime) and (currentTickCount > timeToWake)) { else if((timeToWake < xLastWakeTime) and (currentTickCount > timeToWake)) {
handleMissedDeadline(); handleMissedDeadline();
} }
} }
void FixedTimeslotTask::handleMissedDeadline() { void FixedTimeslotTask::handleMissedDeadline() {
#ifdef DEBUG if(deadlineMissedFunc != nullptr) {
sif::warning << "FixedTimeslotTask: " << pcTaskGetName(NULL) << this->deadlineMissedFunc();
" missed deadline!\n" << std::flush; }
#endif
if(deadlineMissedFunc != nullptr) { #ifdef DEBUG
this->deadlineMissedFunc(); object_id_t handlerId = pst.current->handlerId;
} sif::warning << "FixedTimeslotTask: " << pcTaskGetName(NULL) << " with"
} << " object ID 0x" << std::setfill('0') << std::setw(8) << std::hex
<< handlerId << " missed deadline!" << std::setfill(' ')
ReturnValue_t FixedTimeslotTask::sleepFor(uint32_t ms) { << std::dec << std::endl;
vTaskDelay(pdMS_TO_TICKS(ms)); #endif
return HasReturnvaluesIF::RETURN_OK;
} }
TaskHandle_t FixedTimeslotTask::getTaskHandle() { ReturnValue_t FixedTimeslotTask::sleepFor(uint32_t ms) {
return handle; vTaskDelay(pdMS_TO_TICKS(ms));
} return HasReturnvaluesIF::RETURN_OK;
}
TaskHandle_t FixedTimeslotTask::getTaskHandle() {
return handle;
}

View File

@ -1,101 +1,101 @@
#ifndef FRAMEWORK_OSAL_FREERTOS_FIXEDTIMESLOTTASK_H_ #ifndef FRAMEWORK_OSAL_FREERTOS_FIXEDTIMESLOTTASK_H_
#define FRAMEWORK_OSAL_FREERTOS_FIXEDTIMESLOTTASK_H_ #define FRAMEWORK_OSAL_FREERTOS_FIXEDTIMESLOTTASK_H_
#include "../../osal/FreeRTOS/FreeRTOSTaskIF.h" #include "../../osal/FreeRTOS/FreeRTOSTaskIF.h"
#include "../../tasks/FixedSlotSequence.h" #include "../../tasks/FixedSlotSequence.h"
#include "../../tasks/FixedTimeslotTaskIF.h" #include "../../tasks/FixedTimeslotTaskIF.h"
#include "../../tasks/Typedef.h" #include "../../tasks/Typedef.h"
#include <freertos/FreeRTOS.h> #include <freertos/FreeRTOS.h>
#include <freertos/task.h> #include <freertos/task.h>
class FixedTimeslotTask: public FixedTimeslotTaskIF, public FreeRTOSTaskIF { class FixedTimeslotTask: public FixedTimeslotTaskIF, public FreeRTOSTaskIF {
public: public:
/** /**
* Keep in mind that you need to call before vTaskStartScheduler()! * Keep in mind that you need to call before vTaskStartScheduler()!
* A lot of task parameters are set in "FreeRTOSConfig.h". * A lot of task parameters are set in "FreeRTOSConfig.h".
* @param name Name of the task, lenght limited by configMAX_TASK_NAME_LEN * @param name Name of the task, lenght limited by configMAX_TASK_NAME_LEN
* @param setPriority Number of priorities specified by * @param setPriority Number of priorities specified by
* configMAX_PRIORITIES. High taskPriority_ number means high priority. * configMAX_PRIORITIES. High taskPriority_ number means high priority.
* @param setStack Stack size in words (not bytes!). * @param setStack Stack size in words (not bytes!).
* Lower limit specified by configMINIMAL_STACK_SIZE * Lower limit specified by configMINIMAL_STACK_SIZE
* @param overallPeriod Period in seconds. * @param overallPeriod Period in seconds.
* @param setDeadlineMissedFunc Callback if a deadline was missed. * @param setDeadlineMissedFunc Callback if a deadline was missed.
* @return Pointer to the newly created task. * @return Pointer to the newly created task.
*/ */
FixedTimeslotTask(TaskName name, TaskPriority setPriority, FixedTimeslotTask(TaskName name, TaskPriority setPriority,
TaskStackSize setStack, TaskPeriod overallPeriod, TaskStackSize setStack, TaskPeriod overallPeriod,
void (*setDeadlineMissedFunc)()); void (*setDeadlineMissedFunc)());
/** /**
* @brief The destructor of the class. * @brief The destructor of the class.
* @details * @details
* The destructor frees all heap memory that was allocated on thread * The destructor frees all heap memory that was allocated on thread
* initialization for the PST and the device handlers. This is done by * initialization for the PST and the device handlers. This is done by
* calling the PST's destructor. * calling the PST's destructor.
*/ */
virtual ~FixedTimeslotTask(void); virtual ~FixedTimeslotTask(void);
ReturnValue_t startTask(void); ReturnValue_t startTask(void);
/** /**
* This static function can be used as #deadlineMissedFunc. * This static function can be used as #deadlineMissedFunc.
* It counts missedDeadlines and prints the number of missed deadlines * It counts missedDeadlines and prints the number of missed deadlines
* every 10th time. * every 10th time.
*/ */
static void missedDeadlineCounter(); static void missedDeadlineCounter();
/** /**
* A helper variable to count missed deadlines. * A helper variable to count missed deadlines.
*/ */
static uint32_t deadlineMissedCount; static uint32_t deadlineMissedCount;
ReturnValue_t addSlot(object_id_t componentId, uint32_t slotTimeMs, ReturnValue_t addSlot(object_id_t componentId, uint32_t slotTimeMs,
int8_t executionStep) override; int8_t executionStep) override;
uint32_t getPeriodMs() const override; uint32_t getPeriodMs() const override;
ReturnValue_t checkSequence() const override; ReturnValue_t checkSequence() const override;
ReturnValue_t sleepFor(uint32_t ms) override; ReturnValue_t sleepFor(uint32_t ms) override;
TaskHandle_t getTaskHandle() override; TaskHandle_t getTaskHandle() override;
protected: protected:
bool started; bool started;
TaskHandle_t handle; TaskHandle_t handle;
FixedSlotSequence pst; FixedSlotSequence pst;
/** /**
* @brief This attribute holds a function pointer that is executed when * @brief This attribute holds a function pointer that is executed when
* a deadline was missed. * a deadline was missed.
* @details * @details
* Another function may be announced to determine the actions to perform * Another function may be announced to determine the actions to perform
* when a deadline was missed. Currently, only one function for missing * when a deadline was missed. Currently, only one function for missing
* any deadline is allowed. If not used, it shall be declared NULL. * any deadline is allowed. If not used, it shall be declared NULL.
*/ */
void (*deadlineMissedFunc)(void); void (*deadlineMissedFunc)(void);
/** /**
* @brief This is the entry point for a new task. * @brief This is the entry point for a new task.
* @details * @details
* This method starts the task by calling taskFunctionality(), as soon as * This method starts the task by calling taskFunctionality(), as soon as
* all requirements (task scheduler has started and startTask() * all requirements (task scheduler has started and startTask()
* has been called) are met. * has been called) are met.
*/ */
static void taskEntryPoint(void* argument); static void taskEntryPoint(void* argument);
/** /**
* @brief This function holds the main functionality of the thread. * @brief This function holds the main functionality of the thread.
* @details * @details
* Core function holding the main functionality of the task * Core function holding the main functionality of the task
* It links the functionalities provided by FixedSlotSequence with the * It links the functionalities provided by FixedSlotSequence with the
* OS's System Calls to keep the timing of the periods. * OS's System Calls to keep the timing of the periods.
*/ */
void taskFunctionality(void); void taskFunctionality(void);
void checkMissedDeadline(const TickType_t xLastWakeTime, void checkMissedDeadline(const TickType_t xLastWakeTime,
const TickType_t interval); const TickType_t interval);
void handleMissedDeadline(); void handleMissedDeadline();
}; };
#endif /* POLLINGTASK_H_ */ #endif /* POLLINGTASK_H_ */