timeslot update for FreeRTOS

This commit is contained in:
Robin Müller 2020-08-27 16:05:31 +02:00
parent 9465c8f2b2
commit 66cf2d3559
7 changed files with 647 additions and 619 deletions

View File

@ -1,20 +0,0 @@
/**
* @file PollingSlot.cpp
* @brief This file defines the PollingSlot class.
* @date 19.12.2012
* @author baetz
*/
#include "FixedSequenceSlot.h"
#include "../objectmanager/SystemObjectIF.h"
#include <cstddef>
FixedSequenceSlot::FixedSequenceSlot(object_id_t handlerId, uint32_t setTime,
int8_t setSequenceId, PeriodicTaskIF* executingTask) :
handler(NULL), pollingTimeMs(setTime), opcode(setSequenceId) {
handler = objectManager->get<ExecutableObjectIF>(handlerId);
handler->setTaskIF(executingTask);
}
FixedSequenceSlot::~FixedSequenceSlot() {}

View File

@ -1,162 +1,166 @@
#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(NULL), 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) {
if (objectManager->get<ExecutableObjectIF>(componentId) != nullptr) { ExecutableObjectIF* handler =
pst.addSlot(componentId, slotTimeMs, executionStep, this); objectManager->get<ExecutableObjectIF>(componentId);
return HasReturnvaluesIF::RETURN_OK; if (handler != nullptr) {
} pst.addSlot(componentId, slotTimeMs, executionStep, handler, this);
return HasReturnvaluesIF::RETURN_OK;
sif::error << "Component " << std::hex << componentId << }
" not found, not adding it to pst" << std::endl;
return HasReturnvaluesIF::RETURN_FAILED; sif::error << "Component " << std::hex << componentId <<
} " not found, not adding it to pst" << std::endl;
return HasReturnvaluesIF::RETURN_FAILED;
uint32_t FixedTimeslotTask::getPeriodMs() const { }
return pst.getLengthMs();
} uint32_t FixedTimeslotTask::getPeriodMs() const {
return pst.getLengthMs();
ReturnValue_t FixedTimeslotTask::checkSequence() const { }
return pst.checkSequence();
} ReturnValue_t FixedTimeslotTask::checkSequence() const {
return pst.checkSequence();
void FixedTimeslotTask::taskFunctionality() { }
// A local iterator for the Polling Sequence Table is created to find the
// start time for the first entry. void FixedTimeslotTask::taskFunctionality() {
auto slotListIter = pst.current; // A local iterator for the Polling Sequence Table is created to find the
// start time for the first entry.
//The start time for the first entry is read. auto slotListIter = pst.current;
uint32_t intervalMs = slotListIter->pollingTimeMs;
TickType_t interval = pdMS_TO_TICKS(intervalMs); pst.intializeSequenceAfterTaskCreation();
TickType_t xLastWakeTime; //The start time for the first entry is read.
/* The xLastWakeTime variable needs to be initialized with the current tick uint32_t intervalMs = slotListIter->pollingTimeMs;
count. Note that this is the only time the variable is written to TickType_t interval = pdMS_TO_TICKS(intervalMs);
explicitly. After this assignment, xLastWakeTime is updated automatically
internally within vTaskDelayUntil(). */ TickType_t xLastWakeTime;
xLastWakeTime = xTaskGetTickCount(); /* The xLastWakeTime variable needs to be initialized with the current tick
count. Note that this is the only time the variable is written to
// wait for first entry's start time explicitly. After this assignment, xLastWakeTime is updated automatically
if(interval > 0) { internally within vTaskDelayUntil(). */
vTaskDelayUntil(&xLastWakeTime, interval); xLastWakeTime = xTaskGetTickCount();
}
// wait for first entry's start time
/* Enter the loop that defines the task behavior. */ if(interval > 0) {
for (;;) { vTaskDelayUntil(&xLastWakeTime, interval);
//The component for this slot is executed and the next one is chosen. }
this->pst.executeAndAdvance();
if (not pst.slotFollowsImmediately()) { /* Enter the loop that defines the task behavior. */
// Get the interval till execution of the next slot. for (;;) {
intervalMs = this->pst.getIntervalToPreviousSlotMs(); //The component for this slot is executed and the next one is chosen.
interval = pdMS_TO_TICKS(intervalMs); this->pst.executeAndAdvance();
if (not pst.slotFollowsImmediately()) {
checkMissedDeadline(xLastWakeTime, interval); // Get the interval till execution of the next slot.
intervalMs = this->pst.getIntervalToPreviousSlotMs();
// Wait for the interval. This exits immediately if a deadline was interval = pdMS_TO_TICKS(intervalMs);
// missed while also updating the last wake time.
vTaskDelayUntil(&xLastWakeTime, interval); checkMissedDeadline(xLastWakeTime, interval);
}
} // Wait for the interval. This exits immediately if a deadline was
} // missed while also updating the last wake time.
vTaskDelayUntil(&xLastWakeTime, interval);
void FixedTimeslotTask::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. */ void FixedTimeslotTask::checkMissedDeadline(const TickType_t xLastWakeTime,
TickType_t currentTickCount = xTaskGetTickCount(); const TickType_t interval) {
TickType_t timeToWake = xLastWakeTime + interval; /* Check whether deadline was missed while also taking overflows
// Time to wake has not overflown. * into account. Drawing this on paper with a timeline helps to understand
if(timeToWake > xLastWakeTime) { * it. */
/* If the current time has overflown exclusively or the current TickType_t currentTickCount = xTaskGetTickCount();
* tick count is simply larger than the time to wake, a deadline was TickType_t timeToWake = xLastWakeTime + interval;
* missed */ // Time to wake has not overflown.
if((currentTickCount < xLastWakeTime) or (currentTickCount > timeToWake)) { if(timeToWake > xLastWakeTime) {
handleMissedDeadline(); /* If the current time has overflown exclusively or the current
} * tick count is simply larger than the time to wake, a deadline was
} * missed */
/* Time to wake has overflown. A deadline was missed if the current time if((currentTickCount < xLastWakeTime) or (currentTickCount > timeToWake)) {
* is larger than the time to wake */ handleMissedDeadline();
else if((timeToWake < xLastWakeTime) and (currentTickCount > timeToWake)) { }
handleMissedDeadline(); }
} /* Time to wake has overflown. A deadline was missed if the current time
} * is larger than the time to wake */
else if((timeToWake < xLastWakeTime) and (currentTickCount > timeToWake)) {
void FixedTimeslotTask::handleMissedDeadline() { handleMissedDeadline();
#ifdef DEBUG }
sif::warning << "FixedTimeslotTask: " << pcTaskGetName(NULL) << }
" missed deadline!\n" << std::flush;
#endif void FixedTimeslotTask::handleMissedDeadline() {
if(deadlineMissedFunc != nullptr) { #ifdef DEBUG
this->deadlineMissedFunc(); sif::warning << "FixedTimeslotTask: " << pcTaskGetName(NULL) <<
} " missed deadline!\n" << std::flush;
} #endif
if(deadlineMissedFunc != nullptr) {
ReturnValue_t FixedTimeslotTask::sleepFor(uint32_t ms) { this->deadlineMissedFunc();
vTaskDelay(pdMS_TO_TICKS(ms)); }
return HasReturnvaluesIF::RETURN_OK; }
}
ReturnValue_t FixedTimeslotTask::sleepFor(uint32_t ms) {
TaskHandle_t FixedTimeslotTask::getTaskHandle() { vTaskDelay(pdMS_TO_TICKS(ms));
return handle; return HasReturnvaluesIF::RETURN_OK;
} }
TaskHandle_t FixedTimeslotTask::getTaskHandle() {
return handle;
}

View File

@ -1,102 +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 "FreeRTOSTaskIF.h" #include "../../osal/FreeRTOS/FreeRTOSTaskIF.h"
#include "../../devicehandlers/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 /* FRAMEWORK_OSAL_FREERTOS_FIXEDTIMESLOTTASK_H_ */

View File

@ -0,0 +1,17 @@
#include "FixedSequenceSlot.h"
#include "../objectmanager/SystemObjectIF.h"
#include <cstddef>
FixedSequenceSlot::FixedSequenceSlot(object_id_t handlerId, uint32_t setTime,
int8_t setSequenceId, ExecutableObjectIF* executableObject,
PeriodicTaskIF* executingTask) :
pollingTimeMs(setTime), opcode(setSequenceId) {
if(executableObject == nullptr) {
return;
}
this->executableObject = executableObject;
this->executableObject->setTaskIF(executingTask);
}
FixedSequenceSlot::~FixedSequenceSlot() {}

View File

@ -1,60 +1,57 @@
/** #ifndef FRAMEWORK_TASKS_FIXEDSEQUENCESLOT_H_
* @file FixedSequenceSlot.h #define FRAMEWORK_TASKS_FIXEDSEQUENCESLOT_H_
* @brief This file defines the PollingSlot class.
* @date 19.12.2012 #include "../objectmanager/ObjectManagerIF.h"
* @author baetz #include "../tasks/ExecutableObjectIF.h"
*/ class PeriodicTaskIF;
#ifndef FIXEDSEQUENCESLOT_H_ /**
#define FIXEDSEQUENCESLOT_H_ * @brief This class is the representation of a single polling sequence
* table entry.
#include "../objectmanager/ObjectManagerIF.h" * @details
#include "../tasks/ExecutableObjectIF.h" * The PollingSlot class is the representation of a single polling
class PeriodicTaskIF; * sequence table entry.
* @author baetz
/** */
* @brief This class is the representation of a single polling sequence table entry. class FixedSequenceSlot {
* public:
* @details The PollingSlot class is the representation of a single polling FixedSequenceSlot( object_id_t handlerId, uint32_t setTimeMs,
* sequence table entry. int8_t setSequenceId, ExecutableObjectIF* executableObject,
*/ PeriodicTaskIF* executingTask);
class FixedSequenceSlot { virtual ~FixedSequenceSlot();
public:
FixedSequenceSlot( object_id_t handlerId, uint32_t setTimeMs, /**
int8_t setSequenceId, PeriodicTaskIF* executingTask ); * @brief Handler identifies which object is executed in this slot.
virtual ~FixedSequenceSlot(); */
ExecutableObjectIF* executableObject = nullptr;
/**
* @brief Handler identifies which device handler object is executed in this slot. /**
*/ * @brief This attribute defines when a device handler object is executed.
ExecutableObjectIF* handler; * @details
* The pollingTime attribute identifies the time the handler is
/** * executed in ms. It must be smaller than the period length of the
* @brief This attribute defines when a device handler object is executed. * polling sequence.
* */
* @details The pollingTime attribute identifies the time the handler is executed in ms. uint32_t pollingTimeMs;
* It must be smaller than the period length of the polling sequence.
*/ /**
uint32_t pollingTimeMs; * @brief This value defines the type of device communication.
*
/** * @details The state of this value decides what communication routine is
* @brief This value defines the type of device communication. * called in the PST executable or the device handler object.
* */
* @details The state of this value decides what communication routine is uint8_t opcode;
* called in the PST executable or the device handler object.
*/ /**
uint8_t opcode; * @brief Operator overload for the comparison operator to
* allow sorting by polling time.
/** * @param fixedSequenceSlot
* @brief Operator overload for the comparison operator to * @return
* allow sorting by polling time. */
* @param fixedSequenceSlot bool operator <(const FixedSequenceSlot & fixedSequenceSlot) const {
* @return return pollingTimeMs < fixedSequenceSlot.pollingTimeMs;
*/ }
bool operator <(const FixedSequenceSlot & fixedSequenceSlot) const { };
return pollingTimeMs < fixedSequenceSlot.pollingTimeMs;
}
}; #endif /* FIXEDSEQUENCESLOT_H_ */
#endif /* FIXEDSEQUENCESLOT_H_ */

View File

@ -1,123 +1,147 @@
#include "FixedSlotSequence.h" #include "FixedSlotSequence.h"
#include "../serviceinterface/ServiceInterfaceStream.h" #include "../serviceinterface/ServiceInterfaceStream.h"
#include <cstdlib>
FixedSlotSequence::FixedSlotSequence(uint32_t setLengthMs) :
lengthMs(setLengthMs) { FixedSlotSequence::FixedSlotSequence(uint32_t setLengthMs) :
current = slotList.begin(); lengthMs(setLengthMs) {
} current = slotList.begin();
}
FixedSlotSequence::~FixedSlotSequence() {
// Call the destructor on each list entry. FixedSlotSequence::~FixedSlotSequence() {
slotList.clear(); // Call the destructor on each list entry.
} slotList.clear();
}
void FixedSlotSequence::executeAndAdvance() {
current->handler->performOperation(current->opcode); void FixedSlotSequence::executeAndAdvance() {
// if (returnValue != RETURN_OK) { current->executableObject->performOperation(current->opcode);
// this->sendErrorMessage( returnValue ); // if (returnValue != RETURN_OK) {
// } // this->sendErrorMessage( returnValue );
//Increment the polling Sequence iterator // }
this->current++; //Increment the polling Sequence iterator
//Set it to the beginning, if the list's end is reached. this->current++;
if (this->current == this->slotList.end()) { //Set it to the beginning, if the list's end is reached.
this->current = this->slotList.begin(); if (this->current == this->slotList.end()) {
} this->current = this->slotList.begin();
} }
}
uint32_t FixedSlotSequence::getIntervalToNextSlotMs() {
uint32_t oldTime; uint32_t FixedSlotSequence::getIntervalToNextSlotMs() {
SlotListIter slotListIter = current; uint32_t oldTime;
// Get the pollingTimeMs of the current slot object. SlotListIter slotListIter = current;
oldTime = slotListIter->pollingTimeMs; // Get the pollingTimeMs of the current slot object.
// Advance to the next object. oldTime = slotListIter->pollingTimeMs;
slotListIter++; // Advance to the next object.
// Find the next interval which is not 0. slotListIter++;
while (slotListIter != slotList.end()) { // Find the next interval which is not 0.
if (oldTime != slotListIter->pollingTimeMs) { while (slotListIter != slotList.end()) {
return slotListIter->pollingTimeMs - oldTime; if (oldTime != slotListIter->pollingTimeMs) {
} else { return slotListIter->pollingTimeMs - oldTime;
slotListIter++; } else {
} slotListIter++;
} }
// If the list end is reached (this is definitely an interval != 0), }
// the interval is calculated by subtracting the remaining time of the PST // If the list end is reached (this is definitely an interval != 0),
// and adding the start time of the first handler in the list. // the interval is calculated by subtracting the remaining time of the PST
slotListIter = slotList.begin(); // and adding the start time of the first handler in the list.
return lengthMs - oldTime + slotListIter->pollingTimeMs; slotListIter = slotList.begin();
} return lengthMs - oldTime + slotListIter->pollingTimeMs;
}
uint32_t FixedSlotSequence::getIntervalToPreviousSlotMs() {
uint32_t currentTime; uint32_t FixedSlotSequence::getIntervalToPreviousSlotMs() {
SlotListIter slotListIter = current; uint32_t currentTime;
// Get the pollingTimeMs of the current slot object. SlotListIter slotListIter = current;
currentTime = slotListIter->pollingTimeMs; // Get the pollingTimeMs of the current slot object.
currentTime = slotListIter->pollingTimeMs;
//if it is the first slot, calculate difference to last slot
if (slotListIter == slotList.begin()){ //if it is the first slot, calculate difference to last slot
return lengthMs - (--slotList.end())->pollingTimeMs + currentTime; if (slotListIter == slotList.begin()){
} return lengthMs - (--slotList.end())->pollingTimeMs + currentTime;
// get previous slot }
slotListIter--; // get previous slot
slotListIter--;
return currentTime - slotListIter->pollingTimeMs;
} return currentTime - slotListIter->pollingTimeMs;
}
bool FixedSlotSequence::slotFollowsImmediately() {
uint32_t currentTime = current->pollingTimeMs; bool FixedSlotSequence::slotFollowsImmediately() {
SlotListIter fixedSequenceIter = this->current; uint32_t currentTime = current->pollingTimeMs;
// Get the pollingTimeMs of the current slot object. SlotListIter fixedSequenceIter = this->current;
if (fixedSequenceIter == slotList.begin()) // Get the pollingTimeMs of the current slot object.
return false; if (fixedSequenceIter == slotList.begin())
fixedSequenceIter--; return false;
if (fixedSequenceIter->pollingTimeMs == currentTime) { fixedSequenceIter--;
return true; if (fixedSequenceIter->pollingTimeMs == currentTime) {
} else { return true;
return false; } else {
} return false;
} }
}
uint32_t FixedSlotSequence::getLengthMs() const {
return this->lengthMs; uint32_t FixedSlotSequence::getLengthMs() const {
} return this->lengthMs;
}
ReturnValue_t FixedSlotSequence::checkSequence() const {
if(slotList.empty()) { void FixedSlotSequence::addSlot(object_id_t componentId, uint32_t slotTimeMs,
sif::error << "Fixed Slot Sequence: Slot list is empty!" << std::endl; int8_t executionStep, ExecutableObjectIF* executableObject,
return HasReturnvaluesIF::RETURN_FAILED; PeriodicTaskIF* executingTask) {
} this->slotList.insert(FixedSequenceSlot(componentId, slotTimeMs,
executionStep, executableObject, executingTask));
auto slotIt = slotList.begin(); this->current = slotList.begin();
uint32_t count = 0; }
uint32_t time = 0;
while (slotIt != slotList.end()) { ReturnValue_t FixedSlotSequence::checkSequence() const {
if (slotIt->handler == nullptr) { if(slotList.empty()) {
sif::error << "FixedSlotSequene::initialize: ObjectId does not exist!" sif::error << "Fixed Slot Sequence: Slot list is empty!" << std::endl;
<< std::endl; return HasReturnvaluesIF::RETURN_FAILED;
count++; }
} else if (slotIt->pollingTimeMs < time) {
sif::error << "FixedSlotSequence::initialize: Time: " uint32_t count = 0;
<< slotIt->pollingTimeMs uint32_t time = 0;
<< " is smaller than previous with " << time << std::endl; for(const auto& slot: slotList) {
count++; if (slot.executableObject == nullptr) {
} else { count++;
// All ok, print slot. }
//info << "Current slot polling time: " << std::endl; else if (slot.pollingTimeMs < time) {
//info << std::dec << slotIt->pollingTimeMs << std::endl; sif::error << "FixedSlotSequence::initialize: Time: "
} << slot.pollingTimeMs << " is smaller than previous with "
time = slotIt->pollingTimeMs; << time << std::endl;
slotIt++; count++;
} }
//info << "Number of elements in slot list: " else {
// << slotList.size() << std::endl; // All ok, print slot.
if (count > 0) { //sif::info << "Current slot polling time: " << std::endl;
return HasReturnvaluesIF::RETURN_FAILED; //sif::info << std::dec << slotIt->pollingTimeMs << std::endl;
} }
return HasReturnvaluesIF::RETURN_OK; time = slot.pollingTimeMs;
}
}
void FixedSlotSequence::addSlot(object_id_t componentId, uint32_t slotTimeMs, //sif::info << "Number of elements in slot list: "
int8_t executionStep, PeriodicTaskIF* executingTask) { // << slotList.size() << std::endl;
this->slotList.insert(FixedSequenceSlot(componentId, slotTimeMs, executionStep, if (count > 0) {
executingTask)); return HasReturnvaluesIF::RETURN_FAILED;
this->current = slotList.begin(); }
} return HasReturnvaluesIF::RETURN_OK;
}
ReturnValue_t FixedSlotSequence::intializeSequenceAfterTaskCreation() const {
std::set<ExecutableObjectIF*> uniqueObjects;
uint32_t count = 0;
for(const auto& slot: slotList) {
// Ensure that each unique object is initialized once.
if(uniqueObjects.find(slot.executableObject) == uniqueObjects.end()) {
ReturnValue_t result =
slot.executableObject->initializeAfterTaskCreation();
if(result != HasReturnvaluesIF::RETURN_OK) {
count++;
}
uniqueObjects.emplace(slot.executableObject);
}
}
if (count > 0) {
sif::error << "FixedSlotSequence::intializeSequenceAfterTaskCreation:"
"Counted " << count << " failed initializations!" << std::endl;
return HasReturnvaluesIF::RETURN_FAILED;
}
return HasReturnvaluesIF::RETURN_OK;
}

View File

@ -1,152 +1,159 @@
#ifndef FRAMEWORK_DEVICEHANDLERS_FIXEDSLOTSEQUENCE_H_ #ifndef FRAMEWORK_TASKS_FIXEDSLOTSEQUENCE_H_
#define FRAMEWORK_DEVICEHANDLERS_FIXEDSLOTSEQUENCE_H_ #define FRAMEWORK_TASKS_FIXEDSLOTSEQUENCE_H_
#include "FixedSequenceSlot.h" #include "FixedSequenceSlot.h"
#include "../objectmanager/SystemObject.h" #include "../objectmanager/SystemObject.h"
#include <set>
#include <set>
/**
* @brief This class is the representation of a Polling Sequence Table in software. /**
* * @brief This class is the representation of a Polling Sequence Table in software.
* @details * @details
* The FixedSlotSequence object maintains the dynamic execution of * The FixedSlotSequence object maintains the dynamic execution of
* device handler objects. * device handler objects.
* *
* The main idea is to create a list of device handlers, to announce all * The main idea is to create a list of device handlers, to announce all
* handlers to thepolling sequence and to maintain a list of * handlers to thepolling sequence and to maintain a list of
* polling slot objects. This slot list represents the Polling Sequence Table * polling slot objects. This slot list represents the Polling Sequence Table
* in software. * in software.
* *
* Each polling slot contains information to indicate when and * Each polling slot contains information to indicate when and
* which device handler shall be executed within a given polling period. * which device handler shall be executed within a given polling period.
* The sequence is then executed by iterating through this slot list. * The sequence is then executed by iterating through this slot list.
* Handlers are invoking by calling a certain function stored in the handler list. * Handlers are invoking by calling a certain function stored in the handler list.
*/ */
class FixedSlotSequence { class FixedSlotSequence {
public: public:
using SlotList = std::multiset<FixedSequenceSlot>; using SlotList = std::multiset<FixedSequenceSlot>;
using SlotListIter = std::multiset<FixedSequenceSlot>::iterator; using SlotListIter = std::multiset<FixedSequenceSlot>::iterator;
/** /**
* @brief The constructor of the FixedSlotSequence object. * @brief The constructor of the FixedSlotSequence object.
* *
* @details The constructor takes two arguments, the period length and the init function. * @details The constructor takes two arguments, the period length and the init function.
* *
* @param setLength The period length, expressed in ms. * @param setLength The period length, expressed in ms.
*/ */
FixedSlotSequence(uint32_t setLengthMs); FixedSlotSequence(uint32_t setLengthMs);
/** /**
* @brief The destructor of the FixedSlotSequence object. * @brief The destructor of the FixedSlotSequence object.
* *
* @details The destructor frees all allocated memory by iterating through the slotList * @details The destructor frees all allocated memory by iterating through the slotList
* and deleting all allocated resources. * and deleting all allocated resources.
*/ */
virtual ~FixedSlotSequence(); virtual ~FixedSlotSequence();
/** /**
* @brief This is a method to add an PollingSlot object to slotList. * @brief This is a method to add an PollingSlot object to slotList.
* *
* @details Here, a polling slot object is added to the slot list. It is appended * @details Here, a polling slot object is added to the slot list. It is appended
* to the end of the list. The list is currently NOT reordered. * to the end of the list. The list is currently NOT reordered.
* Afterwards, the iterator current is set to the beginning of the list. * Afterwards, the iterator current is set to the beginning of the list.
* @param Object ID of the object to add * @param Object ID of the object to add
* @param setTime Value between (0 to 1) * slotLengthMs, when a FixedTimeslotTask * @param setTime Value between (0 to 1) * slotLengthMs, when a FixedTimeslotTask
* will be called inside the slot period. * will be called inside the slot period.
* @param setSequenceId ID which can be used to distinguish * @param setSequenceId ID which can be used to distinguish
* different task operations * different task operations
* @param * @param
* @param * @param
*/ */
void addSlot(object_id_t handlerId, uint32_t setTime, int8_t setSequenceId, void addSlot(object_id_t handlerId, uint32_t setTime, int8_t setSequenceId,
PeriodicTaskIF* executingTask); ExecutableObjectIF* executableObject, PeriodicTaskIF* executingTask);
/** /**
* Checks if the current slot shall be executed immediately after the one before. * Checks if the current slot shall be executed immediately after the one before.
* This allows to distinguish between grouped and not grouped handlers. * This allows to distinguish between grouped and not grouped handlers.
* @return - @c true if the slot has the same polling time as the previous * @return - @c true if the slot has the same polling time as the previous
* - @c false else * - @c false else
*/ */
bool slotFollowsImmediately(); bool slotFollowsImmediately();
/** /**
* @brief This method returns the time until the next software * @brief This method returns the time until the next software
* component is invoked. * component is invoked.
* *
* @details * @details
* This method is vitally important for the operation of the PST. * This method is vitally important for the operation of the PST.
* By fetching the polling time of the current slot and that of the * By fetching the polling time of the current slot and that of the
* next one (or the first one, if the list end is reached) * next one (or the first one, if the list end is reached)
* it calculates and returns the interval in milliseconds within * it calculates and returns the interval in milliseconds within
* which the handler execution shall take place. * which the handler execution shall take place.
* If the next slot has the same time as the current one, it is ignored * If the next slot has the same time as the current one, it is ignored
* until a slot with different time or the end of the PST is found. * until a slot with different time or the end of the PST is found.
*/ */
uint32_t getIntervalToNextSlotMs(); uint32_t getIntervalToNextSlotMs();
/** /**
* @brief This method returns the time difference between the current * @brief This method returns the time difference between the current
* slot and the previous slot * slot and the previous slot
* *
* @details * @details
* This method is vitally important for the operation of the PST. * This method is vitally important for the operation of the PST.
* By fetching the polling time of the current slot and that of the previous * By fetching the polling time of the current slot and that of the previous
* one (or the last one, if the slot is the first one) it calculates and * one (or the last one, if the slot is the first one) it calculates and
* returns the interval in milliseconds that the handler execution shall * returns the interval in milliseconds that the handler execution shall
* be delayed. * be delayed.
*/ */
uint32_t getIntervalToPreviousSlotMs(); uint32_t getIntervalToPreviousSlotMs();
/** /**
* @brief This method returns the length of this FixedSlotSequence instance. * @brief This method returns the length of this FixedSlotSequence instance.
*/ */
uint32_t getLengthMs() const; uint32_t getLengthMs() const;
/** /**
* @brief The method to execute the device handler entered in the current * @brief The method to execute the device handler entered in the current
* PollingSlot object. * PollingSlot object.
* *
* @details * @details
* Within this method the device handler object to be executed is chosen by * Within this method the device handler object to be executed is chosen by
* looking up the handler address of the current slot in the handlerMap. * looking up the handler address of the current slot in the handlerMap.
* Either the device handler's talkToInterface or its listenToInterface * Either the device handler's talkToInterface or its listenToInterface
* method is invoked, depending on the isTalking flag of the polling slot. * method is invoked, depending on the isTalking flag of the polling slot.
* After execution the iterator current is increased or, by reaching the * After execution the iterator current is increased or, by reaching the
* end of slotList, reset to the beginning. * end of slotList, reset to the beginning.
*/ */
void executeAndAdvance(); void executeAndAdvance();
/** /**
* @brief An iterator that indicates the current polling slot to execute. * @brief An iterator that indicates the current polling slot to execute.
* *
* @details This is an iterator for slotList and always points to the * @details This is an iterator for slotList and always points to the
* polling slot which is executed next. * polling slot which is executed next.
*/ */
SlotListIter current; SlotListIter current;
/** /**
* Iterate through slotList and check successful creation. * @brief Check and initialize slot list.
* Checks if timing is ok (must be ascending) and if all handlers were found. * @details
* @return * Checks if timing is ok (must be ascending) and if all handlers were found.
*/ * Also calls any initialization steps which are required after task
ReturnValue_t checkSequence() const; * creation.
* @return
protected: */
ReturnValue_t checkSequence() const;
/**
* @brief This list contains all PollingSlot objects, defining order and ReturnValue_t intializeSequenceAfterTaskCreation() const;
* execution time of the device handler objects.
* protected:
* @details
* The slot list is a std:list object that contains all created /**
* PollingSlot instances. They are NOT ordered automatically, so by * @brief This list contains all PollingSlot objects, defining order and
* adding entries, the correct order needs to be ensured. By iterating * execution time of the device handler objects.
* through this list the polling sequence is executed. Two entries with *
* identical polling times are executed immediately one after another. * @details
*/ * The slot list is a std:list object that contains all created
SlotList slotList; * PollingSlot instances. They are NOT ordered automatically, so by
* adding entries, the correct order needs to be ensured. By iterating
uint32_t lengthMs; * through this list the polling sequence is executed. Two entries with
}; * identical polling times are executed immediately one after another.
*/
#endif /* FIXEDSLOTSEQUENCE_H_ */ SlotList slotList;
uint32_t lengthMs;
bool isEmpty = false;
};
#endif /* FIXEDSLOTSEQUENCE_H_ */