all fixed slot sequence improvenements, freeRTOS

fix
This commit is contained in:
Robin Müller 2020-04-06 11:19:05 +02:00
parent cd7e47ccbb
commit 58008c8db5
5 changed files with 112 additions and 81 deletions

View File

@ -19,29 +19,34 @@ class PeriodicTaskIF;
*/ */
class FixedSequenceSlot { class FixedSequenceSlot {
public: public:
FixedSequenceSlot( object_id_t handlerId, uint32_t setTimeMs, int8_t setSequenceId, PeriodicTaskIF* executingTask ); FixedSequenceSlot( object_id_t handlerId, uint32_t setTimeMs,
int8_t setSequenceId, PeriodicTaskIF* executingTask );
virtual ~FixedSequenceSlot(); virtual ~FixedSequenceSlot();
/** /**
* \brief \c handler identifies which device handler object is executed in this slot. * @brief Handler identifies which device handler object is executed in this slot.
*/ */
ExecutableObjectIF* handler; ExecutableObjectIF* handler;
/** /**
* \brief This attribute defines when a device handler object is executed. * @brief This attribute defines when a device handler object is executed.
* *
* \details The pollingTime attribute identifies the time the handler is executed in ms. It must be * @details The pollingTime attribute identifies the time the handler is executed in ms.
* smaller than the period length of the polling sequence, what is ensured by automated calculation * It must be smaller than the period length of the polling sequence.
* from a database.
*/ */
uint32_t pollingTimeMs; uint32_t pollingTimeMs;
/** /**
* \brief This value defines the type of device communication. * \brief This value defines the type of device communication.
* *
* \details The state of this value decides what communication routine is called in the PST executable or the device handler object. * \details The state of this value decides what communication routine is
* called in the PST executable or the device handler object.
*/ */
uint8_t opcode; uint8_t opcode;
bool operator <(const FixedSequenceSlot & fixedSequenceSlot) const {
return pollingTimeMs < fixedSequenceSlot.pollingTimeMs;
}
}; };

View File

