release 0.0.1 of fsfw added as a core

This commit is contained in:
2021-06-21 15:04:15 +02:00
parent b4e5534407
commit caea75b0a8
587 changed files with 55346 additions and 0 deletions

View File

@ -0,0 +1,53 @@
#ifndef FRAMEWORK_TASKS_EXECUTABLEOBJECTIF_H_
#define FRAMEWORK_TASKS_EXECUTABLEOBJECTIF_H_
class PeriodicTaskIF;
#include "../returnvalues/HasReturnvaluesIF.h"
#include <cstring>
/**
* @brief The interface provides a method to execute objects within a task.
* @details The performOperation method, that is required by the interface is
* executed cyclically within a task context.
* @author Bastian Baetz
*/
class ExecutableObjectIF {
public:
/**
* @brief This is the empty virtual destructor as required for C++ interfaces.
*/
virtual ~ExecutableObjectIF() { }
/**
* @brief The performOperation method is executed in a task.
* @details There are no restrictions for calls within this method, so any
* other member of the class can be used.
* @return Currently, the return value is ignored.
*/
virtual ReturnValue_t performOperation(uint8_t operationCode = 0) = 0;
/**
* @brief Function called during setup assignment of object to task
* @details
* Has to be called from the function that assigns the object to a task and
* enables the object implementation to overwrite this function and get
* a reference to the executing task
* @param task_ Pointer to the taskIF of this task
*/
virtual void setTaskIF(PeriodicTaskIF* task_) {};
/**
* This function should be called after the object was assigned to a
* specific task.
*
* Example: Can be used to get task execution frequency.
* The task is created after initialize() and the object ctors have been
* called so the execution frequency can't be cached in initialize()
* @return
*/
virtual ReturnValue_t initializeAfterTaskCreation() {
return HasReturnvaluesIF::RETURN_OK;
}
};
#endif /* FRAMEWORK_TASKS_EXECUTABLEOBJECTIF_H_ */

View File

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

View File

@ -0,0 +1,60 @@
#ifndef FSFW_TASKS_FIXEDSEQUENCESLOT_H_
#define FSFW_TASKS_FIXEDSEQUENCESLOT_H_
#include "ExecutableObjectIF.h"
#include "../objectmanager/ObjectManagerIF.h"
class PeriodicTaskIF;
/**
* @brief This class is the representation of a single polling sequence
* table entry.
* @details
* The PollingSlot class is the representation of a single polling
* sequence table entry.
* @author baetz
*/
class FixedSequenceSlot {
public:
FixedSequenceSlot( object_id_t handlerId, uint32_t setTimeMs,
int8_t setSequenceId, ExecutableObjectIF* executableObject,
PeriodicTaskIF* executingTask);
virtual ~FixedSequenceSlot();
object_id_t handlerId;
/**
* @brief Handler identifies which object is executed in this slot.
*/
ExecutableObjectIF* executableObject = nullptr;
/**
* @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 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
* 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
* @return
*/
bool operator <(const FixedSequenceSlot & fixedSequenceSlot) const {
return pollingTimeMs < fixedSequenceSlot.pollingTimeMs;
}
};
#endif /* FSFW_TASKS_FIXEDSEQUENCESLOT_H_ */

View File