@ -2,22 +2,23 @@
#include <framework/serviceinterface/ServiceInterfaceStream.h> #include <framework/serviceinterface/ServiceInterfaceStream.h>
FixedSlotSequence::FixedSlotSequence(uint32_t setLengthMs) : FixedSlotSequence::FixedSlotSequence(uint32_t setLengthMs) :
lengthMs(setLengthMs) { slotLengthMs(setLengthMs) {
current = slotList.begin(); current = slotList.begin();
} }
FixedSlotSequence::~FixedSlotSequence() { FixedSlotSequence::~FixedSlotSequence() {
std::list<FixedSequenceSlot*>::iterator slotIt; // This should call the destructor on each list entry.
//Iterate through slotList and delete all entries. slotList.clear();
slotIt = this->slotList.begin(); // SlotListIter slotListIter = this->slotList.begin();
while (slotIt != this->slotList.end()) { // //Iterate through slotList and delete all entries.
delete (*slotIt); // while (slotListIter != this->slotList.end()) {
slotIt++; // delete (*slotIt);
} // slotIt++;
// }
} }
void FixedSlotSequence::executeAndAdvance() { void FixedSlotSequence::executeAndAdvance() {
(*this->current)->handler->performOperation((*this->current)->opcode); current->handler->performOperation(current->opcode);
// if (returnValue != RETURN_OK) { // if (returnValue != RETURN_OK) {
// this->sendErrorMessage( returnValue ); // this->sendErrorMessage( returnValue );
// } // }
@ -31,53 +32,50 @@ void FixedSlotSequence::executeAndAdvance() {
uint32_t FixedSlotSequence::getIntervalToNextSlotMs() { uint32_t FixedSlotSequence::getIntervalToNextSlotMs() {
uint32_t oldTime; uint32_t oldTime;
std::list<FixedSequenceSlot*>::iterator it; SlotListIter slotListIter = current;
it = current;
// Get the pollingTimeMs of the current slot object. // Get the pollingTimeMs of the current slot object.
oldTime = (*it)->pollingTimeMs; oldTime = slotListIter->pollingTimeMs;
// Advance to the next object. // Advance to the next object.
it++; slotListIter++;
// Find the next interval which is not 0. // Find the next interval which is not 0.
while (it != slotList.end()) { while (slotListIter != slotList.end()) {
if (oldTime != (*it)->pollingTimeMs) { if (oldTime != slotListIter->pollingTimeMs) {
return (*it)->pollingTimeMs - oldTime; return slotListIter->pollingTimeMs - oldTime;
} else { } else {
it++; slotListIter++;
} }
} }
// If the list end is reached (this is definitely an interval != 0), // If the list end is reached (this is definitely an interval != 0),
// the interval is calculated by subtracting the remaining time of the PST // the interval is calculated by subtracting the remaining time of the PST
// and adding the start time of the first handler in the list. // and adding the start time of the first handler in the list.
it = slotList.begin(); slotListIter = slotList.begin();
return lengthMs - oldTime + (*it)->pollingTimeMs; return slotLengthMs - oldTime + slotListIter->pollingTimeMs;
} }
uint32_t FixedSlotSequence::getIntervalToPreviousSlotMs() { uint32_t FixedSlotSequence::getIntervalToPreviousSlotMs() {
uint32_t currentTime; uint32_t currentTime;
std::list<FixedSequenceSlot*>::iterator it; SlotListIter slotListIter = current;
it = current;
// Get the pollingTimeMs of the current slot object. // Get the pollingTimeMs of the current slot object.
currentTime = (*it)->pollingTimeMs; currentTime = slotListIter->pollingTimeMs;
//if it is the first slot, calculate difference to last slot //if it is the first slot, calculate difference to last slot
if (it == slotList.begin()){ if (slotListIter == slotList.begin()){
return lengthMs - (*(--slotList.end()))->pollingTimeMs + currentTime; return slotLengthMs - (--slotList.end())->pollingTimeMs + currentTime;
} }
// get previous slot // get previous slot
it--; slotListIter--;
return currentTime - (*it)->pollingTimeMs; return currentTime - slotListIter->pollingTimeMs;
} }
bool FixedSlotSequence::slotFollowsImmediately() { bool FixedSlotSequence::slotFollowsImmediately() {
uint32_t currentTime = (*current)->pollingTimeMs; uint32_t currentTime = current->pollingTimeMs;
std::list<FixedSequenceSlot*>::iterator it; SlotListIter fixedSequenceIter = this->current;
it = this->current;
// Get the pollingTimeMs of the current slot object. // Get the pollingTimeMs of the current slot object.
if (it == slotList.begin()) if (fixedSequenceIter == slotList.begin())
return false; return false;
it--; fixedSequenceIter--;
if ((*it)->pollingTimeMs == currentTime) { if (fixedSequenceIter->pollingTimeMs == currentTime) {
return true; return true;
} else { } else {
return false; return false;
@ -85,31 +83,35 @@ bool FixedSlotSequence::slotFollowsImmediately() {
} }
uint32_t FixedSlotSequence::getLengthMs() const { uint32_t FixedSlotSequence::getLengthMs() const {
return this->lengthMs; return this->slotLengthMs;
} }
ReturnValue_t FixedSlotSequence::checkSequence() const { ReturnValue_t FixedSlotSequence::checkSequence() const {
//Iterate through slotList and check successful creation. Checks if timing is ok (must be ascending) and if all handlers were found. // Iterate through slotList and check successful creation.
// Checks if timing is ok (must be ascending) and if all handlers were found.
auto slotIt = slotList.begin(); auto slotIt = slotList.begin();
uint32_t count = 0; uint32_t count = 0;
uint32_t time = 0; uint32_t time = 0;
while (slotIt != slotList.end()) { while (slotIt != slotList.end()) {
if ((*slotIt)->handler == NULL) { if (slotIt->handler == NULL) {
error << "FixedSlotSequene::initialize: ObjectId does not exist!" error << "FixedSlotSequene::initialize: ObjectId does not exist!"
<< std::endl; << std::endl;
count++; count++;
} else if ((*slotIt)->pollingTimeMs < time) { } else if (slotIt->pollingTimeMs < time) {
error << "FixedSlotSequence::initialize: Time: " error << "FixedSlotSequence::initialize: Time: "
<< (*slotIt)->pollingTimeMs << slotIt->pollingTimeMs
<< " is smaller than previous with " << time << std::endl; << " is smaller than previous with " << time << std::endl;
count++; count++;
} else { } else {
//All ok, print slot. // All ok, print slot.
// (*slotIt)->print(); //info << "Current slot polling time: " << std::endl;
//info << std::dec << slotIt->pollingTimeMs << std::endl;
} }
time = (*slotIt)->pollingTimeMs; time = slotIt->pollingTimeMs;
slotIt++; slotIt++;
} }
//info << "Number of elements in slot list: "
// << slotList.size() << std::endl;
if (count > 0) { if (count > 0) {
return HasReturnvaluesIF::RETURN_FAILED; return HasReturnvaluesIF::RETURN_FAILED;
} }
@ -118,8 +120,7 @@ ReturnValue_t FixedSlotSequence::checkSequence() const {
void FixedSlotSequence::addSlot(object_id_t componentId, uint32_t slotTimeMs, void FixedSlotSequence::addSlot(object_id_t componentId, uint32_t slotTimeMs,
int8_t executionStep, PeriodicTaskIF* executingTask) { int8_t executionStep, PeriodicTaskIF* executingTask) {
this->slotList.push_back( this->slotList.insert(FixedSequenceSlot(componentId, slotTimeMs, executionStep,
new FixedSequenceSlot(componentId, slotTimeMs, executionStep, executingTask));
executingTask));
this->current = slotList.begin(); this->current = slotList.begin();
} }

View File

@ -4,11 +4,15 @@
#include <framework/devicehandlers/FixedSequenceSlot.h> #include <framework/devicehandlers/FixedSequenceSlot.h>
#include <framework/objectmanager/SystemObject.h> #include <framework/objectmanager/SystemObject.h>
#include <list> #include <list>
#include <set>
using SlotList = std::multiset<FixedSequenceSlot>;
using SlotListIter = std::multiset<FixedSequenceSlot>::iterator;
/** /**
* \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 The FixedSlotSequence object maintains the dynamic execution of device handler objects. * @details The FixedSlotSequence object maintains the dynamic execution of device handler objects.
* The main idea is to create a list of device handlers, to announce all handlers to the * The main idea is to create a list of device handlers, to announce all handlers to the
* polling sequence and to maintain a list of polling slot objects. This slot list represents the * polling sequence and to maintain a list of polling slot objects. This slot list represents the
* Polling Sequence Table in software. Each polling slot contains information to indicate when and * Polling Sequence Table in software. Each polling slot contains information to indicate when and
@ -19,29 +23,37 @@
class FixedSlotSequence { class FixedSlotSequence {
public: public:
/** /**
* \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 setTime Value between (0 to 1) * slotLengthMs, when a FixedTimeslotTask
* will be called inside the slot period.
* @param setSequenceId ID which can be used to distinguish
* different task operations
* @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); PeriodicTaskIF* executingTask);
@ -57,11 +69,14 @@ public:
/** /**
* \brief This method returns the time until the next software component is invoked. * \brief This method returns the time until the next software component is invoked.
* *
* \details This method is vitally important for the operation of the PST. By fetching the polling time * \details
* of the current slot and that of the next one (or the first one, if the list end is reached) * This method is vitally important for the operation of the PST.
* it calculates and returns the interval in milliseconds within which the handler execution * By fetching the polling time of the current slot and that of the
* shall take place. If the next slot has the same time as the current one, it is ignored until * next one (or the first one, if the list end is reached)
* a slot with different time or the end of the PST is found. * it calculates and returns the interval in milliseconds within
* which the handler execution shall take place.
* 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.
*/ */
uint32_t getIntervalToNextSlotMs(); uint32_t getIntervalToNextSlotMs();
@ -75,12 +90,12 @@ public:
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 OPUSPollingSlot object. * \brief The method to execute the device handler entered in the current PollingSlot object.
* *
* \details Within this method the device handler object to be executed is chosen by looking up the * \details 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. Either the device handler's * handler address of the current slot in the handlerMap. Either the device handler's
@ -91,27 +106,27 @@ public:
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 polling slot which is executed next. * @details This is an iterator for slotList and always points to the polling slot which is executed next.
*/ */
std::list<FixedSequenceSlot*>::iterator current; SlotListIter current;
ReturnValue_t checkSequence() const; virtual ReturnValue_t checkSequence() const;
protected: protected:
/** /**
* \brief This list contains all OPUSPollingSlot objects, defining order and execution time of the * @brief This list contains all PollingSlot objects, defining order and execution time of the
* device handler objects. * device handler objects.
* *
* \details The slot list is a std:list object that contains all created OPUSPollingSlot instances. * @details The slot list is a std:list object that contains all created PollingSlot instances.
* They are NOT ordered automatically, so by adding entries, the correct order needs to be ensured. * They are NOT ordered automatically, so by adding entries, the correct order needs to be ensured.
* By iterating through this list the polling sequence is executed. Two entries with identical * By iterating through this list the polling sequence is executed. Two entries with identical
* polling times are executed immediately one after another. * polling times are executed immediately one after another.
*/ */
std::list<FixedSequenceSlot*> slotList; SlotList slotList;
uint32_t lengthMs; uint32_t slotLengthMs;
}; };
#endif /* FIXEDSLOTSEQUENCE_H_ */ #endif /* FIXEDSLOTSEQUENCE_H_ */

View File

@ -19,8 +19,7 @@ FixedTimeslotTask::~FixedTimeslotTask() {
void FixedTimeslotTask::taskEntryPoint(void* argument) { void FixedTimeslotTask::taskEntryPoint(void* argument) {
//The argument is re-interpreted as FixedTimeslotTask. The Task object is global, so it is found from any place. //The argument is re-interpreted as FixedTimeslotTask. The Task object is global, so it is found from any place.
FixedTimeslotTask *originalTask( FixedTimeslotTask *originalTask(reinterpret_cast<FixedTimeslotTask*>(argument));
reinterpret_cast<FixedTimeslotTask*>(argument));
// Task should not start until explicitly requested // Task should not start until explicitly requested
// in FreeRTOS, tasks start as soon as they are created if the scheduler is running // in FreeRTOS, tasks start as soon as they are created if the scheduler is running
// but not if the scheduler is not running. // but not if the scheduler is not running.
@ -58,8 +57,19 @@ ReturnValue_t FixedTimeslotTask::startTask() {
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) {
pst.addSlot(componentId, slotTimeMs, executionStep, this); if (objectManager->get<ExecutableObjectIF>(componentId) != NULL) {
return HasReturnvaluesIF::RETURN_OK; if(slotTimeMs == 0) {
// TODO: FreeRTOS throws errors for zero values.
// maybe there is a better solution than this.
slotTimeMs = 1;
}
pst.addSlot(componentId, slotTimeMs, executionStep, this);
return HasReturnvaluesIF::RETURN_OK;
}
error << "Component " << std::hex << componentId
<< " not found, not adding it to pst" << std::endl;
return HasReturnvaluesIF::RETURN_FAILED;
} }
uint32_t FixedTimeslotTask::getPeriodMs() const { uint32_t FixedTimeslotTask::getPeriodMs() const {
@ -72,10 +82,10 @@ ReturnValue_t FixedTimeslotTask::checkSequence() const {
void FixedTimeslotTask::taskFunctionality() { void FixedTimeslotTask::taskFunctionality() {
// A local iterator for the Polling Sequence Table is created to find the start time for the first entry. // A local iterator for the Polling Sequence Table is created to find the start time for the first entry.
std::list<FixedSequenceSlot*>::iterator it = pst.current; SlotListIter slotListIter = pst.current;
//The start time for the first entry is read. //The start time for the first entry is read.
uint32_t intervalMs = (*it)->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;
@ -110,4 +120,3 @@ ReturnValue_t FixedTimeslotTask::sleepFor(uint32_t ms) {
vTaskDelay(pdMS_TO_TICKS(ms)); vTaskDelay(pdMS_TO_TICKS(ms));
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
} }

View File

@ -51,6 +51,7 @@ public:
ReturnValue_t checkSequence() const; ReturnValue_t checkSequence() const;
ReturnValue_t sleepFor(uint32_t ms); ReturnValue_t sleepFor(uint32_t ms);
protected: protected:
bool started; bool started;
TaskHandle_t handle; TaskHandle_t handle;