@ -0,0 +1,162 @@
#include "FixedSlotSequence.h"
#include "../serviceinterface/ServiceInterfaceStream.h"
#include <cstdlib>
FixedSlotSequence::FixedSlotSequence(uint32_t setLengthMs) :
lengthMs(setLengthMs) {
current = slotList.begin();
}
FixedSlotSequence::~FixedSlotSequence() {
// Call the destructor on each list entry.
slotList.clear();
}
void FixedSlotSequence::executeAndAdvance() {
current->executableObject->performOperation(current->opcode);
// if (returnValue != RETURN_OK) {
// this->sendErrorMessage( returnValue );
// }
//Increment the polling Sequence iterator
this->current++;
//Set it to the beginning, if the list's end is reached.
if (this->current == this->slotList.end()) {
this->current = this->slotList.begin();
}
}
uint32_t FixedSlotSequence::getIntervalToNextSlotMs() {
uint32_t oldTime;
SlotListIter slotListIter = current;
// Get the pollingTimeMs of the current slot object.
oldTime = slotListIter->pollingTimeMs;
// Advance to the next object.
slotListIter++;
// Find the next interval which is not 0.
while (slotListIter != slotList.end()) {
if (oldTime != slotListIter->pollingTimeMs) {
return slotListIter->pollingTimeMs - oldTime;
} 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
// and adding the start time of the first handler in the list.
slotListIter = slotList.begin();
return lengthMs - oldTime + slotListIter->pollingTimeMs;
}
uint32_t FixedSlotSequence::getIntervalToPreviousSlotMs() {
uint32_t currentTime;
SlotListIter slotListIter = current;
// 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()){
return lengthMs - (--slotList.end())->pollingTimeMs + currentTime;
}
// get previous slot
slotListIter--;
return currentTime - slotListIter->pollingTimeMs;
}
bool FixedSlotSequence::slotFollowsImmediately() {
uint32_t currentTime = current->pollingTimeMs;
SlotListIter fixedSequenceIter = this->current;
// Get the pollingTimeMs of the current slot object.
if (fixedSequenceIter == slotList.begin())
return false;
fixedSequenceIter--;
if (fixedSequenceIter->pollingTimeMs == currentTime) {
return true;
} else {
return false;
}
}
uint32_t FixedSlotSequence::getLengthMs() const {
return this->lengthMs;
}
void FixedSlotSequence::addSlot(object_id_t componentId, uint32_t slotTimeMs,
int8_t executionStep, ExecutableObjectIF* executableObject,
PeriodicTaskIF* executingTask) {
this->slotList.insert(FixedSequenceSlot(componentId, slotTimeMs,
executionStep, executableObject, executingTask));
this->current = slotList.begin();
}
ReturnValue_t FixedSlotSequence::checkSequence() const {
if(slotList.empty()) {
sif::error << "FixedSlotSequence::checkSequence:"
<< " Slot list is empty!" << std::endl;
return HasReturnvaluesIF::RETURN_FAILED;
}
if(customCheckFunction != nullptr) {
ReturnValue_t result = customCheckFunction(slotList);
if(result != HasReturnvaluesIF::RETURN_OK) {
// Continue for now but print error output.
sif::error << "FixedSlotSequence::checkSequence:"
<< " Custom check failed!" << std::endl;
}
}
uint32_t errorCount = 0;
uint32_t time = 0;
for(const auto& slot: slotList) {
if (slot.executableObject == nullptr) {
errorCount++;
}
else if (slot.pollingTimeMs < time) {
sif::error << "FixedSlotSequence::checkSequence: Time: "
<< slot.pollingTimeMs << " is smaller than previous with "
<< time << std::endl;
errorCount++;
}
else {
// All ok, print slot.
//sif::info << "Current slot polling time: " << std::endl;
//sif::info << std::dec << slotIt->pollingTimeMs << std::endl;
}
time = slot.pollingTimeMs;
}
//sif::info << "Number of elements in slot list: "
// << slotList.size() << std::endl;
if (errorCount > 0) {
return HasReturnvaluesIF::RETURN_FAILED;
}
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;
}
void FixedSlotSequence::addCustomCheck(ReturnValue_t
(*customCheckFunction)(const SlotList&)) {
this->customCheckFunction = customCheckFunction;
}

View File

@ -0,0 +1,181 @@
#ifndef FSFW_TASKS_FIXEDSLOTSEQUENCE_H_
#define FSFW_TASKS_FIXEDSLOTSEQUENCE_H_
#include "FixedSequenceSlot.h"
#include "../objectmanager/SystemObject.h"
#include <set>
/**
* @brief This class is the representation of a
* Polling Sequence Table in software.
* @details
* The FixedSlotSequence object maintains the dynamic execution of
* objects with stricter timing requirements for the FixedTimeslotTask.
*
* The main idea is to create a list of executable objects (for example
* 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 Table in software.
*
* Each polling slot contains information to indicate when and
* which executable object shall be executed within a given polling period.
* When adding a slot, a pointer to the executing task, a pointer to the
* executable object and a step number can be passed. The step number will be
* passed to the periodic handler.
* The sequence is executed by iterating through the slot sequence and
* executing the executable object in the correct timeslot.
*/
class FixedSlotSequence {
public:
using SlotList = std::multiset<FixedSequenceSlot>;
using SlotListIter = std::multiset<FixedSequenceSlot>::iterator;
/**
* @brief The constructor of the FixedSlotSequence object.
* @param setLength The period length, expressed in ms.
*/
FixedSlotSequence(uint32_t setLengthMs);
/**
* @brief The destructor of the FixedSlotSequence object.
* @details
* The destructor frees all allocated memory by iterating through the
* slotList and deleting all allocated resources.
*/
virtual ~FixedSlotSequence();
/**
* @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
* to the end of the list. The list is currently NOT reordered.
* Afterwards, the iterator current is set to the beginning of the list.
* @param handlerId 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. This
* value will be passed to the executable function.
* @param
* @param
*/
void addSlot(object_id_t handlerId, uint32_t setTime, int8_t setSequenceId,
ExecutableObjectIF* executableObject,
PeriodicTaskIF* executingTask);
/**
* @brief Checks if the current slot shall be executed immediately
* after the one before.
* @details
* This allows to distinguish between grouped and separated handlers.
* @return - @c true if the slot has the same polling time as the previous
* - @c false else
*/
bool slotFollowsImmediately();
/**
* @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 of the current slot and that of the
* next one (or the first one, if the list end is reached)
* 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();
/**
* @brief This method returns the time difference between the current
* slot and the previous slot
*
* @details
* 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
* 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
* be delayed.
*/
uint32_t getIntervalToPreviousSlotMs();
/**
* @brief This method returns the length of this FixedSlotSequence instance.
*/
uint32_t getLengthMs() const;
/**
* @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 handler address of the current slot in the handlerMap.
* Either the device handler's talkToInterface or its listenToInterface
* method is invoked, depending on the isTalking flag of the polling slot.
* After execution the iterator current is increased or, by reaching the
* end of slotList, reset to the beginning.
*/
void executeAndAdvance();
/**
* @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.
*/
SlotListIter current;
/**
* @brief Check and initialize slot list.
* @details
* Checks if timing is ok (must be ascending) and if all handlers were found.
* @return
*/
ReturnValue_t checkSequence() const;
/**
* @brief A custom check can be injected for the respective slot list.
* @details
* This can be used by the developer to check the validity of a certain
* sequence. The function will be run in the #checkSequence function.
* The general check will be continued for now if the custom check function
* fails but a diagnostic debug output will be given.
* @param customCheckFunction
*/
void addCustomCheck(ReturnValue_t (*customCheckFunction)(const SlotList &));
/**
* @brief Perform any initialization steps required after the executing
* task has been created. This function should be called from the
* executing task!
* @return
*/
ReturnValue_t intializeSequenceAfterTaskCreation() const;
protected:
/**
* @brief This list contains all PollingSlot objects, defining order and
* execution time of the device handler objects.
*
* @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. By iterating
* through this list the polling sequence is executed. Two entries with
* identical polling times are executed immediately one after another.
*/
SlotList slotList;
ReturnValue_t (*customCheckFunction)(const SlotList&) = nullptr;
uint32_t lengthMs;
};
#endif /* FSFW_TASKS_FIXEDSLOTSEQUENCE_H_ */

View File

@ -0,0 +1,19 @@
#ifndef FRAMEWORK_TASKS_FIXEDTIMESLOTTASKIF_H_
#define FRAMEWORK_TASKS_FIXEDTIMESLOTTASKIF_H_
#include "../objectmanager/ObjectManagerIF.h"
#include "PeriodicTaskIF.h"
/**
* Following the same principle as the base class IF. This is the interface for a Fixed timeslot task
*/
class FixedTimeslotTaskIF : public PeriodicTaskIF {
public:
virtual ~FixedTimeslotTaskIF() {}
virtual ReturnValue_t addSlot(object_id_t componentId, uint32_t slotTimeMs, int8_t executionStep) = 0;
virtual ReturnValue_t checkSequence() const = 0;
};
#endif /* FRAMEWORK_TASKS_FIXEDTIMESLOTTASKIF_H_ */

View File

@ -0,0 +1,49 @@
#ifndef FRAMEWORK_TASK_PERIODICTASKIF_H_
#define FRAMEWORK_TASK_PERIODICTASKIF_H_
#include "../objectmanager/SystemObjectIF.h"
#include "../timemanager/Clock.h"
#include <cstddef>
class ExecutableObjectIF;
/**
* New version of TaskIF
* Follows RAII principles, i.e. there's no create or delete method.
* Minimalistic.
*/
class PeriodicTaskIF {
public:
static const size_t MINIMUM_STACK_SIZE;
/**
* @brief A virtual destructor as it is mandatory for interfaces.
*/
virtual ~PeriodicTaskIF() { }
/**
* @brief With the startTask method, a created task can be started
* for the first time.
*/
virtual ReturnValue_t startTask() = 0;
/**
* Add a component (object) to a periodic task. The pointer to the
* task can be set optionally
* @param object
* Add an object to the task. The most important case is to add an
* executable object with a function which will be called regularly
* (see ExecutableObjectIF)
* @param setTaskIF
* Can be used to specify whether the task object pointer is passed
* to the component.
* @return
*/
virtual ReturnValue_t addComponent(object_id_t object) {
return HasReturnvaluesIF::RETURN_FAILED;
};
virtual ReturnValue_t sleepFor(uint32_t ms) = 0;
virtual uint32_t getPeriodMs() const = 0;
};
#endif /* PERIODICTASKIF_H_ */

View File

@ -0,0 +1,50 @@
#ifndef FSFW_TASKS_SEMAPHOREFACTORY_H_
#define FSFW_TASKS_SEMAPHOREFACTORY_H_
#include "../tasks/SemaphoreIF.h"
/**
* Creates Semaphore.
* This class is a "singleton" interface, i.e. it provides an
* interface, but also is the base class for a singleton.
*/
class SemaphoreFactory {
public:
virtual ~SemaphoreFactory();
/**
* Returns the single instance of SemaphoreFactory.
* The implementation of #instance is found in its subclasses.
* Thus, we choose link-time variability of the instance.
*/
static SemaphoreFactory* instance();
/**
* Create a binary semaphore.
* Creator function for a binary semaphore which may only be acquired once
* @param argument Can be used to pass implementation specific information.
* @return Pointer to newly created semaphore class instance.
*/
SemaphoreIF* createBinarySemaphore(uint32_t arguments = 0);
/**
* Create a counting semaphore.
* Creator functons for a counting semaphore which may be acquired multiple
* times.
* @param count Semaphore can be taken count times.
* @param initCount Initial count value.
* @param argument Can be used to pass implementation specific information.
* @return
*/
SemaphoreIF* createCountingSemaphore(const uint8_t maxCount,
uint8_t initCount, uint32_t arguments = 0);
void deleteSemaphore(SemaphoreIF* semaphore);
private:
/**
* External instantiation is not allowed.
*/
SemaphoreFactory();
static SemaphoreFactory* factoryInstance;
};
#endif /* FSFW_TASKS_SEMAPHOREFACTORY_H_ */

68
fsfw/tasks/SemaphoreIF.h Normal file
View File

@ -0,0 +1,68 @@
#ifndef FRAMEWORK_TASKS_SEMAPHOREIF_H_
#define FRAMEWORK_TASKS_SEMAPHOREIF_H_
#include "../returnvalues/FwClassIds.h"
#include "../returnvalues/HasReturnvaluesIF.h"
#include <cstdint>
/**
* @brief Generic interface for semaphores, which can be used to achieve
* task synchronization. This is a generic interface which can be
* used for both binary semaphores and counting semaphores.
* @details
* A semaphore is a synchronization primitive.
* See: https://en.wikipedia.org/wiki/Semaphore_(programming)
* A semaphore can be used to achieve task synchonization and track the
* availability of resources by using either the binary or the counting
* semaphore types.
*
* If mutual exlcusion of a resource is desired, a mutex should be used,
* which is a special form of a semaphore and has an own interface.
*/
class SemaphoreIF {
public:
/**
* Different types of timeout for the mutex lock.
*/
enum TimeoutType {
POLLING, //!< If mutex is not available, return immediately
WAITING, //!< Wait a specified time for the mutex to become available
BLOCKING //!< Block indefinitely until the mutex becomes available.
};
virtual~ SemaphoreIF() {};
static const uint8_t INTERFACE_ID = CLASS_ID::SEMAPHORE_IF;
//! Semaphore timeout
static constexpr ReturnValue_t SEMAPHORE_TIMEOUT = MAKE_RETURN_CODE(1);
//! The current semaphore can not be given, because it is not owned
static constexpr ReturnValue_t SEMAPHORE_NOT_OWNED = MAKE_RETURN_CODE(2);
static constexpr ReturnValue_t SEMAPHORE_INVALID = MAKE_RETURN_CODE(3);
/**
* Generic call to acquire a semaphore.
* If there are no more semaphores to be taken (for a counting semaphore,
* a semaphore may be taken more than once), the taks will block
* for a maximum of timeoutMs while trying to acquire the semaphore.
* This can be used to achieve task synchrnization.
* @param timeoutMs
* @return - c RETURN_OK for successfull acquisition
*/
virtual ReturnValue_t acquire(TimeoutType timeoutType =
TimeoutType::BLOCKING, uint32_t timeoutMs = 0) = 0;
/**
* Corrensponding call to release a semaphore.
* @return -@c RETURN_OK for successfull release
*/
virtual ReturnValue_t release() = 0;
/**
* If the semaphore is a counting semaphore then the semaphores current
* count value is returned. If the semaphore is a binary semaphore then 1
* is returned if the semaphore is available, and 0 is returned if the
* semaphore is not available.
*/
virtual uint8_t getSemaphoreCounter() const = 0;
};
#endif /* FRAMEWORK_TASKS_SEMAPHOREIF_H_ */

72
fsfw/tasks/TaskFactory.h Normal file
View File

@ -0,0 +1,72 @@
#ifndef FRAMEWORK_TASKS_TASKFACTORY_H_
#define FRAMEWORK_TASKS_TASKFACTORY_H_
#include <stdlib.h>
#include "FixedTimeslotTaskIF.h"
#include "Typedef.h"
/**
* Singleton Class that produces Tasks.
*/
class TaskFactory {
public:
virtual ~TaskFactory();
/**
* Returns the single instance of TaskFactory.
* The implementation of #instance is found in its subclasses.
* Thus, we choose link-time variability of the instance.
*/
static TaskFactory* instance();
/**
* Creates a new periodic task and returns the interface pointer.
* @param name_ Name of the task
* @param taskPriority_ Priority of the task
* @param stackSize_ Stack Size of the task
* @param period_ Period of the task
* @param deadLineMissedFunction_ Function to be called if a deadline was missed
* @return PeriodicTaskIF* Pointer to the newly created Task
*/
PeriodicTaskIF* createPeriodicTask(TaskName name_,
TaskPriority taskPriority_, TaskStackSize stackSize_,
TaskPeriod periodInSeconds_,
TaskDeadlineMissedFunction deadLineMissedFunction_);
/**
*
* @param name_ Name of the task
* @param taskPriority_ Priority of the task
* @param stackSize_ Stack Size of the task
* @param period_ Period of the task
* @param deadLineMissedFunction_ Function to be called if a deadline was missed
* @return FixedTimeslotTaskIF* Pointer to the newly created Task
*/
FixedTimeslotTaskIF* createFixedTimeslotTask(TaskName name_,
TaskPriority taskPriority_, TaskStackSize stackSize_,
TaskPeriod periodInSeconds_,
TaskDeadlineMissedFunction deadLineMissedFunction_);
/**
* Function to be called to delete a task
* @param task The pointer to the task that shall be deleted, NULL specifies current Task
* @return Success of deletion
*/
static ReturnValue_t deleteTask(PeriodicTaskIF* task = NULL);
/**
* Function to be called to delay current task
* @param delay The delay in milliseconds
* @return Success of deletion
*/
static ReturnValue_t delayTask(uint32_t delayMs);
private:
/**
* External instantiation is not allowed.
*/
TaskFactory();
static TaskFactory* factoryInstance;
};
#endif /* FRAMEWORK_TASKS_TASKFACTORY_H_ */

10
fsfw/tasks/Typedef.h Normal file
View File

@ -0,0 +1,10 @@
#ifndef FRAMEWORK_TASKS_TYPEDEF_H_
#define FRAMEWORK_TASKS_TYPEDEF_H_
typedef const char* TaskName;
typedef uint8_t TaskPriority;
typedef size_t TaskStackSize;
typedef double TaskPeriod;
typedef void (*TaskDeadlineMissedFunction)();
#endif /* FRAMEWORK_TASKS_TYPEDEF_H_ */