Merge remote-tracking branch 'upstream/master' into mueller/SimpleRingBufferUpdate2

This commit is contained in:
Robin Müller 2020-09-16 19:56:13 +02:00
commit 96f2b68a22
75 changed files with 3800 additions and 1077 deletions

View File

@ -72,11 +72,15 @@ public:
return tmp; return tmp;
} }
T operator*() { T& operator*(){
return *value; return *value;
} }
T *operator->() { const T& operator*() const{
return *value;
}
T *operator->(){
return value; return value;
} }

55
container/DynamicFIFO.h Normal file
View File

@ -0,0 +1,55 @@
#ifndef FSFW_CONTAINER_DYNAMICFIFO_H_
#define FSFW_CONTAINER_DYNAMICFIFO_H_
#include "FIFOBase.h"
#include <vector>
/**
* @brief Simple First-In-First-Out data structure. The maximum size
* can be set in the constructor.
* @details
* The maximum capacity can be determined at run-time, so this container
* performs dynamic memory allocation!
* The public interface of FIFOBase exposes the user interface for the FIFO.
* @tparam T Entry Type
* @tparam capacity Maximum capacity
*/
template<typename T>
class DynamicFIFO: public FIFOBase<T> {
public:
DynamicFIFO(size_t maxCapacity): FIFOBase<T>(nullptr, maxCapacity),
fifoVector(maxCapacity) {
// trying to pass the pointer of the uninitialized vector
// to the FIFOBase constructor directly lead to a super evil bug.
// So we do it like this now.
this->setContainer(fifoVector.data());
};
/**
* @brief Custom copy constructor which prevents setting the
* underlying pointer wrong. This function allocates memory!
* @details This is a very heavy operation so try to avoid this!
*
*/
DynamicFIFO(const DynamicFIFO& other): FIFOBase<T>(other),
fifoVector(other.maxCapacity) {
this->fifoVector = other.fifoVector;
this->setContainer(fifoVector.data());
}
/**
* @brief Custom assignment operator
* @details This is a very heavy operation so try to avoid this!
* @param other DyamicFIFO to copy from
*/
DynamicFIFO& operator=(const DynamicFIFO& other){
FIFOBase<T>::operator=(other);
this->fifoVector = other.fifoVector;
this->setContainer(fifoVector.data());
return *this;
}
private:
std::vector<T> fifoVector;
};
#endif /* FSFW_CONTAINER_DYNAMICFIFO_H_ */

View File

@ -1,82 +1,47 @@
#ifndef FIFO_H_ #ifndef FSFW_CONTAINER_FIFO_H_
#define FIFO_H_ #define FSFW_CONTAINER_FIFO_H_
#include "../returnvalues/HasReturnvaluesIF.h" #include "FIFOBase.h"
#include <array>
/** /**
* @brief Simple First-In-First-Out data structure * @brief Simple First-In-First-Out data structure with size fixed at
* compile time
* @details
* Performs no dynamic memory allocation.
* The public interface of FIFOBase exposes the user interface for the FIFO.
* @tparam T Entry Type * @tparam T Entry Type
* @tparam capacity Maximum capacity * @tparam capacity Maximum capacity
*/ */
template<typename T, uint8_t capacity> template<typename T, size_t capacity>
class FIFO { class FIFO: public FIFOBase<T> {
private:
uint8_t readIndex, writeIndex, currentSize;
T data[capacity];
uint8_t next(uint8_t current) {
++current;
if (current == capacity) {
current = 0;
}
return current;
}
public: public:
FIFO() : FIFO(): FIFOBase<T>(nullptr, capacity) {
readIndex(0), writeIndex(0), currentSize(0) { this->setContainer(fifoArray.data());
};
/**
* @brief Custom copy constructor to set pointer correctly.
* @param other
*/
FIFO(const FIFO& other): FIFOBase<T>(other) {
this->fifoArray = other.fifoArray;
this->setContainer(fifoArray.data());
} }
bool empty() { /**
return (currentSize == 0); * @brief Custom assignment operator
* @param other
*/
FIFO& operator=(const FIFO& other){
FIFOBase<T>::operator=(other);
this->fifoArray = other.fifoArray;
this->setContainer(fifoArray.data());
return *this;
} }
bool full() { private:
return (currentSize == capacity); std::array<T, capacity> fifoArray;
}
uint8_t size(){
return currentSize;
}
ReturnValue_t insert(T value) {
if (full()) {
return FULL;
} else {
data[writeIndex] = value;
writeIndex = next(writeIndex);
++currentSize;
return HasReturnvaluesIF::RETURN_OK;
}
}
ReturnValue_t retrieve(T *value) {
if (empty()) {
return EMPTY;
} else {
*value = data[readIndex];
readIndex = next(readIndex);
--currentSize;
return HasReturnvaluesIF::RETURN_OK;
}
}
ReturnValue_t peek(T * value) {
if(empty()) {
return EMPTY;
} else {
*value = data[readIndex];
return HasReturnvaluesIF::RETURN_OK;
}
}
ReturnValue_t pop() {
T value;
return this->retrieve(&value);
}
static const uint8_t INTERFACE_ID = CLASS_ID::FIFO_CLASS;
static const ReturnValue_t FULL = MAKE_RETURN_CODE(1);
static const ReturnValue_t EMPTY = MAKE_RETURN_CODE(2);
}; };
#endif /* FIFO_H_ */ #endif /* FSFW_CONTAINER_FIFO_H_ */

65
container/FIFOBase.h Normal file
View File

@ -0,0 +1,65 @@
#ifndef FSFW_CONTAINER_FIFOBASE_H_
#define FSFW_CONTAINER_FIFOBASE_H_
#include "../returnvalues/HasReturnvaluesIF.h"
#include <cstddef>
#include <cstring>
template <typename T>
class FIFOBase {
public:
static const uint8_t INTERFACE_ID = CLASS_ID::FIFO_CLASS;
static const ReturnValue_t FULL = MAKE_RETURN_CODE(1);
static const ReturnValue_t EMPTY = MAKE_RETURN_CODE(2);
/** Default ctor, takes pointer to first entry of underlying container
* and maximum capacity */
FIFOBase(T* values, const size_t maxCapacity);
/**
* Insert value into FIFO
* @param value
* @return
*/
ReturnValue_t insert(T value);
/**
* Retrieve item from FIFO. This removes the item from the FIFO.
* @param value
* @return
*/
ReturnValue_t retrieve(T *value);
/**
* Retrieve item from FIFO without removing it from FIFO.
* @param value
* @return
*/
ReturnValue_t peek(T * value);
/**
* Remove item from FIFO.
* @return
*/
ReturnValue_t pop();
bool empty();
bool full();
size_t size();
size_t getMaxCapacity() const;
protected:
void setContainer(T* data);
size_t maxCapacity = 0;
T* values;
size_t readIndex = 0;
size_t writeIndex = 0;
size_t currentSize = 0;
size_t next(size_t current);
};
#include "FIFOBase.tpp"
#endif /* FSFW_CONTAINER_FIFOBASE_H_ */

87
container/FIFOBase.tpp Normal file
View File

@ -0,0 +1,87 @@
#ifndef FSFW_CONTAINER_FIFOBASE_TPP_
#define FSFW_CONTAINER_FIFOBASE_TPP_
#ifndef FSFW_CONTAINER_FIFOBASE_H_
#error Include FIFOBase.h before FIFOBase.tpp!
#endif
template<typename T>
inline FIFOBase<T>::FIFOBase(T* values, const size_t maxCapacity):
maxCapacity(maxCapacity), values(values){};
template<typename T>
inline ReturnValue_t FIFOBase<T>::insert(T value) {
if (full()) {
return FULL;
} else {
values[writeIndex] = value;
writeIndex = next(writeIndex);
++currentSize;
return HasReturnvaluesIF::RETURN_OK;
}
};
template<typename T>
inline ReturnValue_t FIFOBase<T>::retrieve(T* value) {
if (empty()) {
return EMPTY;
} else {
*value = values[readIndex];
readIndex = next(readIndex);
--currentSize;
return HasReturnvaluesIF::RETURN_OK;
}
};
template<typename T>
inline ReturnValue_t FIFOBase<T>::peek(T* value) {
if(empty()) {
return EMPTY;
} else {
*value = values[readIndex];
return HasReturnvaluesIF::RETURN_OK;
}
};
template<typename T>
inline ReturnValue_t FIFOBase<T>::pop() {
T value;
return this->retrieve(&value);
};
template<typename T>
inline bool FIFOBase<T>::empty() {
return (currentSize == 0);
};
template<typename T>
inline bool FIFOBase<T>::full() {
return (currentSize == maxCapacity);
}
template<typename T>
inline size_t FIFOBase<T>::size() {
return currentSize;
}
template<typename T>
inline size_t FIFOBase<T>::next(size_t current) {
++current;
if (current == maxCapacity) {
current = 0;
}
return current;
}
template<typename T>
inline size_t FIFOBase<T>::getMaxCapacity() const {
return maxCapacity;
}
template<typename T>
inline void FIFOBase<T>::setContainer(T *data) {
this->values = data;
}
#endif

View File

@ -1,15 +1,20 @@
#ifndef FIXEDMAP_H_ #ifndef FSFW_CONTAINER_FIXEDMAP_H_
#define FIXEDMAP_H_ #define FSFW_CONTAINER_FIXEDMAP_H_
#include "ArrayList.h" #include "ArrayList.h"
#include "../returnvalues/HasReturnvaluesIF.h" #include "../returnvalues/HasReturnvaluesIF.h"
#include <utility> #include <utility>
#include <type_traits>
/** /**
* \ingroup container * @warning Iterators return a non-const key_t in the pair.
* @warning A User is not allowed to change the key, otherwise the map is corrupted.
* @ingroup container
*/ */
template<typename key_t, typename T> template<typename key_t, typename T>
class FixedMap: public SerializeIF { class FixedMap: public SerializeIF {
static_assert (std::is_trivially_copyable<T>::value or std::is_base_of<SerializeIF, T>::value,
"Types used in FixedMap must either be trivial copy-able or a derived Class from SerializeIF to be serialize-able");
public: public:
static const uint8_t INTERFACE_ID = CLASS_ID::FIXED_MAP; static const uint8_t INTERFACE_ID = CLASS_ID::FIXED_MAP;
static const ReturnValue_t KEY_ALREADY_EXISTS = MAKE_RETURN_CODE(0x01); static const ReturnValue_t KEY_ALREADY_EXISTS = MAKE_RETURN_CODE(0x01);
@ -47,15 +52,6 @@ public:
Iterator(std::pair<key_t, T> *pair) : Iterator(std::pair<key_t, T> *pair) :
ArrayList<std::pair<key_t, T>, uint32_t>::Iterator(pair) { ArrayList<std::pair<key_t, T>, uint32_t>::Iterator(pair) {
} }
T operator*() {
return ArrayList<std::pair<key_t, T>, uint32_t>::Iterator::value->second;
}
T *operator->() {
return &ArrayList<std::pair<key_t, T>, uint32_t>::Iterator::value->second;
}
}; };
Iterator begin() const { Iterator begin() const {
@ -70,7 +66,7 @@ public:
return _size; return _size;
} }
ReturnValue_t insert(key_t key, T value, Iterator *storedValue = NULL) { ReturnValue_t insert(key_t key, T value, Iterator *storedValue = nullptr) {
if (exists(key) == HasReturnvaluesIF::RETURN_OK) { if (exists(key) == HasReturnvaluesIF::RETURN_OK) {
return KEY_ALREADY_EXISTS; return KEY_ALREADY_EXISTS;
} }
@ -79,7 +75,7 @@ public:
} }
theMap[_size].first = key; theMap[_size].first = key;
theMap[_size].second = value; theMap[_size].second = value;
if (storedValue != NULL) { if (storedValue != nullptr) {
*storedValue = Iterator(&theMap[_size]); *storedValue = Iterator(&theMap[_size]);
} }
++_size; ++_size;
@ -87,7 +83,7 @@ public:
} }
ReturnValue_t insert(std::pair<key_t, T> pair) { ReturnValue_t insert(std::pair<key_t, T> pair) {
return insert(pair.fist, pair.second); return insert(pair.first, pair.second);
} }
ReturnValue_t exists(key_t key) const { ReturnValue_t exists(key_t key) const {
@ -196,4 +192,4 @@ public:
}; };
#endif /* FIXEDMAP_H_ */ #endif /* FSFW_CONTAINER_FIXEDMAP_H_ */

View File

@ -48,7 +48,7 @@ private:
if (_size <= position) { if (_size <= position) {
return; return;
} }
memmove(&theMap[position], &theMap[position + 1], memmove(static_cast<void*>(&theMap[position]), static_cast<void*>(&theMap[position + 1]),
(_size - position - 1) * sizeof(std::pair<key_t,T>)); (_size - position - 1) * sizeof(std::pair<key_t,T>));
--_size; --_size;
} }
@ -68,15 +68,6 @@ public:
Iterator(std::pair<key_t, T> *pair) : Iterator(std::pair<key_t, T> *pair) :
ArrayList<std::pair<key_t, T>, uint32_t>::Iterator(pair) { ArrayList<std::pair<key_t, T>, uint32_t>::Iterator(pair) {
} }
T operator*() {
return ArrayList<std::pair<key_t, T>, uint32_t>::Iterator::value->second;
}
T *operator->() {
return &ArrayList<std::pair<key_t, T>, uint32_t>::Iterator::value->second;
}
}; };
Iterator begin() const { Iterator begin() const {
@ -91,17 +82,17 @@ public:
return _size; return _size;
} }
ReturnValue_t insert(key_t key, T value, Iterator *storedValue = NULL) { ReturnValue_t insert(key_t key, T value, Iterator *storedValue = nullptr) {
if (_size == theMap.maxSize()) { if (_size == theMap.maxSize()) {
return MAP_FULL; return MAP_FULL;
} }
uint32_t position = findNicePlace(key); uint32_t position = findNicePlace(key);
memmove(&theMap[position + 1], &theMap[position], memmove(static_cast<void*>(&theMap[position + 1]),static_cast<void*>(&theMap[position]),
(_size - position) * sizeof(std::pair<key_t,T>)); (_size - position) * sizeof(std::pair<key_t,T>));
theMap[position].first = key; theMap[position].first = key;
theMap[position].second = value; theMap[position].second = value;
++_size; ++_size;
if (storedValue != NULL) { if (storedValue != nullptr) {
*storedValue = Iterator(&theMap[position]); *storedValue = Iterator(&theMap[position]);
} }
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
@ -145,12 +136,6 @@ public:
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
} }
//This is potentially unsafe
// T *findValue(key_t key) const {
// return &theMap[findFirstIndex(key)].second;
// }
Iterator find(key_t key) const { Iterator find(key_t key) const {
ReturnValue_t result = exists(key); ReturnValue_t result = exists(key);
if (result != HasReturnvaluesIF::RETURN_OK) { if (result != HasReturnvaluesIF::RETURN_OK) {

View File

@ -1,41 +0,0 @@
#ifndef ISDERIVEDFROM_H_
#define ISDERIVEDFROM_H_
template<typename D, typename B>
class IsDerivedFrom {
class No {
};
class Yes {
No no[3];
};
static Yes Test(B*); // declared, but not defined
static No Test(... ); // declared, but not defined
public:
enum {
Is = sizeof(Test(static_cast<D*>(0))) == sizeof(Yes)
};
};
template<typename, typename>
struct is_same {
static bool const value = false;
};
template<typename A>
struct is_same<A, A> {
static bool const value = true;
};
template<bool C, typename T = void>
struct enable_if {
typedef T type;
};
template<typename T>
struct enable_if<false, T> { };
#endif /* ISDERIVEDFROM_H_ */

View File

@ -25,12 +25,10 @@ SimpleRingBuffer::SimpleRingBuffer(uint8_t *buffer, const size_t size,
} }
} }
SimpleRingBuffer::~SimpleRingBuffer() { SimpleRingBuffer::~SimpleRingBuffer() {
delete[] buffer; delete[] buffer;
} }
ReturnValue_t SimpleRingBuffer::getFreeElement(uint8_t **writePointer, ReturnValue_t SimpleRingBuffer::getFreeElement(uint8_t **writePointer,
size_t amount) { size_t amount) {
if (availableWriteSpace() >= amount or overwriteOld) { if (availableWriteSpace() >= amount or overwriteOld) {
@ -131,5 +129,3 @@ ReturnValue_t SimpleRingBuffer::deleteData(size_t amount,
incrementRead(amount, READ_PTR); incrementRead(amount, READ_PTR);
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
} }

View File

@ -117,6 +117,7 @@ public:
*/ */
ReturnValue_t deleteData(size_t amount, bool deleteRemaining = false, ReturnValue_t deleteData(size_t amount, bool deleteRemaining = false,
size_t* trueAmount = nullptr); size_t* trueAmount = nullptr);
private: private:
static const uint8_t READ_PTR = 0; static const uint8_t READ_PTR = 0;
uint8_t* buffer = nullptr; uint8_t* buffer = nullptr;

View File

@ -1,17 +1,19 @@
#include "../subsystem/SubsystemBase.h" #include "../subsystem/SubsystemBase.h"
#include "ChildHandlerBase.h" #include "../devicehandlers/ChildHandlerBase.h"
#include "../subsystem/SubsystemBase.h" #include "../subsystem/SubsystemBase.h"
ChildHandlerBase::ChildHandlerBase(object_id_t setObjectId, ChildHandlerBase::ChildHandlerBase(object_id_t setObjectId,
object_id_t deviceCommunication, CookieIF * comCookie, object_id_t deviceCommunication, CookieIF * cookie,
uint8_t setDeviceSwitch, uint32_t thermalStatePoolId, uint32_t thermalStatePoolId, uint32_t thermalRequestPoolId,
uint32_t thermalRequestPoolId, uint32_t parent, object_id_t parent, FailureIsolationBase* customFdir,
FailureIsolationBase* customFdir, size_t cmdQueueSize) : size_t cmdQueueSize) :
DeviceHandlerBase(setObjectId, deviceCommunication, comCookie, DeviceHandlerBase(setObjectId, deviceCommunication, cookie,
setDeviceSwitch, thermalStatePoolId,thermalRequestPoolId,
(customFdir == nullptr? &childHandlerFdir : customFdir), (customFdir == nullptr? &childHandlerFdir : customFdir),
cmdQueueSize), cmdQueueSize),
parentId(parent), childHandlerFdir(setObjectId) { parentId(parent), childHandlerFdir(setObjectId) {
this->setThermalStateRequestPoolIds(thermalStatePoolId,
thermalRequestPoolId);
} }
ChildHandlerBase::~ChildHandlerBase() { ChildHandlerBase::~ChildHandlerBase() {
@ -25,7 +27,7 @@ ReturnValue_t ChildHandlerBase::initialize() {
MessageQueueId_t parentQueue = 0; MessageQueueId_t parentQueue = 0;
if (parentId != 0) { if (parentId != objects::NO_OBJECT) {
SubsystemBase *parent = objectManager->get<SubsystemBase>(parentId); SubsystemBase *parent = objectManager->get<SubsystemBase>(parentId);
if (parent == NULL) { if (parent == NULL) {
return RETURN_FAILED; return RETURN_FAILED;

View File

@ -1,15 +1,15 @@
#ifndef PAYLOADHANDLERBASE_H_ #ifndef FSFW_DEVICES_CHILDHANDLERBASE_H_
#define PAYLOADHANDLERBASE_H_ #define FSFW_DEVICES_CHILDHANDLERBASE_H_
#include "ChildHandlerFDIR.h" #include "ChildHandlerFDIR.h"
#include "DeviceHandlerBase.h" #include "DeviceHandlerBase.h"
class ChildHandlerBase: public DeviceHandlerBase { class ChildHandlerBase: public DeviceHandlerBase {
public: public:
ChildHandlerBase(object_id_t setObjectId, ChildHandlerBase(object_id_t setObjectId, object_id_t deviceCommunication,
object_id_t deviceCommunication, CookieIF * comCookie, CookieIF * cookie, uint32_t thermalStatePoolId,
uint8_t setDeviceSwitch, uint32_t thermalStatePoolId, uint32_t thermalRequestPoolId,
uint32_t thermalRequestPoolId, uint32_t parent, object_id_t parent = objects::NO_OBJECT,
FailureIsolationBase* customFdir = nullptr, FailureIsolationBase* customFdir = nullptr,
size_t cmdQueueSize = 20); size_t cmdQueueSize = 20);
virtual ~ChildHandlerBase(); virtual ~ChildHandlerBase();
@ -22,4 +22,5 @@ protected:
}; };
#endif /* PAYLOADHANDLERBASE_H_ */ #endif /* FSFW_DEVICES_CHILDHANDLERBASE_H_ */

View File

@ -1,12 +1,12 @@
#include "DeviceHandlerBase.h" #include "DeviceHandlerBase.h"
#include "AcceptsDeviceResponsesIF.h"
#include "DeviceTmReportingWrapper.h"
#include "../objectmanager/ObjectManager.h" #include "../objectmanager/ObjectManager.h"
#include "../storagemanager/StorageManagerIF.h" #include "../storagemanager/StorageManagerIF.h"
#include "../thermal/ThermalComponentIF.h" #include "../thermal/ThermalComponentIF.h"
#include "AcceptsDeviceResponsesIF.h"
#include "../datapool/DataSet.h" #include "../datapool/DataSet.h"
#include "../datapool/PoolVariable.h" #include "../datapool/PoolVariable.h"
#include "DeviceTmReportingWrapper.h"
#include "../globalfunctions/CRC.h" #include "../globalfunctions/CRC.h"
#include "../subsystem/SubsystemBase.h" #include "../subsystem/SubsystemBase.h"
#include "../ipc/QueueFactory.h" #include "../ipc/QueueFactory.h"
@ -14,45 +14,47 @@
#include <iomanip> #include <iomanip>
object_id_t DeviceHandlerBase::powerSwitcherId = 0; object_id_t DeviceHandlerBase::powerSwitcherId = objects::NO_OBJECT;
object_id_t DeviceHandlerBase::rawDataReceiverId = 0; object_id_t DeviceHandlerBase::rawDataReceiverId = objects::NO_OBJECT;
object_id_t DeviceHandlerBase::defaultFDIRParentId = 0; object_id_t DeviceHandlerBase::defaultFdirParentId = objects::NO_OBJECT;
DeviceHandlerBase::DeviceHandlerBase(object_id_t setObjectId, DeviceHandlerBase::DeviceHandlerBase(object_id_t setObjectId,
object_id_t deviceCommunication, CookieIF * comCookie, object_id_t deviceCommunication, CookieIF * comCookie,
uint8_t setDeviceSwitch, uint32_t thermalStatePoolId, FailureIsolationBase* fdirInstance, size_t cmdQueueSize) :
uint32_t thermalRequestPoolId, FailureIsolationBase* fdirInstance,
size_t cmdQueueSize) :
SystemObject(setObjectId), mode(MODE_OFF), submode(SUBMODE_NONE), SystemObject(setObjectId), mode(MODE_OFF), submode(SUBMODE_NONE),
wiretappingMode(OFF), storedRawData(StorageManagerIF::INVALID_ADDRESS), wiretappingMode(OFF), storedRawData(StorageManagerIF::INVALID_ADDRESS),
deviceCommunicationId(deviceCommunication), comCookie(comCookie), deviceCommunicationId(deviceCommunication), comCookie(comCookie),
deviceThermalStatePoolId(thermalStatePoolId),
deviceThermalRequestPoolId(thermalRequestPoolId),
healthHelper(this,setObjectId), modeHelper(this), parameterHelper(this), healthHelper(this,setObjectId), modeHelper(this), parameterHelper(this),
childTransitionFailure(RETURN_OK), fdirInstance(fdirInstance), actionHelper(this, nullptr), childTransitionFailure(RETURN_OK),
hkSwitcher(this), defaultFDIRUsed(fdirInstance == nullptr), fdirInstance(fdirInstance), hkSwitcher(this),
switchOffWasReported(false), actionHelper(this, nullptr), defaultFDIRUsed(fdirInstance == nullptr), switchOffWasReported(false),
childTransitionDelay(5000), childTransitionDelay(5000), transitionSourceMode(_MODE_POWER_DOWN),
transitionSourceMode(_MODE_POWER_DOWN), transitionSourceSubMode( transitionSourceSubMode(SUBMODE_NONE) {
SUBMODE_NONE), deviceSwitch(setDeviceSwitch) {
commandQueue = QueueFactory::instance()->createMessageQueue(cmdQueueSize, commandQueue = QueueFactory::instance()->createMessageQueue(cmdQueueSize,
CommandMessage::MAX_MESSAGE_SIZE); MessageQueueMessage::MAX_MESSAGE_SIZE);
insertInCommandMap(RAW_COMMAND_ID); insertInCommandMap(RAW_COMMAND_ID);
cookieInfo.state = COOKIE_UNUSED; cookieInfo.state = COOKIE_UNUSED;
cookieInfo.pendingCommand = deviceCommandMap.end(); cookieInfo.pendingCommand = deviceCommandMap.end();
if (comCookie == nullptr) { if (comCookie == nullptr) {
sif::error << "DeviceHandlerBase: ObjectID 0x" << std::hex << sif::error << "DeviceHandlerBase: ObjectID 0x" << std::hex
std::setw(8) << std::setfill('0') << this->getObjectId() << << std::setw(8) << std::setfill('0') << this->getObjectId()
std::dec << ": Do not pass nullptr as a cookie, consider " << std::dec << ": Do not pass nullptr as a cookie, consider "
<< std::setfill(' ') << "passing a dummy cookie instead!" << << std::setfill(' ') << "passing a dummy cookie instead!"
std::endl; << std::endl;
} }
if (this->fdirInstance == nullptr) { if (this->fdirInstance == nullptr) {
this->fdirInstance = new DeviceHandlerFailureIsolation(setObjectId, this->fdirInstance = new DeviceHandlerFailureIsolation(setObjectId,
defaultFDIRParentId); defaultFdirParentId);
} }
} }
void DeviceHandlerBase::setThermalStateRequestPoolIds(
uint32_t thermalStatePoolId, uint32_t thermalRequestPoolId) {
this->deviceThermalRequestPoolId = thermalStatePoolId;
this->deviceThermalRequestPoolId = thermalRequestPoolId;
}
DeviceHandlerBase::~DeviceHandlerBase() { DeviceHandlerBase::~DeviceHandlerBase() {
delete comCookie; delete comCookie;
if (defaultFDIRUsed) { if (defaultFDIRUsed) {
@ -108,8 +110,12 @@ ReturnValue_t DeviceHandlerBase::initialize() {
communicationInterface = objectManager->get<DeviceCommunicationIF>( communicationInterface = objectManager->get<DeviceCommunicationIF>(
deviceCommunicationId); deviceCommunicationId);
if (communicationInterface == NULL) { if (communicationInterface == nullptr) {
return RETURN_FAILED; sif::error << "DeviceHandlerBase::initialize: Communication interface "
"invalid." << std::endl;
sif::error << "Make sure it is set up properly and implements"
" DeviceCommunicationIF" << std::endl;
return ObjectManagerIF::CHILD_INIT_FAILED;
} }
result = communicationInterface->initializeInterface(comCookie); result = communicationInterface->initializeInterface(comCookie);
@ -118,22 +124,35 @@ ReturnValue_t DeviceHandlerBase::initialize() {
} }
IPCStore = objectManager->get<StorageManagerIF>(objects::IPC_STORE); IPCStore = objectManager->get<StorageManagerIF>(objects::IPC_STORE);
if (IPCStore == NULL) { if (IPCStore == nullptr) {
return RETURN_FAILED; sif::error << "DeviceHandlerBase::initialize: IPC store not set up in "
"factory." << std::endl;
return ObjectManagerIF::CHILD_INIT_FAILED;
} }
if(rawDataReceiverId != objects::NO_OBJECT) {
AcceptsDeviceResponsesIF *rawReceiver = objectManager->get< AcceptsDeviceResponsesIF *rawReceiver = objectManager->get<
AcceptsDeviceResponsesIF>(rawDataReceiverId); AcceptsDeviceResponsesIF>(rawDataReceiverId);
if (rawReceiver == NULL) { if (rawReceiver == nullptr) {
return RETURN_FAILED; sif::error << "DeviceHandlerBase::initialize: Raw receiver object "
"ID set but no valid object found." << std::endl;
sif::error << "Make sure the raw receiver object is set up properly"
" and implements AcceptsDeviceResponsesIF" << std::endl;
return ObjectManagerIF::CHILD_INIT_FAILED;
}
defaultRawReceiver = rawReceiver->getDeviceQueue();
} }
defaultRawReceiver = rawReceiver->getDeviceQueue(); if(powerSwitcherId != objects::NO_OBJECT) {
powerSwitcher = objectManager->get<PowerSwitchIF>(powerSwitcherId); powerSwitcher = objectManager->get<PowerSwitchIF>(powerSwitcherId);
if (powerSwitcher == NULL) { if (powerSwitcher == nullptr) {
return RETURN_FAILED; sif::error << "DeviceHandlerBase::initialize: Power switcher "
<< "object ID set but no valid object found." << std::endl;
sif::error << "Make sure the raw receiver object is set up properly"
<< " and implements PowerSwitchIF" << std::endl;
return ObjectManagerIF::CHILD_INIT_FAILED;
}
} }
result = healthHelper.initialize(); result = healthHelper.initialize();
@ -168,7 +187,7 @@ ReturnValue_t DeviceHandlerBase::initialize() {
//Set temperature target state to NON_OP. //Set temperature target state to NON_OP.
DataSet mySet; DataSet mySet;
PoolVariable<int8_t> thermalRequest(deviceThermalRequestPoolId, &mySet, db_int8_t thermalRequest(deviceThermalRequestPoolId, &mySet,
PoolVariableIF::VAR_WRITE); PoolVariableIF::VAR_WRITE);
mySet.read(); mySet.read();
thermalRequest = ThermalComponentIF::STATE_REQUEST_NON_OPERATIONAL; thermalRequest = ThermalComponentIF::STATE_REQUEST_NON_OPERATIONAL;
@ -200,38 +219,43 @@ void DeviceHandlerBase::readCommandQueue() {
return; return;
} }
CommandMessage message; CommandMessage command;
ReturnValue_t result = commandQueue->receiveMessage(&message); ReturnValue_t result = commandQueue->receiveMessage(&command);
if (result != RETURN_OK) { if (result != RETURN_OK) {
return; return;
} }
result = healthHelper.handleHealthCommand(&message); result = healthHelper.handleHealthCommand(&command);
if (result == RETURN_OK) { if (result == RETURN_OK) {
return; return;
} }
result = modeHelper.handleModeCommand(&message); result = modeHelper.handleModeCommand(&command);
if (result == RETURN_OK) { if (result == RETURN_OK) {
return; return;
} }
result = actionHelper.handleActionMessage(&message); result = actionHelper.handleActionMessage(&command);
if (result == RETURN_OK) { if (result == RETURN_OK) {
return; return;
} }
result = parameterHelper.handleParameterMessage(&message); result = parameterHelper.handleParameterMessage(&command);
if (result == RETURN_OK) { if (result == RETURN_OK) {
return; return;
} }
result = handleDeviceHandlerMessage(&message); // result = hkManager.handleHousekeepingMessage(&command);
// if (result == RETURN_OK) {
// return;
// }
result = handleDeviceHandlerMessage(&command);
if (result == RETURN_OK) { if (result == RETURN_OK) {
return; return;
} }
result = letChildHandleMessage(&message); result = letChildHandleMessage(&command);
if (result == RETURN_OK) { if (result == RETURN_OK) {
return; return;
} }
@ -273,7 +297,8 @@ void DeviceHandlerBase::doStateMachine() {
case _MODE_WAIT_ON: { case _MODE_WAIT_ON: {
uint32_t currentUptime; uint32_t currentUptime;
Clock::getUptime(&currentUptime); Clock::getUptime(&currentUptime);
if (currentUptime - timeoutStart >= powerSwitcher->getSwitchDelayMs()) { if (powerSwitcher != nullptr and currentUptime - timeoutStart >=
powerSwitcher->getSwitchDelayMs()) {
triggerEvent(MODE_TRANSITION_FAILED, PowerSwitchIF::SWITCH_TIMEOUT, triggerEvent(MODE_TRANSITION_FAILED, PowerSwitchIF::SWITCH_TIMEOUT,
0); 0);
setMode(_MODE_POWER_DOWN); setMode(_MODE_POWER_DOWN);
@ -293,6 +318,12 @@ void DeviceHandlerBase::doStateMachine() {
case _MODE_WAIT_OFF: { case _MODE_WAIT_OFF: {
uint32_t currentUptime; uint32_t currentUptime;
Clock::getUptime(&currentUptime); Clock::getUptime(&currentUptime);
if(powerSwitcher == nullptr) {
setMode(MODE_OFF);
break;
}
if (currentUptime - timeoutStart >= powerSwitcher->getSwitchDelayMs()) { if (currentUptime - timeoutStart >= powerSwitcher->getSwitchDelayMs()) {
triggerEvent(MODE_TRANSITION_FAILED, PowerSwitchIF::SWITCH_TIMEOUT, triggerEvent(MODE_TRANSITION_FAILED, PowerSwitchIF::SWITCH_TIMEOUT,
0); 0);
@ -343,9 +374,10 @@ ReturnValue_t DeviceHandlerBase::isModeCombinationValid(Mode_t mode,
} }
} }
ReturnValue_t DeviceHandlerBase::insertInCommandAndReplyMap(DeviceCommandId_t deviceCommand, ReturnValue_t DeviceHandlerBase::insertInCommandAndReplyMap(
uint16_t maxDelayCycles, size_t replyLen, bool periodic, DeviceCommandId_t deviceCommand, uint16_t maxDelayCycles,
bool hasDifferentReplyId, DeviceCommandId_t replyId) { size_t replyLen, bool periodic, bool hasDifferentReplyId,
DeviceCommandId_t replyId) {
//No need to check, as we may try to insert multiple times. //No need to check, as we may try to insert multiple times.
insertInCommandMap(deviceCommand); insertInCommandMap(deviceCommand);
if (hasDifferentReplyId) { if (hasDifferentReplyId) {
@ -371,7 +403,8 @@ ReturnValue_t DeviceHandlerBase::insertInReplyMap(DeviceCommandId_t replyId,
} }
} }
ReturnValue_t DeviceHandlerBase::insertInCommandMap(DeviceCommandId_t deviceCommand) { ReturnValue_t DeviceHandlerBase::insertInCommandMap(
DeviceCommandId_t deviceCommand) {
DeviceCommandInfo info; DeviceCommandInfo info;
info.expectedReplies = 0; info.expectedReplies = 0;
info.isExecuting = false; info.isExecuting = false;
@ -419,7 +452,7 @@ void DeviceHandlerBase::setTransition(Mode_t modeTo, Submode_t submodeTo) {
transitionSourceSubMode = submode; transitionSourceSubMode = submode;
childTransitionFailure = CHILD_TIMEOUT; childTransitionFailure = CHILD_TIMEOUT;
//transitionTargetMode is set by setMode // transitionTargetMode is set by setMode
setMode((modeTo | TRANSITION_MODE_CHILD_ACTION_MASK), submodeTo); setMode((modeTo | TRANSITION_MODE_CHILD_ACTION_MASK), submodeTo);
} }
@ -437,7 +470,7 @@ void DeviceHandlerBase::setMode(Mode_t newMode, uint8_t newSubmode) {
if (mode == MODE_OFF) { if (mode == MODE_OFF) {
DataSet mySet; DataSet mySet;
PoolVariable<int8_t> thermalRequest(deviceThermalRequestPoolId, &mySet, db_int8_t thermalRequest(deviceThermalRequestPoolId, &mySet,
PoolVariableIF::VAR_READ_WRITE); PoolVariableIF::VAR_READ_WRITE);
mySet.read(); mySet.read();
if (thermalRequest != ThermalComponentIF::STATE_REQUEST_IGNORE) { if (thermalRequest != ThermalComponentIF::STATE_REQUEST_IGNORE) {
@ -578,11 +611,8 @@ void DeviceHandlerBase::doSendRead() {
} }
void DeviceHandlerBase::doGetRead() { void DeviceHandlerBase::doGetRead() {
size_t receivedDataLen; size_t receivedDataLen = 0;
uint8_t *receivedData; uint8_t *receivedData = nullptr;
DeviceCommandId_t foundId = 0xFFFFFFFF;
size_t foundLen = 0;
ReturnValue_t result;
if (cookieInfo.state != COOKIE_READ_SENT) { if (cookieInfo.state != COOKIE_READ_SENT) {
cookieInfo.state = COOKIE_UNUSED; cookieInfo.state = COOKIE_UNUSED;
@ -591,8 +621,8 @@ void DeviceHandlerBase::doGetRead() {
cookieInfo.state = COOKIE_UNUSED; cookieInfo.state = COOKIE_UNUSED;
result = communicationInterface->readReceivedMessage(comCookie, ReturnValue_t result = communicationInterface->readReceivedMessage(
&receivedData, &receivedDataLen); comCookie, &receivedData, &receivedDataLen);
if (result != RETURN_OK) { if (result != RETURN_OK) {
triggerEvent(DEVICE_REQUESTING_REPLY_FAILED, result); triggerEvent(DEVICE_REQUESTING_REPLY_FAILED, result);
@ -608,11 +638,22 @@ void DeviceHandlerBase::doGetRead() {
replyRawData(receivedData, receivedDataLen, requestedRawTraffic); replyRawData(receivedData, receivedDataLen, requestedRawTraffic);
} }
if (mode == MODE_RAW) { if (mode == MODE_RAW and defaultRawReceiver != MessageQueueIF::NO_QUEUE) {
replyRawReplyIfnotWiretapped(receivedData, receivedDataLen); replyRawReplyIfnotWiretapped(receivedData, receivedDataLen);
} else { }
//The loop may not execute more often than the number of received bytes (worst case). else {
//This approach avoids infinite loops due to buggy scanForReply routines (seen in bug 1077). parseReply(receivedData, receivedDataLen);
}
}
void DeviceHandlerBase::parseReply(const uint8_t* receivedData,
size_t receivedDataLen) {
ReturnValue_t result = HasReturnvaluesIF::RETURN_FAILED;
DeviceCommandId_t foundId = 0xFFFFFFFF;
size_t foundLen = 0;
// The loop may not execute more often than the number of received bytes
// (worst case). This approach avoids infinite loops due to buggy
// scanForReply routines.
uint32_t remainingLength = receivedDataLen; uint32_t remainingLength = receivedDataLen;
for (uint32_t count = 0; count < receivedDataLen; count++) { for (uint32_t count = 0; count < receivedDataLen; count++) {
result = scanForReply(receivedData, remainingLength, &foundId, result = scanForReply(receivedData, remainingLength, &foundId,
@ -647,12 +688,51 @@ void DeviceHandlerBase::doGetRead() {
return; return;
} }
} }
}
void DeviceHandlerBase::handleReply(const uint8_t* receivedData,
DeviceCommandId_t foundId, uint32_t foundLen) {
ReturnValue_t result;
DeviceReplyMap::iterator iter = deviceReplyMap.find(foundId);
if (iter == deviceReplyMap.end()) {
replyRawReplyIfnotWiretapped(receivedData, foundLen);
triggerEvent(DEVICE_UNKNOWN_REPLY, foundId);
return;
}
DeviceReplyInfo *info = &(iter->second);
if (info->delayCycles != 0) {
if (info->periodic != false) {
info->delayCycles = info->maxDelayCycles;
}
else {
info->delayCycles = 0;
}
result = interpretDeviceReply(foundId, receivedData);
if (result != RETURN_OK) {
// Report failed interpretation to FDIR.
replyRawReplyIfnotWiretapped(receivedData, foundLen);
triggerEvent(DEVICE_INTERPRETING_REPLY_FAILED, result, foundId);
}
replyToReply(iter, result);
}
else {
// Other completion failure messages are created by timeout.
// Powering down the device might take some time during which periodic
// replies may still come in.
if (mode != _MODE_WAIT_OFF) {
triggerEvent(DEVICE_UNREQUESTED_REPLY, foundId);
}
} }
} }
ReturnValue_t DeviceHandlerBase::getStorageData(store_address_t storageAddress, ReturnValue_t DeviceHandlerBase::getStorageData(store_address_t storageAddress,
uint8_t * *data, uint32_t * len) { uint8_t** data, uint32_t * len) {
size_t lenTmp; size_t lenTmp;
if (IPCStore == nullptr) { if (IPCStore == nullptr) {
@ -675,7 +755,7 @@ ReturnValue_t DeviceHandlerBase::getStorageData(store_address_t storageAddress,
void DeviceHandlerBase::replyRawData(const uint8_t *data, size_t len, void DeviceHandlerBase::replyRawData(const uint8_t *data, size_t len,
MessageQueueId_t sendTo, bool isCommand) { MessageQueueId_t sendTo, bool isCommand) {
if (IPCStore == NULL || len == 0) { if (IPCStore == nullptr or len == 0 or sendTo == MessageQueueIF::NO_QUEUE) {
return; return;
} }
store_address_t address; store_address_t address;
@ -686,18 +766,17 @@ void DeviceHandlerBase::replyRawData(const uint8_t *data, size_t len,
return; return;
} }
CommandMessage message; CommandMessage command;
DeviceHandlerMessage::setDeviceHandlerRawReplyMessage(&message, DeviceHandlerMessage::setDeviceHandlerRawReplyMessage(&command,
getObjectId(), address, isCommand); getObjectId(), address, isCommand);
// this->DeviceHandlerCommand = CommandMessage::CMD_NONE; result = commandQueue->sendMessage(sendTo, &command);
result = commandQueue->sendMessage(sendTo, &message);
if (result != RETURN_OK) { if (result != RETURN_OK) {
IPCStore->deleteData(address); IPCStore->deleteData(address);
//Silently discard data, this indicates heavy TM traffic which should not be increased by additional events. // Silently discard data, this indicates heavy TM traffic which
// should not be increased by additional events.
} }
} }
@ -726,57 +805,6 @@ MessageQueueId_t DeviceHandlerBase::getCommandQueue() const {
return commandQueue->getId(); return commandQueue->getId();
} }
void DeviceHandlerBase::handleReply(const uint8_t* receivedData,
DeviceCommandId_t foundId, uint32_t foundLen) {
ReturnValue_t result;
DeviceReplyMap::iterator iter = deviceReplyMap.find(foundId);
if (iter == deviceReplyMap.end()) {
replyRawReplyIfnotWiretapped(receivedData, foundLen);
triggerEvent(DEVICE_UNKNOWN_REPLY, foundId);
return;
}
DeviceReplyInfo *info = &(iter->second);
if (info->delayCycles != 0) {
if (info->periodic) {
info->delayCycles = info->maxDelayCycles;
} else {
info->delayCycles = 0;
}
result = interpretDeviceReply(foundId, receivedData);
if (result != RETURN_OK) {
//Report failed interpretation to FDIR.
replyRawReplyIfnotWiretapped(receivedData, foundLen);
triggerEvent(DEVICE_INTERPRETING_REPLY_FAILED, result, foundId);
}
replyToReply(iter, result);
} else {
//Other completion failure messages are created by timeout.
//Powering down the device might take some time during which periodic replies may still come in.
if (mode != _MODE_WAIT_OFF) {
triggerEvent(DEVICE_UNREQUESTED_REPLY, foundId);
}
}
}
//ReturnValue_t DeviceHandlerBase::switchCookieChannel(object_id_t newChannelId) {
// DeviceCommunicationIF *newCommunication = objectManager->get<
// DeviceCommunicationIF>(newChannelId);
//
// if (newCommunication != NULL) {
// ReturnValue_t result = newCommunication->reOpen(cookie, ioBoardAddress,
// maxDeviceReplyLen);
// if (result != RETURN_OK) {
// return result;
// }
// return RETURN_OK;
// }
// return RETURN_FAILED;
//}
void DeviceHandlerBase::buildRawDeviceCommand(CommandMessage* commandMessage) { void DeviceHandlerBase::buildRawDeviceCommand(CommandMessage* commandMessage) {
storedRawData = DeviceHandlerMessage::getStoreAddress(commandMessage); storedRawData = DeviceHandlerMessage::getStoreAddress(commandMessage);
ReturnValue_t result = getStorageData(storedRawData, &rawPacket, ReturnValue_t result = getStorageData(storedRawData, &rawPacket,
@ -793,6 +821,9 @@ void DeviceHandlerBase::buildRawDeviceCommand(CommandMessage* commandMessage) {
} }
void DeviceHandlerBase::commandSwitch(ReturnValue_t onOff) { void DeviceHandlerBase::commandSwitch(ReturnValue_t onOff) {
if(powerSwitcher == nullptr) {
return;
}
const uint8_t *switches; const uint8_t *switches;
uint8_t numberOfSwitches = 0; uint8_t numberOfSwitches = 0;
ReturnValue_t result = getSwitches(&switches, &numberOfSwitches); ReturnValue_t result = getSwitches(&switches, &numberOfSwitches);
@ -807,9 +838,7 @@ void DeviceHandlerBase::commandSwitch(ReturnValue_t onOff) {
ReturnValue_t DeviceHandlerBase::getSwitches(const uint8_t **switches, ReturnValue_t DeviceHandlerBase::getSwitches(const uint8_t **switches,
uint8_t *numberOfSwitches) { uint8_t *numberOfSwitches) {
*switches = &deviceSwitch; return DeviceHandlerBase::NO_SWITCH;
*numberOfSwitches = 1;
return RETURN_OK;
} }
void DeviceHandlerBase::modeChanged(void) { void DeviceHandlerBase::modeChanged(void) {
@ -845,6 +874,9 @@ uint32_t DeviceHandlerBase::getTransitionDelayMs(Mode_t modeFrom,
} }
ReturnValue_t DeviceHandlerBase::getStateOfSwitches(void) { ReturnValue_t DeviceHandlerBase::getStateOfSwitches(void) {
if(powerSwitcher == nullptr) {
return NO_SWITCH;
}
uint8_t numberOfSwitches = 0; uint8_t numberOfSwitches = 0;
const uint8_t *switches; const uint8_t *switches;
@ -895,9 +927,9 @@ ReturnValue_t DeviceHandlerBase::checkModeCommand(Mode_t commandedMode,
if ((commandedMode == MODE_ON) && (mode == MODE_OFF) if ((commandedMode == MODE_ON) && (mode == MODE_OFF)
&& (deviceThermalStatePoolId != PoolVariableIF::NO_PARAMETER)) { && (deviceThermalStatePoolId != PoolVariableIF::NO_PARAMETER)) {
DataSet mySet; DataSet mySet;
PoolVariable<int8_t> thermalState(deviceThermalStatePoolId, &mySet, db_int8_t thermalState(deviceThermalStatePoolId, &mySet,
PoolVariableIF::VAR_READ); PoolVariableIF::VAR_READ);
PoolVariable<int8_t> thermalRequest(deviceThermalRequestPoolId, &mySet, db_int8_t thermalRequest(deviceThermalRequestPoolId, &mySet,
PoolVariableIF::VAR_READ); PoolVariableIF::VAR_READ);
mySet.read(); mySet.read();
if (thermalRequest != ThermalComponentIF::STATE_REQUEST_IGNORE) { if (thermalRequest != ThermalComponentIF::STATE_REQUEST_IGNORE) {
@ -925,7 +957,7 @@ void DeviceHandlerBase::startTransition(Mode_t commandedMode,
MODE_ON); MODE_ON);
triggerEvent(CHANGING_MODE, commandedMode, commandedSubmode); triggerEvent(CHANGING_MODE, commandedMode, commandedSubmode);
DataSet mySet; DataSet mySet;
PoolVariable<int8_t> thermalRequest(deviceThermalRequestPoolId, db_int8_t thermalRequest(deviceThermalRequestPoolId,
&mySet, PoolVariableIF::VAR_READ_WRITE); &mySet, PoolVariableIF::VAR_READ_WRITE);
mySet.read(); mySet.read();
if (thermalRequest != ThermalComponentIF::STATE_REQUEST_IGNORE) { if (thermalRequest != ThermalComponentIF::STATE_REQUEST_IGNORE) {
@ -1111,35 +1143,47 @@ void DeviceHandlerBase::handleDeviceTM(SerializeIF* data,
return; return;
} }
DeviceTmReportingWrapper wrapper(getObjectId(), replyId, data); DeviceTmReportingWrapper wrapper(getObjectId(), replyId, data);
if (iter->second.command != deviceCommandMap.end()) {//replies to a command //replies to a command
if (iter->second.command != deviceCommandMap.end())
{
MessageQueueId_t queueId = iter->second.command->second.sendReplyTo; MessageQueueId_t queueId = iter->second.command->second.sendReplyTo;
if (queueId != NO_COMMANDER) { if (queueId != NO_COMMANDER) {
//This may fail, but we'll ignore the fault. //This may fail, but we'll ignore the fault.
actionHelper.reportData(queueId, replyId, data); actionHelper.reportData(queueId, replyId, data);
} }
//This check should make sure we get any TM but don't get anything doubled. //This check should make sure we get any TM but don't get anything doubled.
if (wiretappingMode == TM && (requestedRawTraffic != queueId)) { if (wiretappingMode == TM && (requestedRawTraffic != queueId)) {
actionHelper.reportData(requestedRawTraffic, replyId, &wrapper); actionHelper.reportData(requestedRawTraffic, replyId, &wrapper);
} else if (forceDirectTm && (defaultRawReceiver != queueId)) { }
else if (forceDirectTm and (defaultRawReceiver != queueId) and
// hiding of sender needed so the service will handle it as unexpected Data, no matter what state (defaultRawReceiver != MessageQueueIF::NO_QUEUE))
//(progress or completed) it is in {
// hiding of sender needed so the service will handle it as
// unexpected Data, no matter what state (progress or completed)
// it is in
actionHelper.reportData(defaultRawReceiver, replyId, &wrapper, actionHelper.reportData(defaultRawReceiver, replyId, &wrapper,
true); true);
} }
} else { //unrequested/aperiodic replies }
//unrequested/aperiodic replies
else
{
if (wiretappingMode == TM) { if (wiretappingMode == TM) {
actionHelper.reportData(requestedRawTraffic, replyId, &wrapper); actionHelper.reportData(requestedRawTraffic, replyId, &wrapper);
} else if (forceDirectTm) { }
// hiding of sender needed so the service will handle it as unexpected Data, no matter what state else if (forceDirectTm and defaultRawReceiver !=
//(progress or completed) it is in MessageQueueIF::NO_QUEUE)
{
// hiding of sender needed so the service will handle it as
// unexpected Data, no matter what state (progress or completed)
// it is in
actionHelper.reportData(defaultRawReceiver, replyId, &wrapper, actionHelper.reportData(defaultRawReceiver, replyId, &wrapper,
true); true);
} }
} }
//Try to cast to DataSet and commit data. //Try to cast to GlobDataSet and commit data.
if (!neverInDataPool) { if (!neverInDataPool) {
DataSet* dataSet = dynamic_cast<DataSet*>(data); DataSet* dataSet = dynamic_cast<DataSet*>(data);
if (dataSet != NULL) { if (dataSet != NULL) {
@ -1178,18 +1222,23 @@ void DeviceHandlerBase::buildInternalCommand(void) {
if (mode == MODE_NORMAL) { if (mode == MODE_NORMAL) {
result = buildNormalDeviceCommand(&deviceCommandId); result = buildNormalDeviceCommand(&deviceCommandId);
if (result == BUSY) { if (result == BUSY) {
//so we can track misconfigurations
sif::debug << std::hex << getObjectId() sif::debug << std::hex << getObjectId()
<< ": DHB::buildInternalCommand busy" << std::endl; //so we can track misconfigurations << ": DHB::buildInternalCommand: Busy" << std::endl;
result = NOTHING_TO_SEND; //no need to report this result = NOTHING_TO_SEND; //no need to report this
} }
} else if (mode == MODE_RAW) { }
else if (mode == MODE_RAW) {
result = buildChildRawCommand(); result = buildChildRawCommand();
deviceCommandId = RAW_COMMAND_ID; deviceCommandId = RAW_COMMAND_ID;
} else if (mode & TRANSITION_MODE_CHILD_ACTION_MASK) { }
else if (mode & TRANSITION_MODE_CHILD_ACTION_MASK) {
result = buildTransitionDeviceCommand(&deviceCommandId); result = buildTransitionDeviceCommand(&deviceCommandId);
} else { }
else {
return; return;
} }
if (result == NOTHING_TO_SEND) { if (result == NOTHING_TO_SEND) {
return; return;
} }
@ -1288,4 +1337,15 @@ void DeviceHandlerBase::setTaskIF(PeriodicTaskIF* task_){
void DeviceHandlerBase::debugInterface(uint8_t positionTracker, void DeviceHandlerBase::debugInterface(uint8_t positionTracker,
object_id_t objectId, uint32_t parameter) {} object_id_t objectId, uint32_t parameter) {}
void DeviceHandlerBase::performOperationHook() {} void DeviceHandlerBase::performOperationHook() {
}
ReturnValue_t DeviceHandlerBase::initializeAfterTaskCreation() {
// In this function, the task handle should be valid if the task
// was implemented correctly. We still check to be 1000 % sure :-)
if(executingTask != nullptr) {
pstIntervalMs = executingTask->getPeriodMs();
}
return HasReturnvaluesIF::RETURN_OK;
}

View File

@ -1,22 +1,23 @@
#ifndef DEVICEHANDLERBASE_H_ #ifndef FRAMEWORK_DEVICEHANDLERS_DEVICEHANDLERBASE_H_
#define DEVICEHANDLERBASE_H_ #define FRAMEWORK_DEVICEHANDLERS_DEVICEHANDLERBASE_H_
#include "DeviceHandlerIF.h"
#include "DeviceCommunicationIF.h"
#include "DeviceHandlerFailureIsolation.h"
#include "../objectmanager/SystemObject.h" #include "../objectmanager/SystemObject.h"
#include "../tasks/PeriodicTaskIF.h"
#include "../tasks/ExecutableObjectIF.h" #include "../tasks/ExecutableObjectIF.h"
#include "DeviceHandlerIF.h"
#include "../returnvalues/HasReturnvaluesIF.h" #include "../returnvalues/HasReturnvaluesIF.h"
#include "../action/HasActionsIF.h" #include "../action/HasActionsIF.h"
#include "../datapool/PoolVariableIF.h" #include "../datapool/PoolVariableIF.h"
#include "DeviceCommunicationIF.h"
#include "../modes/HasModesIF.h" #include "../modes/HasModesIF.h"
#include "../power/PowerSwitchIF.h" #include "../power/PowerSwitchIF.h"
#include "../ipc/MessageQueueIF.h" #include "../ipc/MessageQueueIF.h"
#include "../action/ActionHelper.h" #include "../action/ActionHelper.h"
#include "../health/HealthHelper.h" #include "../health/HealthHelper.h"
#include "../parameters/ParameterHelper.h" #include "../parameters/ParameterHelper.h"
#include "../datapool/HkSwitchHelper.h" #include "../datapool/HkSwitchHelper.h"
#include "DeviceHandlerFailureIsolation.h"
#include <map> #include <map>
@ -46,14 +47,16 @@ class StorageManagerIF;
* If data has been received (GET_READ), the data will be interpreted. * If data has been received (GET_READ), the data will be interpreted.
* The action for each step can be defined by the child class but as most * The action for each step can be defined by the child class but as most
* device handlers share a 4-call (sendRead-getRead-sendWrite-getWrite) structure, * device handlers share a 4-call (sendRead-getRead-sendWrite-getWrite) structure,
* a default implementation is provided. NOTE: RMAP is a standard which is used for FLP. * a default implementation is provided.
* NOTE: RMAP is a standard which is used for FLP.
* RMAP communication is not mandatory for projects implementing the FSFW. * RMAP communication is not mandatory for projects implementing the FSFW.
* However, the communication principles are similar to RMAP as there are * However, the communication principles are similar to RMAP as there are
* two write and two send calls involved. * two write and two send calls involved.
* *
* Device handler instances should extend this class and implement the abstract functions. * Device handler instances should extend this class and implement the abstract
* Components and drivers can send so called cookies which are used for communication * functions. Components and drivers can send so called cookies which are used
* and contain information about the communcation (e.g. slave address for I2C or RMAP structs). * for communication and contain information about the communcation (e.g. slave
* address for I2C or RMAP structs).
* The following abstract methods must be implemented by a device handler: * The following abstract methods must be implemented by a device handler:
* 1. doStartUp() * 1. doStartUp()
* 2. doShutDown() * 2. doShutDown()
@ -100,12 +103,12 @@ public:
* @param cmdQueueSize * @param cmdQueueSize
*/ */
DeviceHandlerBase(object_id_t setObjectId, object_id_t deviceCommunication, DeviceHandlerBase(object_id_t setObjectId, object_id_t deviceCommunication,
CookieIF * comCookie, uint8_t setDeviceSwitch, CookieIF * comCookie, FailureIsolationBase* fdirInstance = nullptr,
uint32_t thermalStatePoolId = PoolVariableIF::NO_PARAMETER,
uint32_t thermalRequestPoolId = PoolVariableIF::NO_PARAMETER,
FailureIsolationBase* fdirInstance = nullptr,
size_t cmdQueueSize = 20); size_t cmdQueueSize = 20);
void setThermalStateRequestPoolIds(uint32_t thermalStatePoolId,
uint32_t thermalRequestPoolId);
/** /**
* @brief This function is the device handler base core component and is * @brief This function is the device handler base core component and is
* called periodically. * called periodically.
@ -150,11 +153,9 @@ public:
* @return * @return
*/ */
virtual ReturnValue_t initialize(); virtual ReturnValue_t initialize();
/** Destructor. */
/**
* Destructor.
*/
virtual ~DeviceHandlerBase(); virtual ~DeviceHandlerBase();
protected: protected:
/** /**
* @brief This is used to let the child class handle the transition from * @brief This is used to let the child class handle the transition from
@ -232,8 +233,9 @@ protected:
* Build the device command to send for a transitional mode. * Build the device command to send for a transitional mode.
* *
* This is only called in @c _MODE_TO_NORMAL, @c _MODE_TO_ON, @c _MODE_TO_RAW, * This is only called in @c _MODE_TO_NORMAL, @c _MODE_TO_ON, @c _MODE_TO_RAW,
* @c _MODE_START_UP and @c _MODE_TO_POWER_DOWN. So it is used by doStartUp() * @c _MODE_START_UP and @c _MODE_SHUT_DOWN. So it is used by doStartUp()
* and doShutDown() as well as doTransition() * and doShutDown() as well as doTransition(), by setting those
* modes in the respective functions.
* *
* A good idea is to implement a flag indicating a command has to be built * A good idea is to implement a flag indicating a command has to be built
* and a variable containing the command number to be built * and a variable containing the command number to be built
@ -321,12 +323,11 @@ protected:
* - @c RETURN_FAILED when the reply could not be interpreted, * - @c RETURN_FAILED when the reply could not be interpreted,
* e.g. logical errors or range violations occurred * e.g. logical errors or range violations occurred
*/ */
virtual ReturnValue_t interpretDeviceReply(DeviceCommandId_t id, virtual ReturnValue_t interpretDeviceReply(DeviceCommandId_t id,
const uint8_t *packet) = 0; const uint8_t *packet) = 0;
/** /**
* @brief fill the #deviceCommandMap * @brief fill the #DeviceCommandMap and #DeviceReplyMap
* called by the initialize() of the base class * called by the initialize() of the base class
* @details * @details
* This is used to let the base class know which replies are expected. * This is used to let the base class know which replies are expected.
@ -470,6 +471,18 @@ protected:
virtual ReturnValue_t getSwitches(const uint8_t **switches, virtual ReturnValue_t getSwitches(const uint8_t **switches,
uint8_t *numberOfSwitches); uint8_t *numberOfSwitches);
/**
* This function is used to initialize the local housekeeping pool
* entries. The default implementation leaves the pool empty.
* @param localDataPoolMap
* @return
*/
//virtual ReturnValue_t initializePoolEntries(
// LocalDataPool& localDataPoolMap) override;
/** Get the HK manager object handle */
//virtual LocalDataPoolManager* getHkManagerHandle() override;
/** /**
* @brief Hook function for child handlers which is called once per * @brief Hook function for child handlers which is called once per
* performOperation(). Default implementation is empty. * performOperation(). Default implementation is empty.
@ -493,7 +506,7 @@ public:
ReturnValue_t setHealth(HealthState health); ReturnValue_t setHealth(HealthState health);
virtual ReturnValue_t getParameter(uint8_t domainId, uint16_t parameterId, virtual ReturnValue_t getParameter(uint8_t domainId, uint16_t parameterId,
ParameterWrapper *parameterWrapper, ParameterWrapper *parameterWrapper,
const ParameterWrapper *newValues, uint16_t startAtIndex); const ParameterWrapper *newValues, uint16_t startAtIndex) override;
/** /**
* Implementation of ExecutableObjectIF function * Implementation of ExecutableObjectIF function
* *
@ -505,7 +518,7 @@ public:
protected: protected:
/** /**
* The Returnvalues ID of this class, required by HasReturnvaluesIF * The Returnvalues id of this class, required by HasReturnvaluesIF
*/ */
static const uint8_t INTERFACE_ID = CLASS_ID::DEVICE_HANDLER_BASE; static const uint8_t INTERFACE_ID = CLASS_ID::DEVICE_HANDLER_BASE;
@ -527,114 +540,138 @@ protected:
static const DeviceCommandId_t NO_COMMAND_ID = -2; static const DeviceCommandId_t NO_COMMAND_ID = -2;
static const MessageQueueId_t NO_COMMANDER = 0; static const MessageQueueId_t NO_COMMANDER = 0;
/** /** Pointer to the raw packet that will be sent.*/
* Pointer to the raw packet that will be sent.
*/
uint8_t *rawPacket = nullptr; uint8_t *rawPacket = nullptr;
/** /** Size of the #rawPacket. */
* Size of the #rawPacket.
*/
uint32_t rawPacketLen = 0; uint32_t rawPacketLen = 0;
/** /**
* The mode the device handler is currently in. * The mode the device handler is currently in.
*
* This should never be changed directly but only with setMode() * This should never be changed directly but only with setMode()
*/ */
Mode_t mode; Mode_t mode;
/** /**
* The submode the device handler is currently in. * The submode the device handler is currently in.
*
* This should never be changed directly but only with setMode() * This should never be changed directly but only with setMode()
*/ */
Submode_t submode; Submode_t submode;
/** /** This is the counter value from performOperation(). */
* This is the counter value from performOperation().
*/
uint8_t pstStep = 0; uint8_t pstStep = 0;
uint32_t pstIntervalMs = 0;
/** /**
* wiretapping flag: * Wiretapping flag:
* *
* indicates either that all raw messages to and from the device should be sent to #theOneWhoWantsToReadRawTraffic * indicates either that all raw messages to and from the device should be
* or that all device TM should be downlinked to #theOneWhoWantsToReadRawTraffic * sent to #defaultRawReceiver
* or that all device TM should be downlinked to #defaultRawReceiver.
*/ */
enum WiretappingMode { enum WiretappingMode {
OFF = 0, RAW = 1, TM = 2 OFF = 0, RAW = 1, TM = 2
} wiretappingMode; } wiretappingMode;
/** /**
* A message queue that accepts raw replies * @brief A message queue that accepts raw replies
* *
* Statically initialized in initialize() to a configurable object. Used when there is no method * Statically initialized in initialize() to a configurable object.
* of finding a recipient, ie raw mode and reporting erreonous replies * Used when there is no method of finding a recipient, ie raw mode and
* reporting erroneous replies
*/ */
MessageQueueId_t defaultRawReceiver = 0; MessageQueueId_t defaultRawReceiver = MessageQueueIF::NO_QUEUE;
store_address_t storedRawData; store_address_t storedRawData;
/** /**
* the message queue which wants to read all raw traffic * @brief The message queue which wants to read all raw traffic
* * If #isWiretappingActive all raw communication from and to the device
* if #isWiretappingActive all raw communication from and to the device will be sent to this queue * will be sent to this queue
*/ */
MessageQueueId_t requestedRawTraffic = 0; MessageQueueId_t requestedRawTraffic = 0;
/**
* the object used to set power switches
*/
PowerSwitchIF *powerSwitcher = nullptr;
/** /**
* Pointer to the IPCStore. * Pointer to the IPCStore.
*
* This caches the pointer received from the objectManager in the constructor. * This caches the pointer received from the objectManager in the constructor.
*/ */
StorageManagerIF *IPCStore = nullptr; StorageManagerIF *IPCStore = nullptr;
/** The comIF object ID is cached for the intialize() function */
/**
* cached for init
*/
object_id_t deviceCommunicationId; object_id_t deviceCommunicationId;
/** Communication object used for device communication */
/**
* Communication object used for device communication
*/
DeviceCommunicationIF * communicationInterface = nullptr; DeviceCommunicationIF * communicationInterface = nullptr;
/** Cookie used for communication */
/**
* Cookie used for communication
*/
CookieIF * comCookie; CookieIF * comCookie;
/** Health helper for HasHealthIF */
HealthHelper healthHelper;
/** Mode helper for HasModesIF */
ModeHelper modeHelper;
/** Parameter helper for ReceivesParameterMessagesIF */
ParameterHelper parameterHelper;
/** Action helper for HasActionsIF */
ActionHelper actionHelper;
/** Housekeeping Manager */
//LocalDataPoolManager hkManager;
/**
* @brief Information about commands
*/
struct DeviceCommandInfo { struct DeviceCommandInfo {
bool isExecuting; //!< Indicates if the command is already executing. //! Indicates if the command is already executing.
uint8_t expectedReplies; //!< Dynamic value to indicate how many replies are expected. Inititated with 0. bool isExecuting;
MessageQueueId_t sendReplyTo; //!< if this is != NO_COMMANDER, DHB was commanded externally and shall report everything to commander. //! Dynamic value to indicate how many replies are expected.
//! Inititated with 0.
uint8_t expectedReplies;
//! if this is != NO_COMMANDER, DHB was commanded externally and shall
//! report everything to commander.
MessageQueueId_t sendReplyTo;
}; };
using DeviceCommandMap = std::map<DeviceCommandId_t, DeviceCommandInfo> ; using DeviceCommandMap = std::map<DeviceCommandId_t, DeviceCommandInfo> ;
/**
* Information about commands
*/
DeviceCommandMap deviceCommandMap;
/** /**
* @brief Information about expected replies * @brief Information about expected replies
* * This is used to keep track of pending replies.
* This is used to keep track of pending replies
*/ */
struct DeviceReplyInfo { struct DeviceReplyInfo {
uint16_t maxDelayCycles; //!< The maximum number of cycles the handler should wait for a reply to this command. //! The maximum number of cycles the handler should wait for a reply
uint16_t delayCycles; //!< The currently remaining cycles the handler should wait for a reply, 0 means there is no reply expected //! to this command.
uint16_t maxDelayCycles;
//! The currently remaining cycles the handler should wait for a reply,
//! 0 means there is no reply expected
uint16_t delayCycles;
size_t replyLen = 0; //!< Expected size of the reply. size_t replyLen = 0; //!< Expected size of the reply.
bool periodic; //!< if this is !=0, the delayCycles will not be reset to 0 but to maxDelayCycles //! if this is !=0, the delayCycles will not be reset to 0 but to
DeviceCommandMap::iterator command; //!< The command that expects this reply. //! maxDelayCycles
bool periodic = false;
//! The dataset used to access housekeeping data related to the
//! respective device reply. Will point to a dataset held by
//! the child handler (if one is specified)
// DataSetIF* dataSet = nullptr;
//! The command that expects this reply.
DeviceCommandMap::iterator command;
}; };
using DeviceReplyMap = std::map<DeviceCommandId_t, DeviceReplyInfo> ; using DeviceReplyMap = std::map<DeviceCommandId_t, DeviceReplyInfo> ;
using DeviceReplyIter = DeviceReplyMap::iterator; using DeviceReplyIter = DeviceReplyMap::iterator;
/** /**
* The MessageQueue used to receive device handler commands and to send replies. * This map is used to check and track correct reception of all replies.
*
* It has multiple use:
* - It stores the information on pending replies. If a command is sent,
* the DeviceCommandInfo.count is incremented.
* - It is used to time-out missing replies. If a command is sent, the
* DeviceCommandInfo.DelayCycles is set to MaxDelayCycles.
* - It is queried to check if a reply from the device can be interpreted.
* scanForReply() returns the id of the command a reply was found for.
* The reply is ignored in the following cases:
* - No entry for the returned id was found
* - The deviceReplyInfo.delayCycles is == 0
*/ */
DeviceReplyMap deviceReplyMap;
//! The MessageQueue used to receive device handler commands
//! and to send replies.
MessageQueueIF* commandQueue = nullptr; MessageQueueIF* commandQueue = nullptr;
/** /**
@ -642,23 +679,14 @@ protected:
* *
* can be set to PoolVariableIF::NO_PARAMETER to deactivate thermal checking * can be set to PoolVariableIF::NO_PARAMETER to deactivate thermal checking
*/ */
uint32_t deviceThermalStatePoolId; uint32_t deviceThermalStatePoolId = PoolVariableIF::NO_PARAMETER;
/** /**
* this is the datapool variable with the thermal request of the device * this is the datapool variable with the thermal request of the device
* *
* can be set to PoolVariableIF::NO_PARAMETER to deactivate thermal checking * can be set to PoolVariableIF::NO_PARAMETER to deactivate thermal checking
*/ */
uint32_t deviceThermalRequestPoolId; uint32_t deviceThermalRequestPoolId = PoolVariableIF::NO_PARAMETER;
/**
* Taking care of the health
*/
HealthHelper healthHelper;
ModeHelper modeHelper;
ParameterHelper parameterHelper;
/** /**
* Optional Error code * Optional Error code
@ -676,13 +704,15 @@ protected:
bool switchOffWasReported; //!< Indicates if SWITCH_WENT_OFF was already thrown. bool switchOffWasReported; //!< Indicates if SWITCH_WENT_OFF was already thrown.
PeriodicTaskIF* executingTask = nullptr;//!< Pointer to the task which executes this component, is invalid before setTaskIF was called. //! Pointer to the task which executes this component, is invalid
//! before setTaskIF was called.
PeriodicTaskIF* executingTask = nullptr;
static object_id_t powerSwitcherId; //!< Object which switches power on and off. static object_id_t powerSwitcherId; //!< Object which switches power on and off.
static object_id_t rawDataReceiverId; //!< Object which receives RAW data by default. static object_id_t rawDataReceiverId; //!< Object which receives RAW data by default.
static object_id_t defaultFDIRParentId; //!< Object which may be the root cause of an identified fault. static object_id_t defaultFdirParentId; //!< Object which may be the root cause of an identified fault.
/** /**
* Helper function to report a missed reply * Helper function to report a missed reply
* *
@ -730,28 +760,40 @@ protected:
/** /**
* Do the transition to the main modes (MODE_ON, MODE_NORMAL and MODE_RAW). * Do the transition to the main modes (MODE_ON, MODE_NORMAL and MODE_RAW).
* *
* If the transition is complete, the mode should be set to the target mode, which can be deduced from the current mode which is * If the transition is complete, the mode should be set to the target mode,
* which can be deduced from the current mode which is
* [_MODE_TO_ON, _MODE_TO_NORMAL, _MODE_TO_RAW] * [_MODE_TO_ON, _MODE_TO_NORMAL, _MODE_TO_RAW]
* *
* The intended target submode is already set. The origin submode can be read in subModeFrom. * The intended target submode is already set.
* The origin submode can be read in subModeFrom.
* *
* If the transition can not be completed, the child class can try to reach an working mode by setting the mode either directly * If the transition can not be completed, the child class can try to reach
* or setting the mode to an transitional mode (TO_ON, TO_NORMAL, TO_RAW) if the device needs to be reconfigured. * an working mode by setting the mode either directly
* or setting the mode to an transitional mode (TO_ON, TO_NORMAL, TO_RAW)
* if the device needs to be reconfigured.
* *
* If nothing works, the child class can wait for the timeout and the base class will reset the mode to the mode where the transition * If nothing works, the child class can wait for the timeout and the base
* class will reset the mode to the mode where the transition
* originated from (the child should report the reason for the failed transition). * originated from (the child should report the reason for the failed transition).
* *
* The intended way to send commands is to set a flag (enum) indicating which command is to be sent here * The intended way to send commands is to set a flag (enum) indicating
* and then to check in buildTransitionCommand() for the flag. This flag can also be used by doStartUp() and * which command is to be sent here and then to check in
* doShutDown() to get a nice and clean implementation of buildTransitionCommand() without switching through modes. * buildTransitionCommand() for the flag. This flag can also be used by
* doStartUp() and doShutDown() to get a nice and clean implementation of
* buildTransitionCommand() without switching through modes.
* *
* When the the condition for the completion of the transition is met, the mode can be set, for example in the parseReply() function. * When the the condition for the completion of the transition is met, the
* mode can be set, for example in the scanForReply() function.
* *
* The default implementation goes into the target mode; * The default implementation goes into the target mode directly.
* *
* #transitionFailure can be set to a failure code indicating the reason for a failed transition * #transitionFailure can be set to a failure code indicating the reason
* for a failed transition
* *
* @param modeFrom the mode the transition originated from: [MODE_ON, MODE_NORMAL, MODE_RAW and _MODE_POWER_DOWN (if the mode changed from _MODE_START_UP to _MODE_TO_ON)] * @param modeFrom
* The mode the transition originated from:
* [MODE_ON, MODE_NORMAL, MODE_RAW and _MODE_POWER_DOWN (if the mode changed
* from _MODE_START_UP to _MODE_TO_ON)]
* @param subModeFrom the subMode of modeFrom * @param subModeFrom the subMode of modeFrom
*/ */
virtual void doTransition(Mode_t modeFrom, Submode_t subModeFrom); virtual void doTransition(Mode_t modeFrom, Submode_t subModeFrom);
@ -953,24 +995,11 @@ protected:
bool commandIsExecuting(DeviceCommandId_t commandId); bool commandIsExecuting(DeviceCommandId_t commandId);
/** /**
* This map is used to check and track correct reception of all replies. * set all switches returned by getSwitches()
* *
* It has multiple use: * @param onOff on == @c SWITCH_ON; off != @c SWITCH_ON
* - it stores the information on pending replies. If a command is sent, the DeviceCommandInfo.count is incremented.
* - it is used to time-out missing replies. If a command is sent, the DeviceCommandInfo.DelayCycles is set to MaxDelayCycles.
* - it is queried to check if a reply from the device can be interpreted. scanForReply() returns the id of the command a reply was found for.
* The reply is ignored in the following cases:
* - No entry for the returned id was found
* - The deviceReplyInfo.delayCycles is == 0
*/ */
DeviceReplyMap deviceReplyMap; void commandSwitch(ReturnValue_t onOff);
/**
* Information about commands
*/
DeviceCommandMap deviceCommandMap;
ActionHelper actionHelper;
private: private:
/** /**
@ -997,15 +1026,16 @@ private:
}; };
/** /**
* Info about the #cookie * @brief Info about the #cookie
*
* Used to track the state of the communication * Used to track the state of the communication
*/ */
CookieInfo cookieInfo; CookieInfo cookieInfo;
/** the object used to set power switches */
PowerSwitchIF *powerSwitcher = nullptr;
/** /**
* Used for timing out mode transitions. * @brief Used for timing out mode transitions.
*
* Set when setMode() is called. * Set when setMode() is called.
*/ */
uint32_t timeoutStart = 0; uint32_t timeoutStart = 0;
@ -1016,11 +1046,12 @@ private:
uint32_t childTransitionDelay; uint32_t childTransitionDelay;
/** /**
* The mode the current transition originated from * @brief The mode the current transition originated from
* *
* This is private so the child can not change it and fuck up the timeouts * This is private so the child can not change it and fuck up the timeouts
* *
* IMPORTANT: This is not valid during _MODE_SHUT_DOWN and _MODE_START_UP!! (it is _MODE_POWER_DOWN during this modes) * IMPORTANT: This is not valid during _MODE_SHUT_DOWN and _MODE_START_UP!!
* (it is _MODE_POWER_DOWN during this modes)
* *
* is element of [MODE_ON, MODE_NORMAL, MODE_RAW] * is element of [MODE_ON, MODE_NORMAL, MODE_RAW]
*/ */
@ -1031,13 +1062,6 @@ private:
*/ */
Submode_t transitionSourceSubMode; Submode_t transitionSourceSubMode;
/**
* the switch of the device
*
* for devices using two switches override getSwitches()
*/
const uint8_t deviceSwitch;
/** /**
* read the command queue * read the command queue
*/ */
@ -1135,12 +1159,6 @@ private:
ReturnValue_t getStorageData(store_address_t storageAddress, uint8_t **data, ReturnValue_t getStorageData(store_address_t storageAddress, uint8_t **data,
uint32_t *len); uint32_t *len);
/**
* set all switches returned by getSwitches()
*
* @param onOff on == @c SWITCH_ON; off != @c SWITCH_ON
*/
void commandSwitch(ReturnValue_t onOff);
/** /**
* @param modeTo either @c MODE_ON, MODE_NORMAL or MODE_RAW NOTHING ELSE!!! * @param modeTo either @c MODE_ON, MODE_NORMAL or MODE_RAW NOTHING ELSE!!!
@ -1165,7 +1183,12 @@ private:
ReturnValue_t switchCookieChannel(object_id_t newChannelId); ReturnValue_t switchCookieChannel(object_id_t newChannelId);
ReturnValue_t handleDeviceHandlerMessage(CommandMessage *message); ReturnValue_t handleDeviceHandlerMessage(CommandMessage *message);
virtual ReturnValue_t initializeAfterTaskCreation() override;
void parseReply(const uint8_t* receivedData,
size_t receivedDataLen);
}; };
#endif /* DEVICEHANDLERBASE_H_ */ #endif /* FRAMEWORK_DEVICEHANDLERS_DEVICEHANDLERBASE_H_ */

View File

@ -1,19 +1,27 @@
#include "DeviceHandlerBase.h"
#include "DeviceHandlerFailureIsolation.h" #include "DeviceHandlerFailureIsolation.h"
#include "../devicehandlers/DeviceHandlerIF.h"
#include "../modes/HasModesIF.h"
#include "../health/HealthTableIF.h" #include "../health/HealthTableIF.h"
#include "../power/Fuse.h" #include "../power/Fuse.h"
#include "../serviceinterface/ServiceInterfaceStream.h" #include "../serviceinterface/ServiceInterfaceStream.h"
#include "../thermal/ThermalComponentIF.h" #include "../thermal/ThermalComponentIF.h"
object_id_t DeviceHandlerFailureIsolation::powerConfirmationId = 0; object_id_t DeviceHandlerFailureIsolation::powerConfirmationId =
objects::NO_OBJECT;
DeviceHandlerFailureIsolation::DeviceHandlerFailureIsolation(object_id_t owner, object_id_t parent) : DeviceHandlerFailureIsolation::DeviceHandlerFailureIsolation(object_id_t owner,
FailureIsolationBase(owner, parent), strangeReplyCount(MAX_STRANGE_REPLIES, object_id_t parent) :
STRANGE_REPLIES_TIME_MS, parameterDomainBase++), missedReplyCount( FailureIsolationBase(owner, parent),
MAX_MISSED_REPLY_COUNT, MISSED_REPLY_TIME_MS, strangeReplyCount(DEFAULT_MAX_STRANGE_REPLIES,
parameterDomainBase++), recoveryCounter(MAX_REBOOT, DEFAULT_STRANGE_REPLIES_TIME_MS,
REBOOT_TIME_MS, parameterDomainBase++), fdirState(NONE), powerConfirmation( parameterDomainBase++),
0) { missedReplyCount( DEFAULT_MAX_MISSED_REPLY_COUNT,
DEFAULT_MISSED_REPLY_TIME_MS,
parameterDomainBase++),
recoveryCounter(DEFAULT_MAX_REBOOT, DEFAULT_REBOOT_TIME_MS,
parameterDomainBase++),
fdirState(NONE) {
} }
DeviceHandlerFailureIsolation::~DeviceHandlerFailureIsolation() { DeviceHandlerFailureIsolation::~DeviceHandlerFailureIsolation() {
@ -68,10 +76,12 @@ ReturnValue_t DeviceHandlerFailureIsolation::eventReceived(EventMessage* event)
break; break;
//****Power***** //****Power*****
case PowerSwitchIF::SWITCH_WENT_OFF: case PowerSwitchIF::SWITCH_WENT_OFF:
if(powerConfirmation != MessageQueueIF::NO_QUEUE) {
result = sendConfirmationRequest(event, powerConfirmation); result = sendConfirmationRequest(event, powerConfirmation);
if (result == RETURN_OK) { if (result == RETURN_OK) {
setFdirState(DEVICE_MIGHT_BE_OFF); setFdirState(DEVICE_MIGHT_BE_OFF);
} }
}
break; break;
case Fuse::FUSE_WENT_OFF: case Fuse::FUSE_WENT_OFF:
//Not so good, because PCDU reacted. //Not so good, because PCDU reacted.
@ -133,7 +143,7 @@ void DeviceHandlerFailureIsolation::decrementFaultCounters() {
void DeviceHandlerFailureIsolation::handleRecovery(Event reason) { void DeviceHandlerFailureIsolation::handleRecovery(Event reason) {
clearFaultCounters(); clearFaultCounters();
if (!recoveryCounter.incrementAndCheck()) { if (not recoveryCounter.incrementAndCheck()) {
startRecovery(reason); startRecovery(reason);
} else { } else {
setFaulty(reason); setFaulty(reason);
@ -142,7 +152,8 @@ void DeviceHandlerFailureIsolation::handleRecovery(Event reason) {
void DeviceHandlerFailureIsolation::wasParentsFault(EventMessage* event) { void DeviceHandlerFailureIsolation::wasParentsFault(EventMessage* event) {
//We'll better ignore the SWITCH_WENT_OFF event and await a system-wide reset. //We'll better ignore the SWITCH_WENT_OFF event and await a system-wide reset.
//This means, no fault message will come through until a MODE_ or HEALTH_INFO message comes through -> Is that ok? //This means, no fault message will come through until a MODE_ or
//HEALTH_INFO message comes through -> Is that ok?
//Same issue in TxFailureIsolation! //Same issue in TxFailureIsolation!
// if ((event->getEvent() == PowerSwitchIF::SWITCH_WENT_OFF) // if ((event->getEvent() == PowerSwitchIF::SWITCH_WENT_OFF)
// && (fdirState != RECOVERY_ONGOING)) { // && (fdirState != RECOVERY_ONGOING)) {
@ -158,14 +169,16 @@ void DeviceHandlerFailureIsolation::clearFaultCounters() {
ReturnValue_t DeviceHandlerFailureIsolation::initialize() { ReturnValue_t DeviceHandlerFailureIsolation::initialize() {
ReturnValue_t result = FailureIsolationBase::initialize(); ReturnValue_t result = FailureIsolationBase::initialize();
if (result != HasReturnvaluesIF::RETURN_OK) { if (result != HasReturnvaluesIF::RETURN_OK) {
sif::error << "DeviceHandlerFailureIsolation::initialize: Could not"
" initialize FailureIsolationBase." << std::endl;
return result; return result;
} }
ConfirmsFailuresIF* power = objectManager->get<ConfirmsFailuresIF>( ConfirmsFailuresIF* power = objectManager->get<ConfirmsFailuresIF>(
powerConfirmationId); powerConfirmationId);
if (power == NULL) { if (power != nullptr) {
return RETURN_FAILED;
}
powerConfirmation = power->getEventReceptionQueue(); powerConfirmation = power->getEventReceptionQueue();
}
return RETURN_OK; return RETURN_OK;
} }

View File

@ -1,13 +1,13 @@
#ifndef FRAMEWORK_DEVICEHANDLERS_DEVICEHANDLERFAILUREISOLATION_H_ #ifndef FSFW_DEVICEHANDLERS_DEVICEHANDLERFAILUREISOLATION_H_
#define FRAMEWORK_DEVICEHANDLERS_DEVICEHANDLERFAILUREISOLATION_H_ #define FSFW_DEVICEHANDLERS_DEVICEHANDLERFAILUREISOLATION_H_
#include "../fdir/FaultCounter.h" #include "../fdir/FaultCounter.h"
#include "../fdir/FailureIsolationBase.h" #include "../fdir/FailureIsolationBase.h"
namespace Factory{ namespace Factory{
void setStaticFrameworkObjectIds(); void setStaticFrameworkObjectIds();
} }
class DeviceHandlerFailureIsolation: public FailureIsolationBase { class DeviceHandlerFailureIsolation: public FailureIsolationBase {
friend void (Factory::setStaticFrameworkObjectIds)(); friend void (Factory::setStaticFrameworkObjectIds)();
friend class Heater; friend class Heater;
@ -20,22 +20,27 @@ public:
virtual ReturnValue_t getParameter(uint8_t domainId, uint16_t parameterId, virtual ReturnValue_t getParameter(uint8_t domainId, uint16_t parameterId,
ParameterWrapper *parameterWrapper, ParameterWrapper *parameterWrapper,
const ParameterWrapper *newValues, uint16_t startAtIndex); const ParameterWrapper *newValues, uint16_t startAtIndex);
protected: protected:
FaultCounter strangeReplyCount; FaultCounter strangeReplyCount;
FaultCounter missedReplyCount; FaultCounter missedReplyCount;
FaultCounter recoveryCounter; FaultCounter recoveryCounter;
enum FDIRState { enum FDIRState {
NONE, RECOVERY_ONGOING, DEVICE_MIGHT_BE_OFF, AWAIT_SHUTDOWN NONE, RECOVERY_ONGOING, DEVICE_MIGHT_BE_OFF, AWAIT_SHUTDOWN
}; };
FDIRState fdirState; FDIRState fdirState;
MessageQueueId_t powerConfirmation;
MessageQueueId_t powerConfirmation = MessageQueueIF::NO_QUEUE;
static object_id_t powerConfirmationId; static object_id_t powerConfirmationId;
static const uint32_t MAX_REBOOT = 1;
static const uint32_t REBOOT_TIME_MS = 180000; static const uint32_t DEFAULT_MAX_REBOOT = 1;
static const uint32_t MAX_STRANGE_REPLIES = 10; static const uint32_t DEFAULT_REBOOT_TIME_MS = 180000;
static const uint32_t STRANGE_REPLIES_TIME_MS = 10000; static const uint32_t DEFAULT_MAX_STRANGE_REPLIES = 10;
static const uint32_t MAX_MISSED_REPLY_COUNT = 5; static const uint32_t DEFAULT_STRANGE_REPLIES_TIME_MS = 10000;
static const uint32_t MISSED_REPLY_TIME_MS = 10000; static const uint32_t DEFAULT_MAX_MISSED_REPLY_COUNT = 5;
static const uint32_t DEFAULT_MISSED_REPLY_TIME_MS = 10000;
virtual ReturnValue_t eventReceived(EventMessage* event); virtual ReturnValue_t eventReceived(EventMessage* event);
virtual void eventConfirmed(EventMessage* event); virtual void eventConfirmed(EventMessage* event);
void wasParentsFault(EventMessage* event); void wasParentsFault(EventMessage* event);
@ -49,4 +54,4 @@ protected:
bool isFdirInActionOrAreWeFaulty(EventMessage* event); bool isFdirInActionOrAreWeFaulty(EventMessage* event);
}; };
#endif /* FRAMEWORK_DEVICEHANDLERS_DEVICEHANDLERFAILUREISOLATION_H_ */ #endif /* FSFW_DEVICEHANDLERS_DEVICEHANDLERFAILUREISOLATION_H_ */

View File

@ -8,13 +8,16 @@
const uint16_t EventManager::POOL_SIZES[N_POOLS] = { const uint16_t EventManager::POOL_SIZES[N_POOLS] = {
sizeof(EventMatchTree::Node), sizeof(EventIdRangeMatcher), sizeof(EventMatchTree::Node), sizeof(EventIdRangeMatcher),
sizeof(ReporterRangeMatcher) }; sizeof(ReporterRangeMatcher) };
//If one checks registerListener calls, there are around 40 (to max 50) objects registering for certain events. // If one checks registerListener calls, there are around 40 (to max 50)
//Each listener requires 1 or 2 EventIdMatcher and 1 or 2 ReportRangeMatcher. So a good guess is 75 to a max of 100 pools required for each, which fits well. // objects registering for certain events.
// Each listener requires 1 or 2 EventIdMatcher and 1 or 2 ReportRangeMatcher.
// So a good guess is 75 to a max of 100 pools required for each, which fits well.
// SHOULDDO: Shouldn't this be in the config folder and passed via ctor?
const uint16_t EventManager::N_ELEMENTS[N_POOLS] = { 240, 120, 120 }; const uint16_t EventManager::N_ELEMENTS[N_POOLS] = { 240, 120, 120 };
EventManager::EventManager(object_id_t setObjectId) : EventManager::EventManager(object_id_t setObjectId) :
SystemObject(setObjectId), eventReportQueue(NULL), mutex(NULL), factoryBackend( SystemObject(setObjectId),
0, POOL_SIZES, N_ELEMENTS, false, true) { factoryBackend(0, POOL_SIZES, N_ELEMENTS, false, true) {
mutex = MutexFactory::instance()->createMutex(); mutex = MutexFactory::instance()->createMutex();
eventReportQueue = QueueFactory::instance()->createMessageQueue( eventReportQueue = QueueFactory::instance()->createMessageQueue(
MAX_EVENTS_PER_CYCLE, EventMessage::EVENT_MESSAGE_SIZE); MAX_EVENTS_PER_CYCLE, EventMessage::EVENT_MESSAGE_SIZE);
@ -108,41 +111,45 @@ ReturnValue_t EventManager::unsubscribeFromEventRange(MessageQueueId_t listener,
#ifdef DEBUG #ifdef DEBUG
//forward declaration, should be implemented by mission
const char* translateObject(object_id_t object);
const char * translateEvents(Event event);
void EventManager::printEvent(EventMessage* message) { void EventManager::printEvent(EventMessage* message) {
const char *string = 0; const char *string = 0;
switch (message->getSeverity()) { switch (message->getSeverity()) {
case SEVERITY::INFO: case SEVERITY::INFO:
// string = translateObject(message->getReporter()); #ifdef DEBUG_INFO_EVENT
// sif::info << "EVENT: ";
// if (string != 0) {
// sif::info << string;
// } else {
// sif::info << "0x" << std::hex << message->getReporter() << std::dec;
// }
// sif::info << " reported " << translateEvents(message->getEvent()) << " ("
// << std::dec << message->getEventId() << std::hex << ") P1: 0x"
// << message->getParameter1() << " P2: 0x"
// << message->getParameter2() << std::dec << std::endl;
break;
default:
string = translateObject(message->getReporter()); string = translateObject(message->getReporter());
sif::error << "EVENT: "; sif::info << "EVENT: ";
if (string != 0) { if (string != 0) {
sif::error << string; sif::info << string;
} else { } else {
sif::error << "0x" << std::hex << message->getReporter() << std::dec; sif::info << "0x" << std::hex << message->getReporter() << std::dec;
} }
sif::error << " reported " << translateEvents(message->getEvent()) << " (" sif::info << " reported " << translateEvents(message->getEvent()) << " ("
<< std::dec << message->getEventId() << std::hex << ") P1: 0x" << std::dec << message->getEventId() << std::hex << ") P1: 0x"
<< message->getParameter1() << " P2: 0x" << message->getParameter1() << " P2: 0x"
<< message->getParameter2() << std::dec << std::endl; << message->getParameter2() << std::dec << std::endl;
#endif
break;
default:
string = translateObject(message->getReporter());
sif::debug << "EventManager: ";
if (string != 0) {
sif::debug << string;
}
else {
sif::debug << "0x" << std::hex << message->getReporter() << std::dec;
}
sif::debug << " reported " << translateEvents(message->getEvent())
<< " (" << std::dec << message->getEventId() << ") "
<< std::endl;
sif::debug << std::hex << "P1 Hex: 0x" << message->getParameter1()
<< ", P1 Dec: " << std::dec << message->getParameter1()
<< std::endl;
sif::debug << std::hex << "P2 Hex: 0x" << message->getParameter2()
<< ", P2 Dec: " << std::dec << message->getParameter2()
<< std::endl;
break; break;
} }
} }
#endif #endif

View File

@ -10,6 +10,12 @@
#include "../ipc/MutexIF.h" #include "../ipc/MutexIF.h"
#include <map> #include <map>
#ifdef DEBUG
// forward declaration, should be implemented by mission
extern const char* translateObject(object_id_t object);
extern const char* translateEvents(Event event);
#endif
class EventManager: public EventManagerIF, class EventManager: public EventManagerIF,
public ExecutableObjectIF, public ExecutableObjectIF,
public SystemObject { public SystemObject {
@ -36,11 +42,11 @@ public:
ReturnValue_t performOperation(uint8_t opCode); ReturnValue_t performOperation(uint8_t opCode);
protected: protected:
MessageQueueIF* eventReportQueue; MessageQueueIF* eventReportQueue = nullptr;
std::map<MessageQueueId_t, EventMatchTree> listenerList; std::map<MessageQueueId_t, EventMatchTree> listenerList;
MutexIF* mutex; MutexIF* mutex = nullptr;
static const uint8_t N_POOLS = 3; static const uint8_t N_POOLS = 3;
LocalPool<N_POOLS> factoryBackend; LocalPool<N_POOLS> factoryBackend;

View File

@ -5,10 +5,12 @@
#include "../ipc/QueueFactory.h" #include "../ipc/QueueFactory.h"
#include "../objectmanager/ObjectManagerIF.h" #include "../objectmanager/ObjectManagerIF.h"
FailureIsolationBase::FailureIsolationBase(object_id_t owner, object_id_t parent, uint8_t messageDepth, uint8_t parameterDomainBase) : FailureIsolationBase::FailureIsolationBase(object_id_t owner,
eventQueue(NULL), ownerId( object_id_t parent, uint8_t messageDepth, uint8_t parameterDomainBase) :
owner), owner(NULL), faultTreeParent(parent), parameterDomainBase(parameterDomainBase) { ownerId(owner), faultTreeParent(parent),
eventQueue = QueueFactory::instance()->createMessageQueue(messageDepth, EventMessage::EVENT_MESSAGE_SIZE); parameterDomainBase(parameterDomainBase) {
eventQueue = QueueFactory::instance()->createMessageQueue(messageDepth,
EventMessage::EVENT_MESSAGE_SIZE);
} }
FailureIsolationBase::~FailureIsolationBase() { FailureIsolationBase::~FailureIsolationBase() {
@ -18,27 +20,36 @@ FailureIsolationBase::~FailureIsolationBase() {
ReturnValue_t FailureIsolationBase::initialize() { ReturnValue_t FailureIsolationBase::initialize() {
EventManagerIF* manager = objectManager->get<EventManagerIF>( EventManagerIF* manager = objectManager->get<EventManagerIF>(
objects::EVENT_MANAGER); objects::EVENT_MANAGER);
if (manager == NULL) { if (manager == nullptr) {
sif::error << "FailureIsolationBase::initialize: Event Manager has not"
" been initialized!" << std::endl;
return RETURN_FAILED; return RETURN_FAILED;
} }
ReturnValue_t result = manager->registerListener(eventQueue->getId()); ReturnValue_t result = manager->registerListener(eventQueue->getId());
if (result != HasReturnvaluesIF::RETURN_OK) { if (result != HasReturnvaluesIF::RETURN_OK) {
return result; return result;
} }
if (ownerId != 0) { if (ownerId != objects::NO_OBJECT) {
result = manager->subscribeToAllEventsFrom(eventQueue->getId(), ownerId); result = manager->subscribeToAllEventsFrom(eventQueue->getId(), ownerId);
if (result != HasReturnvaluesIF::RETURN_OK) { if (result != HasReturnvaluesIF::RETURN_OK) {
return result; return result;
} }
owner = objectManager->get<HasHealthIF>(ownerId); owner = objectManager->get<HasHealthIF>(ownerId);
if (owner == NULL) { if (owner == nullptr) {
return RETURN_FAILED; sif::error << "FailureIsolationBase::intialize: Owner object "
"invalid. Make sure it implements HasHealthIF" << std::endl;
return ObjectManagerIF::CHILD_INIT_FAILED;
} }
} }
if (faultTreeParent != 0) { if (faultTreeParent != objects::NO_OBJECT) {
ConfirmsFailuresIF* parentIF = objectManager->get<ConfirmsFailuresIF>( ConfirmsFailuresIF* parentIF = objectManager->get<ConfirmsFailuresIF>(
faultTreeParent); faultTreeParent);
if (parentIF == NULL) { if (parentIF == nullptr) {
sif::error << "FailureIsolationBase::intialize: Parent object"
<< "invalid." << std::endl;
sif::error << "Make sure it implements ConfirmsFailuresIF."
<< std::endl;
return ObjectManagerIF::CHILD_INIT_FAILED;
return RETURN_FAILED; return RETURN_FAILED;
} }
eventQueue->setDefaultDestination(parentIF->getEventReceptionQueue()); eventQueue->setDefaultDestination(parentIF->getEventReceptionQueue());
@ -93,9 +104,9 @@ MessageQueueId_t FailureIsolationBase::getEventReceptionQueue() {
ReturnValue_t FailureIsolationBase::sendConfirmationRequest(EventMessage* event, ReturnValue_t FailureIsolationBase::sendConfirmationRequest(EventMessage* event,
MessageQueueId_t destination) { MessageQueueId_t destination) {
event->setMessageId(EventMessage::CONFIRMATION_REQUEST); event->setMessageId(EventMessage::CONFIRMATION_REQUEST);
if (destination != 0) { if (destination != MessageQueueIF::NO_QUEUE) {
return eventQueue->sendMessage(destination, event); return eventQueue->sendMessage(destination, event);
} else if (faultTreeParent != 0) { } else if (faultTreeParent != objects::NO_OBJECT) {
return eventQueue->sendToDefault(event); return eventQueue->sendToDefault(event);
} }
return RETURN_FAILED; return RETURN_FAILED;

View File

@ -17,18 +17,25 @@ public:
static const Event FDIR_CHANGED_STATE = MAKE_EVENT(1, SEVERITY::INFO); //!< FDIR has an internal state, which changed from par2 (oldState) to par1 (newState). static const Event FDIR_CHANGED_STATE = MAKE_EVENT(1, SEVERITY::INFO); //!< FDIR has an internal state, which changed from par2 (oldState) to par1 (newState).
static const Event FDIR_STARTS_RECOVERY = MAKE_EVENT(2, SEVERITY::MEDIUM); //!< FDIR tries to restart device. Par1: event that caused recovery. static const Event FDIR_STARTS_RECOVERY = MAKE_EVENT(2, SEVERITY::MEDIUM); //!< FDIR tries to restart device. Par1: event that caused recovery.
static const Event FDIR_TURNS_OFF_DEVICE = MAKE_EVENT(3, SEVERITY::MEDIUM); //!< FDIR turns off device. Par1: event that caused recovery. static const Event FDIR_TURNS_OFF_DEVICE = MAKE_EVENT(3, SEVERITY::MEDIUM); //!< FDIR turns off device. Par1: event that caused recovery.
FailureIsolationBase(object_id_t owner, object_id_t parent = 0,
FailureIsolationBase(object_id_t owner,
object_id_t parent = objects::NO_OBJECT,
uint8_t messageDepth = 10, uint8_t parameterDomainBase = 0xF0); uint8_t messageDepth = 10, uint8_t parameterDomainBase = 0xF0);
virtual ~FailureIsolationBase(); virtual ~FailureIsolationBase();
virtual ReturnValue_t initialize(); virtual ReturnValue_t initialize();
/**
* This is called by the DHB in performOperation()
*/
void checkForFailures(); void checkForFailures();
MessageQueueId_t getEventReceptionQueue(); MessageQueueId_t getEventReceptionQueue() override;
virtual void triggerEvent(Event event, uint32_t parameter1 = 0, virtual void triggerEvent(Event event, uint32_t parameter1 = 0,
uint32_t parameter2 = 0); uint32_t parameter2 = 0);
protected: protected:
MessageQueueIF* eventQueue; MessageQueueIF* eventQueue = nullptr;
object_id_t ownerId; object_id_t ownerId;
HasHealthIF* owner; HasHealthIF* owner = nullptr;
object_id_t faultTreeParent; object_id_t faultTreeParent;
uint8_t parameterDomainBase; uint8_t parameterDomainBase;
void setOwnerHealth(HasHealthIF::HealthState health); void setOwnerHealth(HasHealthIF::HealthState health);
@ -38,7 +45,7 @@ protected:
virtual ReturnValue_t confirmFault(EventMessage* event); virtual ReturnValue_t confirmFault(EventMessage* event);
virtual void decrementFaultCounters() = 0; virtual void decrementFaultCounters() = 0;
ReturnValue_t sendConfirmationRequest(EventMessage* event, ReturnValue_t sendConfirmationRequest(EventMessage* event,
MessageQueueId_t destination = 0); MessageQueueId_t destination = MessageQueueIF::NO_QUEUE);
void throwFdirEvent(Event event, uint32_t parameter1 = 0, void throwFdirEvent(Event event, uint32_t parameter1 = 0,
uint32_t parameter2 = 0); uint32_t parameter2 = 0);
private: private:

View File

@ -1,95 +1,124 @@
#include "DleEncoder.h" #include "../globalfunctions/DleEncoder.h"
DleEncoder::DleEncoder() { DleEncoder::DleEncoder() {}
}
DleEncoder::~DleEncoder() { DleEncoder::~DleEncoder() {}
ReturnValue_t DleEncoder::encode(const uint8_t* sourceStream,
size_t sourceLen, uint8_t* destStream, size_t maxDestLen,
size_t* encodedLen, bool addStxEtx) {
if (maxDestLen < 2) {
return STREAM_TOO_SHORT;
}
size_t encodedIndex = 0, sourceIndex = 0;
uint8_t nextByte;
if (addStxEtx) {
destStream[0] = STX_CHAR;
++encodedIndex;
}
while (encodedIndex < maxDestLen and sourceIndex < sourceLen)
{
nextByte = sourceStream[sourceIndex];
// STX, ETX and CR characters in the stream need to be escaped with DLE
if (nextByte == STX_CHAR or nextByte == ETX_CHAR or nextByte == CARRIAGE_RETURN) {
if (encodedIndex + 1 >= maxDestLen) {
return STREAM_TOO_SHORT;
}
else {
destStream[encodedIndex] = DLE_CHAR;
++encodedIndex;
/* Escaped byte will be actual byte + 0x40. This prevents
* STX, ETX, and carriage return characters from appearing
* in the encoded data stream at all, so when polling an
* encoded stream, the transmission can be stopped at ETX.
* 0x40 was chosen at random with special requirements:
* - Prevent going from one control char to another
* - Prevent overflow for common characters */
destStream[encodedIndex] = nextByte + 0x40;
}
}
// DLE characters are simply escaped with DLE.
else if (nextByte == DLE_CHAR) {
if (encodedIndex + 1 >= maxDestLen) {
return STREAM_TOO_SHORT;
}
else {
destStream[encodedIndex] = DLE_CHAR;
++encodedIndex;
destStream[encodedIndex] = DLE_CHAR;
}
}
else {
destStream[encodedIndex] = nextByte;
}
++encodedIndex;
++sourceIndex;
}
if (sourceIndex == sourceLen and encodedIndex < maxDestLen) {
if (addStxEtx) {
destStream[encodedIndex] = ETX_CHAR;
++encodedIndex;
}
*encodedLen = encodedIndex;
return RETURN_OK;
}
else {
return STREAM_TOO_SHORT;
}
} }
ReturnValue_t DleEncoder::decode(const uint8_t *sourceStream, ReturnValue_t DleEncoder::decode(const uint8_t *sourceStream,
uint32_t sourceStreamLen, uint32_t *readLen, uint8_t *destStream, size_t sourceStreamLen, size_t *readLen, uint8_t *destStream,
uint32_t maxDestStreamlen, uint32_t *decodedLen) { size_t maxDestStreamlen, size_t *decodedLen) {
uint32_t encodedIndex = 0, decodedIndex = 0; size_t encodedIndex = 0, decodedIndex = 0;
uint8_t nextByte; uint8_t nextByte;
if (*sourceStream != STX) { if (*sourceStream != STX_CHAR) {
return RETURN_FAILED; return DECODING_ERROR;
} }
++encodedIndex; ++encodedIndex;
while ((encodedIndex < sourceStreamLen) && (decodedIndex < maxDestStreamlen) while ((encodedIndex < sourceStreamLen) && (decodedIndex < maxDestStreamlen)
&& (sourceStream[encodedIndex] != ETX) && (sourceStream[encodedIndex] != ETX_CHAR)
&& (sourceStream[encodedIndex] != STX)) { && (sourceStream[encodedIndex] != STX_CHAR)) {
if (sourceStream[encodedIndex] == DLE) { if (sourceStream[encodedIndex] == DLE_CHAR) {
nextByte = sourceStream[encodedIndex + 1]; nextByte = sourceStream[encodedIndex + 1];
if (nextByte == 0x10) { // The next byte is a DLE character that was escaped by another
// DLE character, so we can write it to the destination stream.
if (nextByte == DLE_CHAR) {
destStream[decodedIndex] = nextByte; destStream[decodedIndex] = nextByte;
} else { }
if ((nextByte == 0x42) || (nextByte == 0x43) else {
|| (nextByte == 0x4D)) { /* The next byte is a STX, DTX or 0x0D character which
* was escaped by a DLE character. The actual byte was
* also encoded by adding + 0x40 to prevent having control chars,
* in the stream at all, so we convert it back. */
if (nextByte == 0x42 or nextByte == 0x43 or nextByte == 0x4D) {
destStream[decodedIndex] = nextByte - 0x40; destStream[decodedIndex] = nextByte - 0x40;
} else { }
return RETURN_FAILED; else {
return DECODING_ERROR;
} }
} }
++encodedIndex; ++encodedIndex;
} else { }
else {
destStream[decodedIndex] = sourceStream[encodedIndex]; destStream[decodedIndex] = sourceStream[encodedIndex];
} }
++encodedIndex; ++encodedIndex;
++decodedIndex; ++decodedIndex;
} }
if (sourceStream[encodedIndex] != ETX) {
return RETURN_FAILED; if (sourceStream[encodedIndex] != ETX_CHAR) {
} else { *readLen = ++encodedIndex;
return DECODING_ERROR;
}
else {
*readLen = ++encodedIndex; *readLen = ++encodedIndex;
*decodedLen = decodedIndex; *decodedLen = decodedIndex;
return RETURN_OK; return RETURN_OK;
} }
} }
ReturnValue_t DleEncoder::encode(const uint8_t* sourceStream,
uint32_t sourceLen, uint8_t* destStream, uint32_t maxDestLen,
uint32_t* encodedLen, bool addStxEtx) {
if (maxDestLen < 2) {
return RETURN_FAILED;
}
uint32_t encodedIndex = 0, sourceIndex = 0;
uint8_t nextByte;
if (addStxEtx) {
destStream[0] = STX;
++encodedIndex;
}
while ((encodedIndex < maxDestLen) && (sourceIndex < sourceLen)) {
nextByte = sourceStream[sourceIndex];
if ((nextByte == STX) || (nextByte == ETX) || (nextByte == 0x0D)) {
if (encodedIndex + 1 >= maxDestLen) {
return RETURN_FAILED;
} else {
destStream[encodedIndex] = DLE;
++encodedIndex;
destStream[encodedIndex] = nextByte + 0x40;
}
} else if (nextByte == DLE) {
if (encodedIndex + 1 >= maxDestLen) {
return RETURN_FAILED;
} else {
destStream[encodedIndex] = DLE;
++encodedIndex;
destStream[encodedIndex] = DLE;
}
} else {
destStream[encodedIndex] = nextByte;
}
++encodedIndex;
++sourceIndex;
}
if ((sourceIndex == sourceLen) && (encodedIndex < maxDestLen)) {
if (addStxEtx) {
destStream[encodedIndex] = ETX;
++encodedIndex;
}
*encodedLen = encodedIndex;
return RETURN_OK;
} else {
return RETURN_FAILED;
}
}

View File

@ -1,25 +1,79 @@
#ifndef DLEENCODER_H_ #ifndef FRAMEWORK_GLOBALFUNCTIONS_DLEENCODER_H_
#define DLEENCODER_H_ #define FRAMEWORK_GLOBALFUNCTIONS_DLEENCODER_H_
#include "../returnvalues/HasReturnvaluesIF.h" #include "../returnvalues/HasReturnvaluesIF.h"
#include <cstddef>
/**
* @brief This DLE Encoder (Data Link Encoder) can be used to encode and
* decode arbitrary data with ASCII control characters
* @details
* List of control codes:
* https://en.wikipedia.org/wiki/C0_and_C1_control_codes
*
* This encoder can be used to achieve a basic transport layer when using
* char based transmission systems.
* The passed source strean is converted into a encoded stream by adding
* a STX marker at the start of the stream and an ETX marker at the end of
* the stream. Any STX, ETX, DLE and CR occurrences in the source stream are
* escaped by a DLE character. The encoder also replaces escaped control chars
* by another char, so STX, ETX and CR should not appear anywhere in the actual
* encoded data stream.
*
* When using a strictly char based reception of packets encoded with DLE,
* STX can be used to notify a reader that actual data will start to arrive
* while ETX can be used to notify the reader that the data has ended.
*/
class DleEncoder: public HasReturnvaluesIF { class DleEncoder: public HasReturnvaluesIF {
private: private:
DleEncoder(); DleEncoder();
virtual ~DleEncoder(); virtual ~DleEncoder();
public: public:
static const uint8_t STX = 0x02; static constexpr uint8_t INTERFACE_ID = CLASS_ID::DLE_ENCODER;
static const uint8_t ETX = 0x03; static constexpr ReturnValue_t STREAM_TOO_SHORT = MAKE_RETURN_CODE(0x01);
static const uint8_t DLE = 0x10; static constexpr ReturnValue_t DECODING_ERROR = MAKE_RETURN_CODE(0x02);
static ReturnValue_t decode(const uint8_t *sourceStream, //! Start Of Text character. First character is encoded stream
uint32_t sourceStreamLen, uint32_t *readLen, uint8_t *destStream, static constexpr uint8_t STX_CHAR = 0x02;
uint32_t maxDestStreamlen, uint32_t *decodedLen); //! End Of Text character. Last character in encoded stream
static constexpr uint8_t ETX_CHAR = 0x03;
//! Data Link Escape character. Used to escape STX, ETX and DLE occurrences
//! in the source stream.
static constexpr uint8_t DLE_CHAR = 0x10;
static constexpr uint8_t CARRIAGE_RETURN = 0x0D;
static ReturnValue_t encode(const uint8_t *sourceStream, uint32_t sourceLen, /**
uint8_t *destStream, uint32_t maxDestLen, uint32_t *encodedLen, * Encodes the give data stream by preceding it with the STX marker
* and ending it with an ETX marker. STX, ETX and DLE characters inside
* the stream are escaped by DLE characters and also replaced by adding
* 0x40 (which is reverted in the decoding process).
* @param sourceStream
* @param sourceLen
* @param destStream
* @param maxDestLen
* @param encodedLen
* @param addStxEtx
* Adding STX and ETX can be omitted, if they are added manually.
* @return
*/
static ReturnValue_t encode(const uint8_t *sourceStream, size_t sourceLen,
uint8_t *destStream, size_t maxDestLen, size_t *encodedLen,
bool addStxEtx = true); bool addStxEtx = true);
/**
* Converts an encoded stream back.
* @param sourceStream
* @param sourceStreamLen
* @param readLen
* @param destStream
* @param maxDestStreamlen
* @param decodedLen
* @return
*/
static ReturnValue_t decode(const uint8_t *sourceStream,
size_t sourceStreamLen, size_t *readLen, uint8_t *destStream,
size_t maxDestStreamlen, size_t *decodedLen);
}; };
#endif /* DLEENCODER_H_ */ #endif /* FRAMEWORK_GLOBALFUNCTIONS_DLEENCODER_H_ */

View File

@ -0,0 +1,34 @@
#include "PeriodicOperationDivider.h"
PeriodicOperationDivider::PeriodicOperationDivider(uint32_t divider,
bool resetAutomatically): resetAutomatically(resetAutomatically),
counter(divider), divider(divider) {
}
bool PeriodicOperationDivider::checkAndIncrement() {
if(counter >= divider) {
if(resetAutomatically) {
counter = 0;
}
return true;
}
counter ++;
return false;
}
void PeriodicOperationDivider::resetCounter() {
counter = 0;
}
void PeriodicOperationDivider::setDivider(uint32_t newDivider) {
divider = newDivider;
}
uint32_t PeriodicOperationDivider::getCounter() const {
return counter;
}
uint32_t PeriodicOperationDivider::getDivider() const {
return divider;
}

View File

@ -0,0 +1,55 @@
#ifndef FSFW_GLOBALFUNCTIONS_PERIODICOPERATIONDIVIDER_H_
#define FSFW_GLOBALFUNCTIONS_PERIODICOPERATIONDIVIDER_H_
#include <cstdint>
/**
* @brief Lightweight helper class to facilitate periodic operation with
* decreased frequencies.
* @details
* This class is useful to perform operations which have to be performed
* with a reduced frequency, like debugging printouts in high periodic tasks
* or low priority operations.
*/
class PeriodicOperationDivider {
public:
/**
* Initialize with the desired divider and specify whether the internal
* counter will be reset automatically.
* @param divider
* @param resetAutomatically
*/
PeriodicOperationDivider(uint32_t divider, bool resetAutomatically = true);
/**
* Check whether operation is necessary.
* If an operation is necessary and the class has been
* configured to be reset automatically, the counter will be reset.
* If not, the counter will be incremented.
* @return
* -@c true if the counter is larger or equal to the divider
* -@c false otherwise
*/
bool checkAndIncrement();
/**
* Can be used to reset the counter to 0 manually.
*/
void resetCounter();
uint32_t getCounter() const;
/**
* Can be used to set a new divider value.
* @param newDivider
*/
void setDivider(uint32_t newDivider);
uint32_t getDivider() const;
private:
bool resetAutomatically = true;
uint32_t counter = 0;
uint32_t divider = 0;
};
#endif /* FSFW_GLOBALFUNCTIONS_PERIODICOPERATIONDIVIDER_H_ */

View File

@ -90,3 +90,10 @@ double timevalOperations::toDouble(const timeval timeval) {
double result = timeval.tv_sec * 1000000. + timeval.tv_usec; double result = timeval.tv_sec * 1000000. + timeval.tv_usec;
return result / 1000000.; return result / 1000000.;
} }
timeval timevalOperations::toTimeval(const double seconds) {
timeval tval;
tval.tv_sec = seconds;
tval.tv_usec = seconds *(double) 1e6 - (tval.tv_sec *1e6);
return tval;
}

View File

@ -41,6 +41,7 @@ namespace timevalOperations {
* @return seconds * @return seconds
*/ */
double toDouble(const timeval timeval); double toDouble(const timeval timeval);
timeval toTimeval(const double seconds);
} }
#endif /* TIMEVALOPERATIONS_H_ */ #endif /* TIMEVALOPERATIONS_H_ */

View File

@ -1,9 +1,8 @@
#include "HealthHelper.h" #include "HealthHelper.h"
#include "../ipc/MessageQueueSenderIF.h"
#include "../serviceinterface/ServiceInterfaceStream.h" #include "../serviceinterface/ServiceInterfaceStream.h"
HealthHelper::HealthHelper(HasHealthIF* owner, object_id_t objectId) : HealthHelper::HealthHelper(HasHealthIF* owner, object_id_t objectId) :
healthTable(NULL), eventSender(NULL), objectId(objectId), parentQueue( objectId(objectId), owner(owner) {
0), owner(owner) {
} }
HealthHelper::~HealthHelper() { HealthHelper::~HealthHelper() {
@ -40,9 +39,19 @@ void HealthHelper::setParentQueue(MessageQueueId_t parentQueue) {
ReturnValue_t HealthHelper::initialize() { ReturnValue_t HealthHelper::initialize() {
healthTable = objectManager->get<HealthTableIF>(objects::HEALTH_TABLE); healthTable = objectManager->get<HealthTableIF>(objects::HEALTH_TABLE);
eventSender = objectManager->get<EventReportingProxyIF>(objectId); eventSender = objectManager->get<EventReportingProxyIF>(objectId);
if ((healthTable == NULL) || eventSender == NULL) {
return HasReturnvaluesIF::RETURN_FAILED; if (healthTable == nullptr) {
sif::error << "HealthHelper::initialize: Health table object needs"
"to be created in factory." << std::endl;
return ObjectManagerIF::CHILD_INIT_FAILED;
} }
if(eventSender == nullptr) {
sif::error << "HealthHelper::initialize: Owner has to implement "
"ReportingProxyIF." << std::endl;
return ObjectManagerIF::CHILD_INIT_FAILED;
}
ReturnValue_t result = healthTable->registerObject(objectId, ReturnValue_t result = healthTable->registerObject(objectId,
HasHealthIF::HEALTHY); HasHealthIF::HEALTHY);
if (result != HasReturnvaluesIF::RETURN_OK) { if (result != HasReturnvaluesIF::RETURN_OK) {
@ -62,22 +71,22 @@ void HealthHelper::setHealth(HasHealthIF::HealthState health) {
void HealthHelper::informParent(HasHealthIF::HealthState health, void HealthHelper::informParent(HasHealthIF::HealthState health,
HasHealthIF::HealthState oldHealth) { HasHealthIF::HealthState oldHealth) {
if (parentQueue == 0) { if (parentQueue == MessageQueueIF::NO_QUEUE) {
return; return;
} }
CommandMessage message; CommandMessage information;
HealthMessage::setHealthMessage(&message, HealthMessage::HEALTH_INFO, HealthMessage::setHealthMessage(&information, HealthMessage::HEALTH_INFO,
health, oldHealth); health, oldHealth);
if (MessageQueueSenderIF::sendMessage(parentQueue, &message, if (MessageQueueSenderIF::sendMessage(parentQueue, &information,
owner->getCommandQueue()) != HasReturnvaluesIF::RETURN_OK) { owner->getCommandQueue()) != HasReturnvaluesIF::RETURN_OK) {
sif::debug << "HealthHelper::informParent: sending health reply failed." sif::debug << "HealthHelper::informParent: sending health reply failed."
<< std::endl; << std::endl;
} }
} }
void HealthHelper::handleSetHealthCommand(CommandMessage* message) { void HealthHelper::handleSetHealthCommand(CommandMessage* command) {
ReturnValue_t result = owner->setHealth(HealthMessage::getHealth(message)); ReturnValue_t result = owner->setHealth(HealthMessage::getHealth(command));
if (message->getSender() == 0) { if (command->getSender() == MessageQueueIF::NO_QUEUE) {
return; return;
} }
CommandMessage reply; CommandMessage reply;
@ -85,12 +94,12 @@ void HealthHelper::handleSetHealthCommand(CommandMessage* message) {
HealthMessage::setHealthMessage(&reply, HealthMessage::setHealthMessage(&reply,
HealthMessage::REPLY_HEALTH_SET); HealthMessage::REPLY_HEALTH_SET);
} else { } else {
reply.setReplyRejected(result, message->getCommand()); reply.setReplyRejected(result, command->getCommand());
} }
if (MessageQueueSenderIF::sendMessage(message->getSender(), &reply, if (MessageQueueSenderIF::sendMessage(command->getSender(), &reply,
owner->getCommandQueue()) != HasReturnvaluesIF::RETURN_OK) { owner->getCommandQueue()) != HasReturnvaluesIF::RETURN_OK) {
sif::debug sif::debug << "HealthHelper::handleHealthCommand: sending health "
<< "HealthHelper::handleHealthCommand: sending health reply failed." "reply failed." << std::endl;
<< std::endl;
} }
} }

View File

@ -1,11 +1,13 @@
#ifndef HEALTHHELPER_H_ #ifndef FSFW_HEALTH_HEALTHHELPER_H_
#define HEALTHHELPER_H_ #define FSFW_HEALTH_HEALTHHELPER_H_
#include "../events/EventManagerIF.h"
#include "../events/EventReportingProxyIF.h"
#include "HasHealthIF.h" #include "HasHealthIF.h"
#include "HealthMessage.h" #include "HealthMessage.h"
#include "HealthTableIF.h" #include "HealthTableIF.h"
#include "../events/EventManagerIF.h"
#include "../events/EventReportingProxyIF.h"
#include "../ipc/MessageQueueIF.h"
#include "../objectmanager/ObjectManagerIF.h" #include "../objectmanager/ObjectManagerIF.h"
#include "../returnvalues/HasReturnvaluesIF.h" #include "../returnvalues/HasReturnvaluesIF.h"
@ -27,8 +29,8 @@ public:
/** /**
* ctor * ctor
* *
* @param owner
* @param objectId the object Id to use when communication with the HealthTable * @param objectId the object Id to use when communication with the HealthTable
* @param useAsFrom id to use as from id when sending replies, can be set to 0
*/ */
HealthHelper(HasHealthIF* owner, object_id_t objectId); HealthHelper(HasHealthIF* owner, object_id_t objectId);
@ -39,12 +41,12 @@ public:
* *
* only valid after initialize() has been called * only valid after initialize() has been called
*/ */
HealthTableIF *healthTable; HealthTableIF *healthTable = nullptr;
/** /**
* Proxy to forward events. * Proxy to forward events.
*/ */
EventReportingProxyIF* eventSender; EventReportingProxyIF* eventSender = nullptr;
/** /**
* Try to handle the message. * Try to handle the message.
@ -100,7 +102,7 @@ private:
/** /**
* The Queue of the parent * The Queue of the parent
*/ */
MessageQueueId_t parentQueue; MessageQueueId_t parentQueue = MessageQueueIF::NO_QUEUE;
/** /**
* The one using the healthHelper. * The one using the healthHelper.
@ -117,4 +119,4 @@ private:
void handleSetHealthCommand(CommandMessage *message); void handleSetHealthCommand(CommandMessage *message);
}; };
#endif /* HEALTHHELPER_H_ */ #endif /* FSFW_HEALTH_HEALTHHELPER_H_ */

View File

@ -100,7 +100,6 @@ void ObjectManager::initialize() {
} }
void ObjectManager::printList() { void ObjectManager::printList() {
std::map<object_id_t, SystemObjectIF*>::iterator it;
sif::debug << "ObjectManager: Object List contains:" << std::endl; sif::debug << "ObjectManager: Object List contains:" << std::endl;
for (auto const& it : objectList) { for (auto const& it : objectList) {
sif::debug << std::hex << it.first << " | " << it.second << std::endl; sif::debug << std::hex << it.first << " | " << it.second << std::endl;

View File

@ -64,6 +64,11 @@ ReturnValue_t PeriodicTask::sleepFor(uint32_t ms) {
void PeriodicTask::taskFunctionality() { void PeriodicTask::taskFunctionality() {
TickType_t xLastWakeTime; TickType_t xLastWakeTime;
const TickType_t xPeriod = pdMS_TO_TICKS(this->period * 1000.); const TickType_t xPeriod = pdMS_TO_TICKS(this->period * 1000.);
for (auto const &object: objectList) {
object->initializeAfterTaskCreation();
}
/* 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

View File

@ -1,11 +1,10 @@
#ifndef FRAMEWORK_OSAL_FREERTOS_PERIODICTASK_H_ #ifndef FSFW_OSAL_FREERTOS_PERIODICTASK_H_
#define FRAMEWORK_OSAL_FREERTOS_PERIODICTASK_H_ #define FSFW_OSAL_FREERTOS_PERIODICTASK_H_
#include "FreeRTOSTaskIF.h"
#include "../../objectmanager/ObjectManagerIF.h" #include "../../objectmanager/ObjectManagerIF.h"
#include "../../tasks/PeriodicTaskIF.h" #include "../../tasks/PeriodicTaskIF.h"
#include "../../tasks/Typedef.h" #include "../../tasks/Typedef.h"
#include "FreeRTOSTaskIF.h"
#include <freertos/FreeRTOS.h> #include <freertos/FreeRTOS.h>
#include <freertos/task.h> #include <freertos/task.h>
@ -24,7 +23,6 @@ public:
/** /**
* Keep in Mind that you need to call before this vTaskStartScheduler()! * Keep in Mind that you need to call before this vTaskStartScheduler()!
* A lot of task parameters are set in "FreeRTOSConfig.h". * A lot of task parameters are set in "FreeRTOSConfig.h".
* TODO: why does this need to be called before vTaskStartScheduler?
* @details * @details
* The class is initialized without allocated objects. * The class is initialized without allocated objects.
* These need to be added with #addComponent. * These need to be added with #addComponent.
@ -125,4 +123,4 @@ protected:
void handleMissedDeadline(); void handleMissedDeadline();
}; };
#endif /* PERIODICTASK_H_ */ #endif /* FSFW_OSAL_FREERTOS_PERIODICTASK_H_ */

227
osal/host/Clock.cpp Normal file
View File

@ -0,0 +1,227 @@
#include "../../serviceinterface/ServiceInterfaceStream.h"
#include "../../timemanager/Clock.h"
#include <chrono>
#if defined(WIN32)
#include <windows.h>
#elif defined(LINUX)
#include <fstream>
#endif
uint16_t Clock::leapSeconds = 0;
MutexIF* Clock::timeMutex = NULL;
using SystemClock = std::chrono::system_clock;
uint32_t Clock::getTicksPerSecond(void){
sif::warning << "Clock::getTicksPerSecond: not implemented yet" << std::endl;
return 0;
//return CLOCKS_PER_SEC;
//uint32_t ticks = sysconf(_SC_CLK_TCK);
//return ticks;
}
ReturnValue_t Clock::setClock(const TimeOfDay_t* time) {
// do some magic with chrono
sif::warning << "Clock::setClock: not implemented yet" << std::endl;
return HasReturnvaluesIF::RETURN_OK;
}
ReturnValue_t Clock::setClock(const timeval* time) {
// do some magic with chrono
#if defined(WIN32)
return HasReturnvaluesIF::RETURN_OK;
#elif defined(LINUX)
return HasReturnvaluesIF::RETURN_OK;
#else
#endif
sif::warning << "Clock::getUptime: Not implemented for found OS" << std::endl;
return HasReturnvaluesIF::RETURN_FAILED;
}
ReturnValue_t Clock::getClock_timeval(timeval* time) {
#if defined(WIN32)
auto now = std::chrono::system_clock::now();
auto secondsChrono = std::chrono::time_point_cast<std::chrono::seconds>(now);
auto epoch = now.time_since_epoch();
time->tv_sec = std::chrono::duration_cast<std::chrono::seconds>(epoch).count();
auto fraction = now - secondsChrono;
time->tv_usec = std::chrono::duration_cast<std::chrono::microseconds>(
fraction).count();
return HasReturnvaluesIF::RETURN_OK;
#elif defined(LINUX)
timespec timeUnix;
int status = clock_gettime(CLOCK_REALTIME,&timeUnix);
if(status!=0){
return HasReturnvaluesIF::RETURN_FAILED;
}
time->tv_sec = timeUnix.tv_sec;
time->tv_usec = timeUnix.tv_nsec / 1000.0;
return HasReturnvaluesIF::RETURN_OK;
#else
sif::warning << "Clock::getUptime: Not implemented for found OS" << std::endl;
return HasReturnvaluesIF::RETURN_FAILED;
#endif
}
ReturnValue_t Clock::getClock_usecs(uint64_t* time) {
// do some magic with chrono
sif::warning << "Clock::gerClock_usecs: not implemented yet" << std::endl;
return HasReturnvaluesIF::RETURN_OK;
}
timeval Clock::getUptime() {
timeval timeval;
#if defined(WIN32)
auto uptime = std::chrono::milliseconds(GetTickCount64());
auto secondsChrono = std::chrono::duration_cast<std::chrono::seconds>(uptime);
timeval.tv_sec = secondsChrono.count();
auto fraction = uptime - secondsChrono;
timeval.tv_usec = std::chrono::duration_cast<std::chrono::microseconds>(
fraction).count();
#elif defined(LINUX)
double uptimeSeconds;
if (std::ifstream("/proc/uptime", std::ios::in) >> uptimeSeconds)
{
// value is rounded down automatically
timeval.tv_sec = uptimeSeconds;
timeval.tv_usec = uptimeSeconds *(double) 1e6 - (timeval.tv_sec *1e6);
}
#else
sif::warning << "Clock::getUptime: Not implemented for found OS" << std::endl;
#endif
return timeval;
}
ReturnValue_t Clock::getUptime(timeval* uptime) {
*uptime = getUptime();
return HasReturnvaluesIF::RETURN_OK;
}
ReturnValue_t Clock::getUptime(uint32_t* uptimeMs) {
timeval uptime = getUptime();
*uptimeMs = uptime.tv_sec * 1000 + uptime.tv_usec / 1000;
return HasReturnvaluesIF::RETURN_OK;
}
ReturnValue_t Clock::getDateAndTime(TimeOfDay_t* time) {
// do some magic with chrono (C++20!)
// Right now, the library doesn't have the new features yet.
// so we work around that for now.
auto now = SystemClock::now();
auto seconds = std::chrono::time_point_cast<std::chrono::seconds>(now);
auto fraction = now - seconds;
time_t tt = SystemClock::to_time_t(now);
struct tm* timeInfo;
timeInfo = gmtime(&tt);
time->year = timeInfo->tm_year + 1900;
time->month = timeInfo->tm_mon+1;
time->day = timeInfo->tm_mday;
time->hour = timeInfo->tm_hour;
time->minute = timeInfo->tm_min;
time->second = timeInfo->tm_sec;
auto usecond = std::chrono::duration_cast<std::chrono::microseconds>(fraction);
time->usecond = usecond.count();
//sif::warning << "Clock::getDateAndTime: not implemented yet" << std::endl;
return HasReturnvaluesIF::RETURN_OK;
}
ReturnValue_t Clock::convertTimeOfDayToTimeval(const TimeOfDay_t* from,
timeval* to) {
struct tm time_tm;
time_tm.tm_year = from->year - 1900;
time_tm.tm_mon = from->month - 1;
time_tm.tm_mday = from->day;
time_tm.tm_hour = from->hour;
time_tm.tm_min = from->minute;
time_tm.tm_sec = from->second;
time_t seconds = mktime(&time_tm);
to->tv_sec = seconds;
to->tv_usec = from->usecond;
//Fails in 2038..
return HasReturnvaluesIF::RETURN_OK;
sif::warning << "Clock::convertTimeBla: not implemented yet" << std::endl;
return HasReturnvaluesIF::RETURN_OK;
}
ReturnValue_t Clock::convertTimevalToJD2000(timeval time, double* JD2000) {
*JD2000 = (time.tv_sec - 946728000. + time.tv_usec / 1000000.) / 24.
/ 3600.;
return HasReturnvaluesIF::RETURN_OK;
}
ReturnValue_t Clock::convertUTCToTT(timeval utc, timeval* tt) {
//SHOULDDO: works not for dates in the past (might have less leap seconds)
if (timeMutex == NULL) {
return HasReturnvaluesIF::RETURN_FAILED;
}
uint16_t leapSeconds;
ReturnValue_t result = getLeapSeconds(&leapSeconds);
if (result != HasReturnvaluesIF::RETURN_OK) {
return result;
}
timeval leapSeconds_timeval = { 0, 0 };
leapSeconds_timeval.tv_sec = leapSeconds;
//initial offset between UTC and TAI
timeval UTCtoTAI1972 = { 10, 0 };
timeval TAItoTT = { 32, 184000 };
*tt = utc + leapSeconds_timeval + UTCtoTAI1972 + TAItoTT;
return HasReturnvaluesIF::RETURN_OK;
}
ReturnValue_t Clock::setLeapSeconds(const uint16_t leapSeconds_) {
if(checkOrCreateClockMutex()!=HasReturnvaluesIF::RETURN_OK){
return HasReturnvaluesIF::RETURN_FAILED;
}
ReturnValue_t result = timeMutex->lockMutex(MutexIF::BLOCKING);
if (result != HasReturnvaluesIF::RETURN_OK) {
return result;
}
leapSeconds = leapSeconds_;
result = timeMutex->unlockMutex();
return result;
}
ReturnValue_t Clock::getLeapSeconds(uint16_t* leapSeconds_) {
if(timeMutex == nullptr){
return HasReturnvaluesIF::RETURN_FAILED;
}
ReturnValue_t result = timeMutex->lockMutex(MutexIF::BLOCKING);
if (result != HasReturnvaluesIF::RETURN_OK) {
return result;
}
*leapSeconds_ = leapSeconds;
result = timeMutex->unlockMutex();
return result;
}
ReturnValue_t Clock::checkOrCreateClockMutex(){
if(timeMutex == nullptr){
MutexFactory* mutexFactory = MutexFactory::instance();
if (mutexFactory == nullptr) {
return HasReturnvaluesIF::RETURN_FAILED;
}
timeMutex = mutexFactory->createMutex();
if (timeMutex == nullptr) {
return HasReturnvaluesIF::RETURN_FAILED;
}
}
return HasReturnvaluesIF::RETURN_OK;
}

View File

@ -0,0 +1,197 @@
#include "../../osal/host/FixedTimeslotTask.h"
#include "../../ipc/MutexFactory.h"
#include "../../osal/host/Mutex.h"
#include "../../osal/host/FixedTimeslotTask.h"
#include "../../serviceinterface/ServiceInterfaceStream.h"
#include "../../tasks/ExecutableObjectIF.h"
#include <thread>
#include <chrono>
#if defined(WIN32)
#include <windows.h>
#elif defined(LINUX)
#include <pthread.h>
#endif
FixedTimeslotTask::FixedTimeslotTask(const char *name, TaskPriority setPriority,
TaskStackSize setStack, TaskPeriod setPeriod,
void (*setDeadlineMissedFunc)()) :
started(false), pollingSeqTable(setPeriod*1000), taskName(name),
period(setPeriod), deadlineMissedFunc(setDeadlineMissedFunc) {
// It is propably possible to set task priorities by using the native
// task handles for Windows / Linux
mainThread = std::thread(&FixedTimeslotTask::taskEntryPoint, this, this);
#if defined(WIN32)
/* List of possible priority classes:
* https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/
* nf-processthreadsapi-setpriorityclass
* And respective thread priority numbers:
* https://docs.microsoft.com/en-us/windows/
* win32/procthread/scheduling-priorities */
int result = SetPriorityClass(
reinterpret_cast<HANDLE>(mainThread.native_handle()),
ABOVE_NORMAL_PRIORITY_CLASS);
if(result != 0) {
sif::error << "FixedTimeslotTask: Windows SetPriorityClass failed with code "
<< GetLastError() << std::endl;
}
result = SetThreadPriority(
reinterpret_cast<HANDLE>(mainThread.native_handle()),
THREAD_PRIORITY_NORMAL);
if(result != 0) {
sif::error << "FixedTimeslotTask: Windows SetPriorityClass failed with code "
<< GetLastError() << std::endl;
}
#elif defined(LINUX)
// we can just copy and paste the code from linux here.
#endif
}
FixedTimeslotTask::~FixedTimeslotTask(void) {
//Do not delete objects, we were responsible for ptrs only.
terminateThread = true;
if(mainThread.joinable()) {
mainThread.join();
}
delete this;
}
void FixedTimeslotTask::taskEntryPoint(void* argument) {
FixedTimeslotTask *originalTask(reinterpret_cast<FixedTimeslotTask*>(argument));
if (not originalTask->started) {
// we have to suspend/block here until the task is started.
// if semaphores are implemented, use them here.
std::unique_lock<std::mutex> lock(initMutex);
initCondition.wait(lock);
}
this->taskFunctionality();
sif::debug << "FixedTimeslotTask::taskEntryPoint: "
"Returned from taskFunctionality." << std::endl;
}
ReturnValue_t FixedTimeslotTask::startTask() {
started = true;
// Notify task to start.
std::lock_guard<std::mutex> lock(initMutex);
initCondition.notify_one();
return HasReturnvaluesIF::RETURN_OK;
}
ReturnValue_t FixedTimeslotTask::sleepFor(uint32_t ms) {
std::this_thread::sleep_for(std::chrono::milliseconds(ms));
return HasReturnvaluesIF::RETURN_OK;
}
void FixedTimeslotTask::taskFunctionality() {
pollingSeqTable.intializeSequenceAfterTaskCreation();
// A local iterator for the Polling Sequence Table is created to
// find the start time for the first entry.
auto slotListIter = pollingSeqTable.current;
// Get start time for first entry.
chron_ms interval(slotListIter->pollingTimeMs);
auto currentStartTime {
std::chrono::duration_cast<chron_ms>(
std::chrono::system_clock::now().time_since_epoch())
};
if(interval.count() > 0) {
delayForInterval(&currentStartTime, interval);
}
/* Enter the loop that defines the task behavior. */
for (;;) {
if(terminateThread.load()) {
break;
}
//The component for this slot is executed and the next one is chosen.
this->pollingSeqTable.executeAndAdvance();
if (not pollingSeqTable.slotFollowsImmediately()) {
// we need to wait before executing the current slot
//this gives us the time to wait:
interval = chron_ms(this->pollingSeqTable.getIntervalToPreviousSlotMs());
delayForInterval(&currentStartTime, interval);
//TODO deadline missed check
}
}
}
ReturnValue_t FixedTimeslotTask::addSlot(object_id_t componentId,
uint32_t slotTimeMs, int8_t executionStep) {
ExecutableObjectIF* executableObject = objectManager->
get<ExecutableObjectIF>(componentId);
if (executableObject != nullptr) {
pollingSeqTable.addSlot(componentId, slotTimeMs, executionStep,
executableObject, this);
return HasReturnvaluesIF::RETURN_OK;
}
sif::error << "Component " << std::hex << componentId <<
" not found, not adding it to pst" << std::endl;
return HasReturnvaluesIF::RETURN_FAILED;
}
ReturnValue_t FixedTimeslotTask::checkSequence() const {
return pollingSeqTable.checkSequence();
}
uint32_t FixedTimeslotTask::getPeriodMs() const {
return period * 1000;
}
bool FixedTimeslotTask::delayForInterval(chron_ms * previousWakeTimeMs,
const chron_ms interval) {
bool shouldDelay = false;
//Get current wakeup time
auto currentStartTime =
std::chrono::duration_cast<chron_ms>(
std::chrono::system_clock::now().time_since_epoch());
/* Generate the tick time at which the task wants to wake. */
auto nextTimeToWake_ms = (*previousWakeTimeMs) + interval;
if (currentStartTime < *previousWakeTimeMs) {
/* The tick count has overflowed since this function was
lasted called. In this case the only time we should ever
actually delay is if the wake time has also overflowed,
and the wake time is greater than the tick time. When this
is the case it is as if neither time had overflowed. */
if ((nextTimeToWake_ms < *previousWakeTimeMs)
&& (nextTimeToWake_ms > currentStartTime)) {
shouldDelay = true;
}
} else {
/* The tick time has not overflowed. In this case we will
delay if either the wake time has overflowed, and/or the
tick time is less than the wake time. */
if ((nextTimeToWake_ms < *previousWakeTimeMs)
|| (nextTimeToWake_ms > currentStartTime)) {
shouldDelay = true;
}
}
/* Update the wake time ready for the next call. */
(*previousWakeTimeMs) = nextTimeToWake_ms;
if (shouldDelay) {
auto sleepTime = std::chrono::duration_cast<chron_ms>(
nextTimeToWake_ms - currentStartTime);
std::this_thread::sleep_for(sleepTime);
return true;
}
//We are shifting the time in case the deadline was missed like rtems
(*previousWakeTimeMs) = currentStartTime;
return false;
}

View File

@ -0,0 +1,130 @@
#ifndef FRAMEWORK_OSAL_HOST_FIXEDTIMESLOTTASK_H_
#define FRAMEWORK_OSAL_HOST_FIXEDTIMESLOTTASK_H_
#include "../../objectmanager/ObjectManagerIF.h"
#include "../../tasks/FixedSlotSequence.h"
#include "../../tasks/FixedTimeslotTaskIF.h"
#include "../../tasks/Typedef.h"
#include <vector>
#include <thread>
#include <condition_variable>
#include <atomic>
class ExecutableObjectIF;
/**
* @brief This class represents a task for periodic activities with multiple
* steps and strict timeslot requirements for these steps.
* @details
* @ingroup task_handling
*/
class FixedTimeslotTask: public FixedTimeslotTaskIF {
public:
/**
* @brief Standard constructor of the class.
* @details
* The class is initialized without allocated objects. These need to be
* added with #addComponent.
* @param priority
* @param stack_size
* @param setPeriod
* @param setDeadlineMissedFunc
* The function pointer to the deadline missed function that shall be
* assigned.
*/
FixedTimeslotTask(const char *name, TaskPriority setPriority,
TaskStackSize setStack, TaskPeriod setPeriod,
void (*setDeadlineMissedFunc)());
/**
* @brief Currently, the executed object's lifetime is not coupled with
* the task object's lifetime, so the destructor is empty.
*/
virtual ~FixedTimeslotTask(void);
/**
* @brief The method to start the task.
* @details The method starts the task with the respective system call.
* Entry point is the taskEntryPoint method described below.
* The address of the task object is passed as an argument
* to the system call.
*/
ReturnValue_t startTask(void);
/**
* Add timeslot to the polling sequence table.
* @param componentId
* @param slotTimeMs
* @param executionStep
* @return
*/
ReturnValue_t addSlot(object_id_t componentId,
uint32_t slotTimeMs, int8_t executionStep);
ReturnValue_t checkSequence() const override;
uint32_t getPeriodMs() const;
ReturnValue_t sleepFor(uint32_t ms);
protected:
using chron_ms = std::chrono::milliseconds;
bool started;
//!< Typedef for the List of objects.
typedef std::vector<ExecutableObjectIF*> ObjectList;
std::thread mainThread;
std::atomic<bool> terminateThread = false;
//! Polling sequence table which contains the object to execute
//! and information like the timeslots and the passed execution step.
FixedSlotSequence pollingSeqTable;
std::condition_variable initCondition;
std::mutex initMutex;
std::string taskName;
/**
* @brief The period of the task.
* @details
* The period determines the frequency of the task's execution.
* It is expressed in clock ticks.
*/
TaskPeriod period;
/**
* @brief The pointer to the deadline-missed function.
* @details
* This pointer stores the function that is executed if the task's deadline
* is missed. So, each may react individually on a timing failure.
* The pointer may be NULL, then nothing happens on missing the deadline.
* The deadline is equal to the next execution of the periodic task.
*/
void (*deadlineMissedFunc)(void);
/**
* @brief This is the function executed in the new task's context.
* @details
* It converts the argument back to the thread object type and copies the
* class instance to the task context.
* The taskFunctionality method is called afterwards.
* @param A pointer to the task object itself is passed as argument.
*/
void taskEntryPoint(void* argument);
/**
* @brief The function containing the actual functionality of the task.
* @details
* The method sets and starts the task's period, then enters a loop that is
* repeated as long as the isRunning attribute is true. Within the loop,
* all performOperation methods of the added objects are called. Afterwards
* the checkAndRestartPeriod system call blocks the task until the next
* period. On missing the deadline, the deadlineMissedFunction is executed.
*/
void taskFunctionality(void);
bool delayForInterval(chron_ms * previousWakeTimeMs,
const chron_ms interval);
};
#endif /* FRAMEWORK_OSAL_HOST_FIXEDTIMESLOTTASK_H_ */

159
osal/host/MessageQueue.cpp Normal file
View File

@ -0,0 +1,159 @@
#include "MessageQueue.h"
#include "QueueMapManager.h"
#include "../../serviceinterface/ServiceInterfaceStream.h"
#include "../../ipc/MutexFactory.h"
#include "../../ipc/MutexHelper.h"
MessageQueue::MessageQueue(size_t messageDepth, size_t maxMessageSize):
messageSize(maxMessageSize), messageDepth(messageDepth) {
queueLock = MutexFactory::instance()->createMutex();
auto result = QueueMapManager::instance()->addMessageQueue(this, &mqId);
if(result != HasReturnvaluesIF::RETURN_OK) {
sif::error << "MessageQueue::MessageQueue:"
<< " Could not be created" << std::endl;
}
}
MessageQueue::~MessageQueue() {
MutexFactory::instance()->deleteMutex(queueLock);
}
ReturnValue_t MessageQueue::sendMessage(MessageQueueId_t sendTo,
MessageQueueMessageIF* message, bool ignoreFault) {
return sendMessageFrom(sendTo, message, this->getId(), ignoreFault);
}
ReturnValue_t MessageQueue::sendToDefault(MessageQueueMessageIF* message) {
return sendToDefaultFrom(message, this->getId());
}
ReturnValue_t MessageQueue::sendToDefaultFrom(MessageQueueMessageIF* message,
MessageQueueId_t sentFrom, bool ignoreFault) {
return sendMessageFrom(defaultDestination,message,sentFrom,ignoreFault);
}
ReturnValue_t MessageQueue::reply(MessageQueueMessageIF* message) {
if (this->lastPartner != 0) {
return sendMessageFrom(this->lastPartner, message, this->getId());
} else {
return MessageQueueIF::NO_REPLY_PARTNER;
}
}
ReturnValue_t MessageQueue::sendMessageFrom(MessageQueueId_t sendTo,
MessageQueueMessageIF* message, MessageQueueId_t sentFrom,
bool ignoreFault) {
return sendMessageFromMessageQueue(sendTo, message, sentFrom,
ignoreFault);
}
ReturnValue_t MessageQueue::receiveMessage(MessageQueueMessageIF* message,
MessageQueueId_t* receivedFrom) {
ReturnValue_t status = this->receiveMessage(message);
if(status == HasReturnvaluesIF::RETURN_OK) {
*receivedFrom = this->lastPartner;
}
return status;
}
ReturnValue_t MessageQueue::receiveMessage(MessageQueueMessageIF* message) {
if(messageQueue.empty()) {
return MessageQueueIF::EMPTY;
}
// not sure this will work..
//*message = std::move(messageQueue.front());
MutexHelper mutexLock(queueLock, MutexIF::TimeoutType::WAITING, 20);
MessageQueueMessage* currentMessage = &messageQueue.front();
std::copy(currentMessage->getBuffer(),
currentMessage->getBuffer() + messageSize, message->getBuffer());
messageQueue.pop();
// The last partner is the first uint32_t field in the message
this->lastPartner = message->getSender();
return HasReturnvaluesIF::RETURN_OK;
}
MessageQueueId_t MessageQueue::getLastPartner() const {
return lastPartner;
}
ReturnValue_t MessageQueue::flush(uint32_t* count) {
*count = messageQueue.size();
// Clears the queue.
messageQueue = std::queue<MessageQueueMessage>();
return HasReturnvaluesIF::RETURN_OK;
}
MessageQueueId_t MessageQueue::getId() const {
return mqId;
}
void MessageQueue::setDefaultDestination(MessageQueueId_t defaultDestination) {
defaultDestinationSet = true;
this->defaultDestination = defaultDestination;
}
MessageQueueId_t MessageQueue::getDefaultDestination() const {
return defaultDestination;
}
bool MessageQueue::isDefaultDestinationSet() const {
return defaultDestinationSet;
}
// static core function to send messages.
ReturnValue_t MessageQueue::sendMessageFromMessageQueue(MessageQueueId_t sendTo,
MessageQueueMessageIF* message, MessageQueueId_t sentFrom,
bool ignoreFault) {
if(message->getMessageSize() > message->getMaximumMessageSize()) {
// Actually, this should never happen or an error will be emitted
// in MessageQueueMessage.
// But I will still return a failure here.
return HasReturnvaluesIF::RETURN_FAILED;
}
MessageQueue* targetQueue = dynamic_cast<MessageQueue*>(
QueueMapManager::instance()->getMessageQueue(sendTo));
if(targetQueue == nullptr) {
if(not ignoreFault) {
InternalErrorReporterIF* internalErrorReporter =
objectManager->get<InternalErrorReporterIF>(
objects::INTERNAL_ERROR_REPORTER);
if (internalErrorReporter != nullptr) {
internalErrorReporter->queueMessageNotSent();
}
}
// TODO: Better returnvalue
return HasReturnvaluesIF::RETURN_FAILED;
}
if(targetQueue->messageQueue.size() < targetQueue->messageDepth) {
MutexHelper mutexLock(targetQueue->queueLock,
MutexIF::TimeoutType::WAITING, 20);
// not ideal, works for now though.
MessageQueueMessage* mqmMessage =
dynamic_cast<MessageQueueMessage*>(message);
if(message != nullptr) {
targetQueue->messageQueue.push(*mqmMessage);
}
else {
sif::error << "MessageQueue::sendMessageFromMessageQueue: Message"
"is not MessageQueueMessage!" << std::endl;
}
}
else {
return MessageQueueIF::FULL;
}
message->setSender(sentFrom);
return HasReturnvaluesIF::RETURN_OK;
}
ReturnValue_t MessageQueue::lockQueue(MutexIF::TimeoutType timeoutType,
dur_millis_t lockTimeout) {
return queueLock->lockMutex(timeoutType, lockTimeout);
}
ReturnValue_t MessageQueue::unlockQueue() {
return queueLock->unlockMutex();
}

231
osal/host/MessageQueue.h Normal file
View File

@ -0,0 +1,231 @@
#ifndef FRAMEWORK_OSAL_HOST_MESSAGEQUEUE_H_
#define FRAMEWORK_OSAL_HOST_MESSAGEQUEUE_H_
#include "../../internalError/InternalErrorReporterIF.h"
#include "../../ipc/MessageQueueIF.h"
#include "../../ipc/MessageQueueMessage.h"
#include "../../ipc/MutexIF.h"
#include "../../timemanager/Clock.h"
#include <queue>
#include <memory>
/**
* @brief This class manages sending and receiving of
* message queue messages.
* @details
* Message queues are used to pass asynchronous messages between processes.
* They work like post boxes, where all incoming messages are stored in FIFO
* order. This class creates a new receiving queue and provides methods to fetch
* received messages. Being a child of MessageQueueSender, this class also
* provides methods to send a message to a user-defined or a default destination.
* In addition it also provides a reply method to answer to the queue it
* received its last message from.
*
* The MessageQueue should be used as "post box" for a single owning object.
* So all message queue communication is "n-to-one".
* For creating the queue, as well as sending and receiving messages, the class
* makes use of the operating system calls provided.
*
* Please keep in mind that FreeRTOS offers different calls for message queue
* operations if called from an ISR.
* For now, the system context needs to be switched manually.
* @ingroup osal
* @ingroup message_queue
*/
class MessageQueue : public MessageQueueIF {
friend class MessageQueueSenderIF;
public:
/**
* @brief The constructor initializes and configures the message queue.
* @details
* By making use of the according operating system call, a message queue is
* created and initialized. The message depth - the maximum number of
* messages to be buffered - may be set with the help of a parameter,
* whereas the message size is automatically set to the maximum message
* queue message size. The operating system sets the message queue id, or
* in case of failure, it is set to zero.
* @param message_depth
* The number of messages to be buffered before passing an error to the
* sender. Default is three.
* @param max_message_size
* With this parameter, the maximum message size can be adjusted.
* This should be left default.
*/
MessageQueue(size_t messageDepth = 3,
size_t maxMessageSize = MessageQueueMessage::MAX_MESSAGE_SIZE);
/** Copying message queues forbidden */
MessageQueue(const MessageQueue&) = delete;
MessageQueue& operator=(const MessageQueue&) = delete;
/**
* @brief The destructor deletes the formerly created message queue.
* @details This is accomplished by using the delete call provided
* by the operating system.
*/
virtual ~MessageQueue();
/**
* @brief This operation sends a message to the given destination.
* @details It directly uses the sendMessage call of the MessageQueueSender
* parent, but passes its queue id as "sentFrom" parameter.
* @param sendTo This parameter specifies the message queue id of the
* destination message queue.
* @param message A pointer to a previously created message, which is sent.
* @param ignoreFault If set to true, the internal software fault counter
* is not incremented if queue is full.
*/
ReturnValue_t sendMessage(MessageQueueId_t sendTo,
MessageQueueMessageIF* message, bool ignoreFault = false) override;
/**
* @brief This operation sends a message to the default destination.
* @details As in the sendMessage method, this function uses the
* sendToDefault call of the MessageQueueSender parent class and adds its
* queue id as "sentFrom" information.
* @param message A pointer to a previously created message, which is sent.
*/
ReturnValue_t sendToDefault(MessageQueueMessageIF* message) override;
/**
* @brief This operation sends a message to the last communication partner.
* @details This operation simplifies answering an incoming message by using
* the stored lastPartner information as destination. If there was no
* message received yet (i.e. lastPartner is zero), an error code is returned.
* @param message A pointer to a previously created message, which is sent.
*/
ReturnValue_t reply(MessageQueueMessageIF* message) override;
/**
* @brief With the sendMessage call, a queue message is sent to a
* receiving queue.
* @details
* This method takes the message provided, adds the sentFrom information and
* passes it on to the destination provided with an operating system call.
* The OS's return value is returned.
* @param sendTo This parameter specifies the message queue id to send
* the message to.
* @param message This is a pointer to a previously created message,
* which is sent.
* @param sentFrom The sentFrom information can be set to inject the
* sender's queue id into the message. This variable is set to zero by
* default.
* @param ignoreFault If set to true, the internal software fault counter
* is not incremented if queue is full.
*/
virtual ReturnValue_t sendMessageFrom( MessageQueueId_t sendTo,
MessageQueueMessageIF* message, MessageQueueId_t sentFrom = NO_QUEUE,
bool ignoreFault = false) override;
/**
* @brief The sendToDefault method sends a queue message to the default
* destination.
* @details
* In all other aspects, it works identical to the sendMessage method.
* @param message This is a pointer to a previously created message,
* which is sent.
* @param sentFrom The sentFrom information can be set to inject the
* sender's queue id into the message. This variable is set to zero by
* default.
*/
virtual ReturnValue_t sendToDefaultFrom( MessageQueueMessageIF* message,
MessageQueueId_t sentFrom = NO_QUEUE,
bool ignoreFault = false) override;
/**
* @brief This function reads available messages from the message queue
* and returns the sender.
* @details
* It works identically to the other receiveMessage call, but in addition
* returns the sender's queue id.
* @param message A pointer to a message in which the received data is stored.
* @param receivedFrom A pointer to a queue id in which the sender's id is stored.
*/
ReturnValue_t receiveMessage(MessageQueueMessageIF* message,
MessageQueueId_t *receivedFrom) override;
/**
* @brief This function reads available messages from the message queue.
* @details
* If data is available it is stored in the passed message pointer.
* The message's original content is overwritten and the sendFrom
* information is stored in the lastPartner attribute. Else, the lastPartner
* information remains untouched, the message's content is cleared and the
* function returns immediately.
* @param message A pointer to a message in which the received data is stored.
*/
ReturnValue_t receiveMessage(MessageQueueMessageIF* message) override;
/**
* Deletes all pending messages in the queue.
* @param count The number of flushed messages.
* @return RETURN_OK on success.
*/
ReturnValue_t flush(uint32_t* count) override;
/**
* @brief This method returns the message queue id of the last
* communication partner.
*/
MessageQueueId_t getLastPartner() const override;
/**
* @brief This method returns the message queue id of this class's
* message queue.
*/
MessageQueueId_t getId() const override;
/**
* @brief This method is a simple setter for the default destination.
*/
void setDefaultDestination(MessageQueueId_t defaultDestination) override;
/**
* @brief This method is a simple getter for the default destination.
*/
MessageQueueId_t getDefaultDestination() const override;
bool isDefaultDestinationSet() const override;
ReturnValue_t lockQueue(MutexIF::TimeoutType timeoutType,
dur_millis_t lockTimeout);
ReturnValue_t unlockQueue();
protected:
/**
* @brief Implementation to be called from any send Call within
* MessageQueue and MessageQueueSenderIF.
* @details
* This method takes the message provided, adds the sentFrom information and
* passes it on to the destination provided with an operating system call.
* The OS's return value is returned.
* @param sendTo
* This parameter specifies the message queue id to send the message to.
* @param message
* This is a pointer to a previously created message, which is sent.
* @param sentFrom
* The sentFrom information can be set to inject the sender's queue id into
* the message. This variable is set to zero by default.
* @param ignoreFault
* If set to true, the internal software fault counter is not incremented
* if queue is full.
* @param context Specify whether call is made from task or from an ISR.
*/
static ReturnValue_t sendMessageFromMessageQueue(MessageQueueId_t sendTo,
MessageQueueMessageIF* message, MessageQueueId_t sentFrom = NO_QUEUE,
bool ignoreFault=false);
//static ReturnValue_t handleSendResult(BaseType_t result, bool ignoreFault);
private:
std::queue<MessageQueueMessage> messageQueue;
/**
* @brief The class stores the queue id it got assigned.
* If initialization fails, the queue id is set to zero.
*/
MessageQueueId_t mqId = 0;
size_t messageSize = 0;
size_t messageDepth = 0;
MutexIF* queueLock;
bool defaultDestinationSet = false;
MessageQueueId_t defaultDestination = 0;
MessageQueueId_t lastPartner = 0;
};
#endif /* FRAMEWORK_OSAL_HOST_MESSAGEQUEUE_H_ */

39
osal/host/Mutex.cpp Normal file
View File

@ -0,0 +1,39 @@
#include "Mutex.h"
#include "../../serviceinterface/ServiceInterfaceStream.h"
Mutex::Mutex() {}
ReturnValue_t Mutex::lockMutex(TimeoutType timeoutType, uint32_t timeoutMs) {
if(timeoutMs == MutexIF::BLOCKING) {
mutex.lock();
locked = true;
return HasReturnvaluesIF::RETURN_OK;
}
else if(timeoutMs == MutexIF::POLLING) {
if(mutex.try_lock()) {
locked = true;
return HasReturnvaluesIF::RETURN_OK;
}
}
else if(timeoutMs > MutexIF::POLLING){
auto chronoMs = std::chrono::milliseconds(timeoutMs);
if(mutex.try_lock_for(chronoMs)) {
locked = true;
return HasReturnvaluesIF::RETURN_OK;
}
}
return MutexIF::MUTEX_TIMEOUT;
}
ReturnValue_t Mutex::unlockMutex() {
if(not locked) {
return MutexIF::CURR_THREAD_DOES_NOT_OWN_MUTEX;
}
mutex.unlock();
locked = false;
return HasReturnvaluesIF::RETURN_OK;
}
std::timed_mutex* Mutex::getMutexHandle() {
return &mutex;
}

29
osal/host/Mutex.h Normal file
View File

@ -0,0 +1,29 @@
#ifndef FSFW_OSAL_HOSTED_MUTEX_H_
#define FSFW_OSAL_HOSTED_MUTEX_H_
#include "../../ipc/MutexIF.h"
#include <mutex>
/**
* @brief OS component to implement MUTual EXclusion
*
* @details
* Mutexes are binary semaphores which include a priority inheritance mechanism.
* Documentation: https://www.freertos.org/Real-time-embedded-RTOS-mutexes.html
* @ingroup osal
*/
class Mutex : public MutexIF {
public:
Mutex();
ReturnValue_t lockMutex(TimeoutType timeoutType =
TimeoutType::BLOCKING, uint32_t timeoutMs = 0) override;
ReturnValue_t unlockMutex() override;
std::timed_mutex* getMutexHandle();
private:
bool locked = false;
std::timed_mutex mutex;
};
#endif /* FSFW_OSAL_HOSTED_MUTEX_H_ */

View File

@ -0,0 +1,28 @@
#include "../../ipc/MutexFactory.h"
#include "../../osal/host/Mutex.h"
//TODO: Different variant than the lazy loading in QueueFactory.
//What's better and why? -> one is on heap the other on bss/data
//MutexFactory* MutexFactory::factoryInstance = new MutexFactory();
MutexFactory* MutexFactory::factoryInstance = nullptr;
MutexFactory::MutexFactory() {
}
MutexFactory::~MutexFactory() {
}
MutexFactory* MutexFactory::instance() {
if (factoryInstance == nullptr){
factoryInstance = new MutexFactory();
}
return MutexFactory::factoryInstance;
}
MutexIF* MutexFactory::createMutex() {
return new Mutex();
}
void MutexFactory::deleteMutex(MutexIF* mutex) {
delete mutex;
}

176
osal/host/PeriodicTask.cpp Normal file
View File

@ -0,0 +1,176 @@
#include "Mutex.h"
#include "PeriodicTask.h"
#include "../../ipc/MutexFactory.h"
#include "../../serviceinterface/ServiceInterfaceStream.h"
#include "../../tasks/ExecutableObjectIF.h"
#include <thread>
#include <chrono>
#if defined(WIN32)
#include <windows.h>
#elif defined(LINUX)
#include <pthread.h>
#endif
PeriodicTask::PeriodicTask(const char *name, TaskPriority setPriority,
TaskStackSize setStack, TaskPeriod setPeriod,
void (*setDeadlineMissedFunc)()) :
started(false), taskName(name), period(setPeriod),
deadlineMissedFunc(setDeadlineMissedFunc) {
// It is propably possible to set task priorities by using the native
// task handles for Windows / Linux
mainThread = std::thread(&PeriodicTask::taskEntryPoint, this, this);
#if defined(WIN32)
/* List of possible priority classes:
* https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/
* nf-processthreadsapi-setpriorityclass
* And respective thread priority numbers:
* https://docs.microsoft.com/en-us/windows/
* win32/procthread/scheduling-priorities */
int result = SetPriorityClass(
reinterpret_cast<HANDLE>(mainThread.native_handle()),
ABOVE_NORMAL_PRIORITY_CLASS);
if(result != 0) {
sif::error << "PeriodicTask: Windows SetPriorityClass failed with code "
<< GetLastError() << std::endl;
}
result = SetThreadPriority(
reinterpret_cast<HANDLE>(mainThread.native_handle()),
THREAD_PRIORITY_NORMAL);
if(result != 0) {
sif::error << "PeriodicTask: Windows SetPriorityClass failed with code "
<< GetLastError() << std::endl;
}
#elif defined(LINUX)
// we can just copy and paste the code from linux here.
#endif
}
PeriodicTask::~PeriodicTask(void) {
//Do not delete objects, we were responsible for ptrs only.
terminateThread = true;
if(mainThread.joinable()) {
mainThread.join();
}
delete this;
}
void PeriodicTask::taskEntryPoint(void* argument) {
PeriodicTask *originalTask(reinterpret_cast<PeriodicTask*>(argument));
if (not originalTask->started) {
// we have to suspend/block here until the task is started.
// if semaphores are implemented, use them here.
std::unique_lock<std::mutex> lock(initMutex);
initCondition.wait(lock);
}
this->taskFunctionality();
sif::debug << "PeriodicTask::taskEntryPoint: "
"Returned from taskFunctionality." << std::endl;
}
ReturnValue_t PeriodicTask::startTask() {
started = true;
// Notify task to start.
std::lock_guard<std::mutex> lock(initMutex);
initCondition.notify_one();
return HasReturnvaluesIF::RETURN_OK;
}
ReturnValue_t PeriodicTask::sleepFor(uint32_t ms) {
std::this_thread::sleep_for(std::chrono::milliseconds(ms));
return HasReturnvaluesIF::RETURN_OK;
}
void PeriodicTask::taskFunctionality() {
std::chrono::milliseconds periodChrono(static_cast<uint32_t>(period*1000));
auto currentStartTime {
std::chrono::duration_cast<std::chrono::milliseconds>(
std::chrono::system_clock::now().time_since_epoch())
};
auto nextStartTime{ currentStartTime };
/* Enter the loop that defines the task behavior. */
for (;;) {
if(terminateThread.load()) {
break;
}
for (ObjectList::iterator it = objectList.begin();
it != objectList.end(); ++it) {
(*it)->performOperation();
}
if(not delayForInterval(&currentStartTime, periodChrono)) {
sif::warning << "PeriodicTask: " << taskName <<
" missed deadline!\n" << std::flush;
if(deadlineMissedFunc != nullptr) {
this->deadlineMissedFunc();
}
}
}
}
ReturnValue_t PeriodicTask::addComponent(object_id_t object) {
ExecutableObjectIF* newObject = objectManager->get<ExecutableObjectIF>(
object);
if (newObject == nullptr) {
return HasReturnvaluesIF::RETURN_FAILED;
}
objectList.push_back(newObject);
return HasReturnvaluesIF::RETURN_OK;
}
uint32_t PeriodicTask::getPeriodMs() const {
return period * 1000;
}
bool PeriodicTask::delayForInterval(chron_ms* previousWakeTimeMs,
const chron_ms interval) {
bool shouldDelay = false;
//Get current wakeup time
auto currentStartTime =
std::chrono::duration_cast<std::chrono::milliseconds>(
std::chrono::system_clock::now().time_since_epoch());
/* Generate the tick time at which the task wants to wake. */
auto nextTimeToWake_ms = (*previousWakeTimeMs) + interval;
if (currentStartTime < *previousWakeTimeMs) {
/* The tick count has overflowed since this function was
lasted called. In this case the only time we should ever
actually delay is if the wake time has also overflowed,
and the wake time is greater than the tick time. When this
is the case it is as if neither time had overflowed. */
if ((nextTimeToWake_ms < *previousWakeTimeMs)
&& (nextTimeToWake_ms > currentStartTime)) {
shouldDelay = true;
}
} else {
/* The tick time has not overflowed. In this case we will
delay if either the wake time has overflowed, and/or the
tick time is less than the wake time. */
if ((nextTimeToWake_ms < *previousWakeTimeMs)
|| (nextTimeToWake_ms > currentStartTime)) {
shouldDelay = true;
}
}
/* Update the wake time ready for the next call. */
(*previousWakeTimeMs) = nextTimeToWake_ms;
if (shouldDelay) {
auto sleepTime = std::chrono::duration_cast<std::chrono::milliseconds>(
nextTimeToWake_ms - currentStartTime);
std::this_thread::sleep_for(sleepTime);
return true;
}
//We are shifting the time in case the deadline was missed like rtems
(*previousWakeTimeMs) = currentStartTime;
return false;
}

123
osal/host/PeriodicTask.h Normal file
View File

@ -0,0 +1,123 @@
#ifndef FRAMEWORK_OSAL_HOST_PERIODICTASK_H_
#define FRAMEWORK_OSAL_HOST_PERIODICTASK_H_
#include "../../objectmanager/ObjectManagerIF.h"
#include "../../tasks/PeriodicTaskIF.h"
#include "../../tasks/Typedef.h"
#include <vector>
#include <thread>
#include <condition_variable>
#include <atomic>
class ExecutableObjectIF;
/**
* @brief This class represents a specialized task for
* periodic activities of multiple objects.
* @details
*
* @ingroup task_handling
*/
class PeriodicTask: public PeriodicTaskIF {
public:
/**
* @brief Standard constructor of the class.
* @details
* The class is initialized without allocated objects. These need to be
* added with #addComponent.
* @param priority
* @param stack_size
* @param setPeriod
* @param setDeadlineMissedFunc
* The function pointer to the deadline missed function that shall be
* assigned.
*/
PeriodicTask(const char *name, TaskPriority setPriority, TaskStackSize setStack,
TaskPeriod setPeriod,void (*setDeadlineMissedFunc)());
/**
* @brief Currently, the executed object's lifetime is not coupled with
* the task object's lifetime, so the destructor is empty.
*/
virtual ~PeriodicTask(void);
/**
* @brief The method to start the task.
* @details The method starts the task with the respective system call.
* Entry point is the taskEntryPoint method described below.
* The address of the task object is passed as an argument
* to the system call.
*/
ReturnValue_t startTask(void);
/**
* Adds an object to the list of objects to be executed.
* The objects are executed in the order added.
* @param object Id of the object to add.
* @return
* -@c RETURN_OK on success
* -@c RETURN_FAILED if the object could not be added.
*/
ReturnValue_t addComponent(object_id_t object);
uint32_t getPeriodMs() const;
ReturnValue_t sleepFor(uint32_t ms);
protected:
using chron_ms = std::chrono::milliseconds;
bool started;
//!< Typedef for the List of objects.
typedef std::vector<ExecutableObjectIF*> ObjectList;
std::thread mainThread;
std::atomic<bool> terminateThread = false;
/**
* @brief This attribute holds a list of objects to be executed.
*/
ObjectList objectList;
std::condition_variable initCondition;
std::mutex initMutex;
std::string taskName;
/**
* @brief The period of the task.
* @details
* The period determines the frequency of the task's execution.
* It is expressed in clock ticks.
*/
TaskPeriod period;
/**
* @brief The pointer to the deadline-missed function.
* @details
* This pointer stores the function that is executed if the task's deadline
* is missed. So, each may react individually on a timing failure.
* The pointer may be NULL, then nothing happens on missing the deadline.
* The deadline is equal to the next execution of the periodic task.
*/
void (*deadlineMissedFunc)(void);
/**
* @brief This is the function executed in the new task's context.
* @details
* It converts the argument back to the thread object type and copies the
* class instance to the task context.
* The taskFunctionality method is called afterwards.
* @param A pointer to the task object itself is passed as argument.
*/
void taskEntryPoint(void* argument);
/**
* @brief The function containing the actual functionality of the task.
* @details
* The method sets and starts the task's period, then enters a loop that is
* repeated as long as the isRunning attribute is true. Within the loop,
* all performOperation methods of the added objects are called. Afterwards
* the checkAndRestartPeriod system call blocks the task until the next
* period. On missing the deadline, the deadlineMissedFunction is executed.
*/
void taskFunctionality(void);
bool delayForInterval(chron_ms * previousWakeTimeMs,
const chron_ms interval);
};
#endif /* PERIODICTASK_H_ */

View File

@ -0,0 +1,41 @@
#include "../../ipc/QueueFactory.h"
#include "../../osal/host/MessageQueue.h"
#include "../../serviceinterface/ServiceInterfaceStream.h"
#include <cstring>
QueueFactory* QueueFactory::factoryInstance = nullptr;
ReturnValue_t MessageQueueSenderIF::sendMessage(MessageQueueId_t sendTo,
MessageQueueMessageIF* message, MessageQueueId_t sentFrom,
bool ignoreFault) {
return MessageQueue::sendMessageFromMessageQueue(sendTo,message,
sentFrom,ignoreFault);
return HasReturnvaluesIF::RETURN_OK;
}
QueueFactory* QueueFactory::instance() {
if (factoryInstance == nullptr) {
factoryInstance = new QueueFactory;
}
return factoryInstance;
}
QueueFactory::QueueFactory() {
}
QueueFactory::~QueueFactory() {
}
MessageQueueIF* QueueFactory::createMessageQueue(uint32_t messageDepth,
size_t maxMessageSize) {
// A thread-safe queue can be implemented by using a combination
// of std::queue and std::mutex. This uses dynamic memory allocation
// which could be alleviated by using a custom allocator, external library
// (etl::queue) or simply using std::queue, we're on a host machine anyway.
return new MessageQueue(messageDepth, maxMessageSize);
}
void QueueFactory::deleteMessageQueue(MessageQueueIF* queue) {
delete queue;
}

View File

@ -0,0 +1,52 @@
#include "QueueMapManager.h"
#include "../../ipc/MutexFactory.h"
#include "../../ipc/MutexHelper.h"
QueueMapManager* QueueMapManager::mqManagerInstance = nullptr;
QueueMapManager::QueueMapManager() {
mapLock = MutexFactory::instance()->createMutex();
}
QueueMapManager* QueueMapManager::instance() {
if (mqManagerInstance == nullptr){
mqManagerInstance = new QueueMapManager();
}
return QueueMapManager::mqManagerInstance;
}
ReturnValue_t QueueMapManager::addMessageQueue(
MessageQueueIF* queueToInsert, MessageQueueId_t* id) {
// Not thread-safe, but it is assumed all message queues are created
// at software initialization now. If this is to be made thread-safe in
// the future, it propably would be sufficient to lock the increment
// operation here
uint32_t currentId = queueCounter++;
auto returnPair = queueMap.emplace(currentId, queueToInsert);
if(not returnPair.second) {
// this should never happen for the atomic variable.
sif::error << "QueueMapManager: This ID is already inside the map!"
<< std::endl;
return HasReturnvaluesIF::RETURN_FAILED;
}
if (id != nullptr) {
*id = currentId;
}
return HasReturnvaluesIF::RETURN_OK;
}
MessageQueueIF* QueueMapManager::getMessageQueue(
MessageQueueId_t messageQueueId) const {
MutexHelper(mapLock, MutexIF::TimeoutType::WAITING, 50);
auto queueIter = queueMap.find(messageQueueId);
if(queueIter != queueMap.end()) {
return queueIter->second;
}
else {
sif::warning << "QueueMapManager::getQueueHandle: The ID" <<
messageQueueId << " does not exists in the map" << std::endl;
return nullptr;
}
}

View File

@ -0,0 +1,47 @@
#ifndef FSFW_OSAL_HOST_QUEUEMAPMANAGER_H_
#define FSFW_OSAL_HOST_QUEUEMAPMANAGER_H_
#include "../../ipc/MessageQueueSenderIF.h"
#include "../../osal/host/MessageQueue.h"
#include <unordered_map>
#include <atomic>
using QueueMap = std::unordered_map<MessageQueueId_t, MessageQueueIF*>;
/**
* An internal map to map message queue IDs to message queues.
* This propably should be a singleton..
*/
class QueueMapManager {
public:
//! Returns the single instance of SemaphoreFactory.
static QueueMapManager* instance();
/**
* Insert a message queue into the map and returns a message queue ID
* @param queue The message queue to insert.
* @param id The passed value will be set unless a nullptr is passed
* @return
*/
ReturnValue_t addMessageQueue(MessageQueueIF* queue, MessageQueueId_t*
id = nullptr);
/**
* Get the message queue handle by providing a message queue ID.
* @param messageQueueId
* @return
*/
MessageQueueIF* getMessageQueue(MessageQueueId_t messageQueueId) const;
private:
//! External instantiation is forbidden.
QueueMapManager();
uint32_t queueCounter = 1;
MutexIF* mapLock;
QueueMap queueMap;
static QueueMapManager* mqManagerInstance;
};
#endif /* FSFW_OSAL_HOST_QUEUEMAPMANAGER_H_ */

View File

@ -0,0 +1,39 @@
#include "../../tasks/SemaphoreFactory.h"
#include "../../osal/linux/BinarySemaphore.h"
#include "../../osal/linux/CountingSemaphore.h"
#include "../../serviceinterface/ServiceInterfaceStream.h"
SemaphoreFactory* SemaphoreFactory::factoryInstance = nullptr;
SemaphoreFactory::SemaphoreFactory() {
}
SemaphoreFactory::~SemaphoreFactory() {
delete factoryInstance;
}
SemaphoreFactory* SemaphoreFactory::instance() {
if (factoryInstance == nullptr){
factoryInstance = new SemaphoreFactory();
}
return SemaphoreFactory::factoryInstance;
}
SemaphoreIF* SemaphoreFactory::createBinarySemaphore(uint32_t arguments) {
// Just gonna wait for full C++20 for now.
sif::error << "SemaphoreFactory: Binary Semaphore not implemented yet."
" Returning nullptr!\n" << std::flush;
return nullptr;
}
SemaphoreIF* SemaphoreFactory::createCountingSemaphore(const uint8_t maxCount,
uint8_t initCount, uint32_t arguments) {
// Just gonna wait for full C++20 for now.
sif::error << "SemaphoreFactory: Counting Semaphore not implemented yet."
" Returning nullptr!\n" << std::flush;
return nullptr;
}
void SemaphoreFactory::deleteSemaphore(SemaphoreIF* semaphore) {
delete semaphore;
}

51
osal/host/TaskFactory.cpp Normal file
View File

@ -0,0 +1,51 @@
#include "../../osal/host/FixedTimeslotTask.h"
#include "../../osal/host/PeriodicTask.h"
#include "../../tasks/TaskFactory.h"
#include "../../returnvalues/HasReturnvaluesIF.h"
#include "../../tasks/PeriodicTaskIF.h"
#include <chrono>
TaskFactory* TaskFactory::factoryInstance = new TaskFactory();
// Will propably not be used for hosted implementation
const size_t PeriodicTaskIF::MINIMUM_STACK_SIZE = 0;
TaskFactory::TaskFactory() {
}
TaskFactory::~TaskFactory() {
}
TaskFactory* TaskFactory::instance() {
return TaskFactory::factoryInstance;
}
PeriodicTaskIF* TaskFactory::createPeriodicTask(TaskName name_,
TaskPriority taskPriority_,TaskStackSize stackSize_,
TaskPeriod periodInSeconds_,
TaskDeadlineMissedFunction deadLineMissedFunction_) {
return new PeriodicTask(name_, taskPriority_, stackSize_, periodInSeconds_,
deadLineMissedFunction_);
}
FixedTimeslotTaskIF* TaskFactory::createFixedTimeslotTask(TaskName name_,
TaskPriority taskPriority_,TaskStackSize stackSize_,
TaskPeriod periodInSeconds_,
TaskDeadlineMissedFunction deadLineMissedFunction_) {
return new FixedTimeslotTask(name_, taskPriority_, stackSize_,
periodInSeconds_, deadLineMissedFunction_);
}
ReturnValue_t TaskFactory::deleteTask(PeriodicTaskIF* task) {
// This might block for some time!
delete task;
return HasReturnvaluesIF::RETURN_FAILED;
}
ReturnValue_t TaskFactory::delayTask(uint32_t delayMs){
std::this_thread::sleep_for(std::chrono::milliseconds(delayMs));
return HasReturnvaluesIF::RETURN_OK;
}

View File

@ -5,8 +5,8 @@
PeriodicPosixTask::PeriodicPosixTask(const char* name_, int priority_, PeriodicPosixTask::PeriodicPosixTask(const char* name_, int priority_,
size_t stackSize_, uint32_t period_, void(deadlineMissedFunc_)()): size_t stackSize_, uint32_t period_, void(deadlineMissedFunc_)()):
PosixThread(name_,priority_,stackSize_),objectList(),started(false), PosixThread(name_, priority_, stackSize_), objectList(), started(false),
periodMs(period_),deadlineMissedFunc(deadlineMissedFunc_) { periodMs(period_), deadlineMissedFunc(deadlineMissedFunc_) {
} }
PeriodicPosixTask::~PeriodicPosixTask() { PeriodicPosixTask::~PeriodicPosixTask() {
@ -25,6 +25,8 @@ ReturnValue_t PeriodicPosixTask::addComponent(object_id_t object) {
ExecutableObjectIF* newObject = objectManager->get<ExecutableObjectIF>( ExecutableObjectIF* newObject = objectManager->get<ExecutableObjectIF>(
object); object);
if (newObject == nullptr) { if (newObject == nullptr) {
sif::error << "PeriodicTask::addComponent: Invalid object. Make sure"
<< " it implements ExecutableObjectIF!" << std::endl;
return HasReturnvaluesIF::RETURN_FAILED; return HasReturnvaluesIF::RETURN_FAILED;
} }
objectList.push_back(newObject); objectList.push_back(newObject);
@ -38,35 +40,41 @@ ReturnValue_t PeriodicPosixTask::sleepFor(uint32_t ms) {
} }
ReturnValue_t PeriodicPosixTask::startTask(void){ ReturnValue_t PeriodicPosixTask::startTask(void) {
started = true; started = true;
//sif::info << stackSize << std::endl; //sif::info << stackSize << std::endl;
PosixThread::createTask(&taskEntryPoint,this); PosixThread::createTask(&taskEntryPoint,this);
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
} }
void PeriodicPosixTask::taskFunctionality(void){ void PeriodicPosixTask::taskFunctionality(void) {
if(!started){ if(not started) {
suspend(); suspend();
} }
for (auto const &object: objectList) {
object->initializeAfterTaskCreation();
}
uint64_t lastWakeTime = getCurrentMonotonicTimeMs(); uint64_t lastWakeTime = getCurrentMonotonicTimeMs();
//The task's "infinite" inner loop is entered. //The task's "infinite" inner loop is entered.
while (1) { while (1) {
for (ObjectList::iterator it = objectList.begin(); for (auto const &object: objectList) {
it != objectList.end(); ++it) { object->performOperation();
(*it)->performOperation();
} }
if(!PosixThread::delayUntil(&lastWakeTime,periodMs)){
if(not PosixThread::delayUntil(&lastWakeTime, periodMs)){
char name[20] = {0}; char name[20] = {0};
int status = pthread_getname_np(pthread_self(),name,sizeof(name)); int status = pthread_getname_np(pthread_self(), name, sizeof(name));
if(status==0){ if(status == 0) {
sif::error << "PeriodicPosixTask " << name << ": Deadline " sif::error << "PeriodicPosixTask " << name << ": Deadline "
"missed." << std::endl; "missed." << std::endl;
}else{ }
else {
sif::error << "PeriodicPosixTask X: Deadline missed. " << sif::error << "PeriodicPosixTask X: Deadline missed. " <<
status << std::endl; status << std::endl;
} }
if (this->deadlineMissedFunc != NULL) { if (this->deadlineMissedFunc != nullptr) {
this->deadlineMissedFunc(); this->deadlineMissedFunc();
} }
} }

View File

@ -32,7 +32,7 @@ public:
* The address of the task object is passed as an argument * The address of the task object is passed as an argument
* to the system call. * to the system call.
*/ */
ReturnValue_t startTask(void); ReturnValue_t startTask() override;
/** /**
* Adds an object to the list of objects to be executed. * Adds an object to the list of objects to be executed.
* The objects are executed in the order added. * The objects are executed in the order added.

View File

@ -0,0 +1,138 @@
#include "TcUnixUdpPollingTask.h"
#include "../../globalfunctions/arrayprinter.h"
TcUnixUdpPollingTask::TcUnixUdpPollingTask(object_id_t objectId,
object_id_t tmtcUnixUdpBridge, size_t frameSize,
double timeoutSeconds): SystemObject(objectId),
tmtcBridgeId(tmtcUnixUdpBridge) {
if(frameSize > 0) {
this->frameSize = frameSize;
}
else {
this->frameSize = DEFAULT_MAX_FRAME_SIZE;
}
// Set up reception buffer with specified frame size.
// For now, it is assumed that only one frame is held in the buffer!
receptionBuffer.reserve(this->frameSize);
receptionBuffer.resize(this->frameSize);
if(timeoutSeconds == -1) {
receptionTimeout = DEFAULT_TIMEOUT;
}
else {
receptionTimeout = timevalOperations::toTimeval(timeoutSeconds);
}
}
TcUnixUdpPollingTask::~TcUnixUdpPollingTask() {}
ReturnValue_t TcUnixUdpPollingTask::performOperation(uint8_t opCode) {
// Poll for new UDP datagrams in permanent loop.
while(1) {
//! Sender Address is cached here.
struct sockaddr_in senderAddress;
socklen_t senderSockLen = 0;
ssize_t bytesReceived = recvfrom(serverUdpSocket,
receptionBuffer.data(), frameSize, receptionFlags,
reinterpret_cast<sockaddr*>(&senderAddress), &senderSockLen);
if(bytesReceived < 0) {
// handle error
sif::error << "TcSocketPollingTask::performOperation: Reception"
"error." << std::endl;
handleReadError();
continue;
}
// sif::debug << "TcSocketPollingTask::performOperation: " << bytesReceived
// << " bytes received" << std::endl;
ReturnValue_t result = handleSuccessfullTcRead(bytesReceived);
if(result != HasReturnvaluesIF::RETURN_FAILED) {
}
tmtcBridge->registerCommConnect();
tmtcBridge->checkAndSetClientAddress(senderAddress);
}
return HasReturnvaluesIF::RETURN_OK;
}
ReturnValue_t TcUnixUdpPollingTask::handleSuccessfullTcRead(size_t bytesRead) {
store_address_t storeId;
ReturnValue_t result = tcStore->addData(&storeId,
receptionBuffer.data(), bytesRead);
// arrayprinter::print(receptionBuffer.data(), bytesRead);
if (result != HasReturnvaluesIF::RETURN_OK) {
sif::error << "TcSerialPollingTask::transferPusToSoftwareBus: Data "
"storage failed" << std::endl;
sif::error << "Packet size: " << bytesRead << std::endl;
return HasReturnvaluesIF::RETURN_FAILED;
}
TmTcMessage message(storeId);
result = MessageQueueSenderIF::sendMessage(targetTcDestination, &message);
if (result != HasReturnvaluesIF::RETURN_OK) {
sif::error << "Serial Polling: Sending message to queue failed"
<< std::endl;
tcStore->deleteData(storeId);
}
return result;
}
ReturnValue_t TcUnixUdpPollingTask::initialize() {
tcStore = objectManager->get<StorageManagerIF>(objects::TC_STORE);
if (tcStore == nullptr) {
sif::error << "TcSerialPollingTask::initialize: TC Store uninitialized!"
<< std::endl;
return ObjectManagerIF::CHILD_INIT_FAILED;
}
tmtcBridge = objectManager->get<TmTcUnixUdpBridge>(tmtcBridgeId);
if(tmtcBridge == nullptr) {
sif::error << "TcSocketPollingTask::TcSocketPollingTask: Invalid"
" TMTC bridge object!" << std::endl;
return ObjectManagerIF::CHILD_INIT_FAILED;
}
serverUdpSocket = tmtcBridge->serverSocket;
return HasReturnvaluesIF::RETURN_OK;
}
ReturnValue_t TcUnixUdpPollingTask::initializeAfterTaskCreation() {
// Initialize the destination after task creation. This ensures
// that the destination will be set in the TMTC bridge.
targetTcDestination = tmtcBridge->getRequestQueue();
return HasReturnvaluesIF::RETURN_OK;
}
void TcUnixUdpPollingTask::setTimeout(double timeoutSeconds) {
timeval tval;
tval = timevalOperations::toTimeval(timeoutSeconds);
int result = setsockopt(serverUdpSocket, SOL_SOCKET, SO_RCVTIMEO,
&tval, sizeof(receptionTimeout));
if(result == -1) {
sif::error << "TcSocketPollingTask::TcSocketPollingTask: Setting "
"receive timeout failed with " << strerror(errno) << std::endl;
}
}
// TODO: sleep after error detection to prevent spam
void TcUnixUdpPollingTask::handleReadError() {
switch(errno) {
case(EAGAIN): {
// todo: When working in timeout mode, this will occur more often
// and is not an error.
sif::error << "TcUnixUdpPollingTask::handleReadError: Timeout."
<< std::endl;
break;
}
default: {
sif::error << "TcUnixUdpPollingTask::handleReadError: "
<< strerror(errno) << std::endl;
}
}
}

View File

@ -0,0 +1,67 @@
#ifndef FRAMEWORK_OSAL_LINUX_TCSOCKETPOLLINGTASK_H_
#define FRAMEWORK_OSAL_LINUX_TCSOCKETPOLLINGTASK_H_
#include "../../objectmanager/SystemObject.h"
#include "../../osal/linux/TmTcUnixUdpBridge.h"
#include "../../tasks/ExecutableObjectIF.h"
#include <sys/socket.h>
#include <vector>
/**
* @brief This class can be used to implement the polling of a Unix socket,
* using UDP for now.
* @details
* The task will be blocked while the specified number of bytes has not been
* received, so TC reception is handled inside a separate task.
* This class caches the IP address of the sender. It is assumed there
* is only one sender for now.
*/
class TcUnixUdpPollingTask: public SystemObject,
public ExecutableObjectIF {
friend class TmTcUnixUdpBridge;
public:
static constexpr size_t DEFAULT_MAX_FRAME_SIZE = 2048;
//! 0.5 default milliseconds timeout for now.
static constexpr timeval DEFAULT_TIMEOUT = {.tv_sec = 0, .tv_usec = 500};
TcUnixUdpPollingTask(object_id_t objectId, object_id_t tmtcUnixUdpBridge,
size_t frameSize = 0, double timeoutSeconds = -1);
virtual~ TcUnixUdpPollingTask();
/**
* Turn on optional timeout for UDP polling. In the default mode,
* the receive function will block until a packet is received.
* @param timeoutSeconds
*/
void setTimeout(double timeoutSeconds);
virtual ReturnValue_t performOperation(uint8_t opCode) override;
virtual ReturnValue_t initialize() override;
virtual ReturnValue_t initializeAfterTaskCreation() override;
protected:
StorageManagerIF* tcStore = nullptr;
private:
//! TMTC bridge is cached.
object_id_t tmtcBridgeId = objects::NO_OBJECT;
TmTcUnixUdpBridge* tmtcBridge = nullptr;
MessageQueueId_t targetTcDestination = MessageQueueIF::NO_QUEUE;
//! Reception flags: https://linux.die.net/man/2/recvfrom.
int receptionFlags = 0;
//! Server socket, which is member of TMTC bridge and is assigned in
//! constructor
int serverUdpSocket = 0;
std::vector<uint8_t> receptionBuffer;
size_t frameSize = 0;
timeval receptionTimeout;
ReturnValue_t handleSuccessfullTcRead(size_t bytesRead);
void handleReadError();
};
#endif /* FRAMEWORK_OSAL_LINUX_TCSOCKETPOLLINGTASK_H_ */

View File

@ -0,0 +1,170 @@
#include "TmTcUnixUdpBridge.h"
#include "../../serviceinterface/ServiceInterfaceStream.h"
#include "../../ipc/MutexHelper.h"
#include <errno.h>
#include <arpa/inet.h>
TmTcUnixUdpBridge::TmTcUnixUdpBridge(object_id_t objectId,
object_id_t tcDestination, object_id_t tmStoreId, object_id_t tcStoreId,
uint16_t serverPort, uint16_t clientPort):
TmTcBridge(objectId, tcDestination, tmStoreId, tcStoreId) {
mutex = MutexFactory::instance()->createMutex();
uint16_t setServerPort = DEFAULT_UDP_SERVER_PORT;
if(serverPort != 0xFFFF) {
setServerPort = serverPort;
}
uint16_t setClientPort = DEFAULT_UDP_CLIENT_PORT;
if(clientPort != 0xFFFF) {
setClientPort = clientPort;
}
// Set up UDP socket: https://man7.org/linux/man-pages/man7/ip.7.html
//clientSocket = socket(AF_INET, SOCK_DGRAM, 0);
serverSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if(serverSocket < 0) {
sif::error << "TmTcUnixUdpBridge::TmTcUnixUdpBridge: Could not open"
" UDP socket!" << std::endl;
handleSocketError();
return;
}
serverAddress.sin_family = AF_INET;
// Accept packets from any interface.
//serverAddress.sin_addr.s_addr = inet_addr("127.73.73.0");
serverAddress.sin_addr.s_addr = htonl(INADDR_ANY);
serverAddress.sin_port = htons(setServerPort);
serverAddressLen = sizeof(serverAddress);
setsockopt(serverSocket, SOL_SOCKET, SO_REUSEADDR, &serverSocketOptions,
sizeof(serverSocketOptions));
clientAddress.sin_family = AF_INET;
clientAddress.sin_addr.s_addr = htonl(INADDR_ANY);
clientAddress.sin_port = htons(setClientPort);
clientAddressLen = sizeof(clientAddress);
int result = bind(serverSocket,
reinterpret_cast<struct sockaddr*>(&serverAddress),
serverAddressLen);
if(result == -1) {
sif::error << "TmTcUnixUdpBridge::TmTcUnixUdpBridge: Could not bind "
"local port " << setServerPort << " to server socket!"
<< std::endl;
handleBindError();
return;
}
}
TmTcUnixUdpBridge::~TmTcUnixUdpBridge() {
}
ReturnValue_t TmTcUnixUdpBridge::sendTm(const uint8_t *data, size_t dataLen) {
int flags = 0;
clientAddress.sin_addr.s_addr = htons(INADDR_ANY);
//clientAddress.sin_addr.s_addr = inet_addr("127.73.73.1");
clientAddressLen = sizeof(serverAddress);
// char ipAddress [15];
// sif::debug << "IP Address Sender: "<< inet_ntop(AF_INET,
// &clientAddress.sin_addr.s_addr, ipAddress, 15) << std::endl;
ssize_t bytesSent = sendto(serverSocket, data, dataLen, flags,
reinterpret_cast<sockaddr*>(&clientAddress), clientAddressLen);
if(bytesSent < 0) {
sif::error << "TmTcUnixUdpBridge::sendTm: Send operation failed."
<< std::endl;
handleSendError();
}
// sif::debug << "TmTcUnixUdpBridge::sendTm: " << bytesSent << " bytes were"
// " sent." << std::endl;
return HasReturnvaluesIF::RETURN_OK;
}
void TmTcUnixUdpBridge::checkAndSetClientAddress(sockaddr_in newAddress) {
MutexHelper lock(mutex, MutexIF::TimeoutType::WAITING, 10);
// char ipAddress [15];
// sif::debug << "IP Address Sender: "<< inet_ntop(AF_INET,
// &newAddress.sin_addr.s_addr, ipAddress, 15) << std::endl;
// sif::debug << "IP Address Old: " << inet_ntop(AF_INET,
// &clientAddress.sin_addr.s_addr, ipAddress, 15) << std::endl;
// Set new IP address if it has changed.
if(clientAddress.sin_addr.s_addr != newAddress.sin_addr.s_addr) {
clientAddress.sin_addr.s_addr = newAddress.sin_addr.s_addr;
clientAddressLen = sizeof(clientAddress);
}
}
void TmTcUnixUdpBridge::handleSocketError() {
// See: https://man7.org/linux/man-pages/man2/socket.2.html
switch(errno) {
case(EACCES):
case(EINVAL):
case(EMFILE):
case(ENFILE):
case(EAFNOSUPPORT):
case(ENOBUFS):
case(ENOMEM):
case(EPROTONOSUPPORT):
sif::error << "TmTcUnixBridge::handleSocketError: Socket creation failed"
<< " with " << strerror(errno) << std::endl;
break;
default:
sif::error << "TmTcUnixBridge::handleSocketError: Unknown error"
<< std::endl;
break;
}
}
void TmTcUnixUdpBridge::handleBindError() {
// See: https://man7.org/linux/man-pages/man2/bind.2.html
switch(errno) {
case(EACCES): {
/*
Ephermeral ports can be shown with following command:
sysctl -A | grep ip_local_port_range
*/
sif::error << "TmTcUnixBridge::handleBindError: Port access issue."
"Ports 1-1024 are reserved on UNIX systems and require root "
"rights while ephermeral ports should not be used as well."
<< std::endl;
}
break;
case(EADDRINUSE):
case(EBADF):
case(EINVAL):
case(ENOTSOCK):
case(EADDRNOTAVAIL):
case(EFAULT):
case(ELOOP):
case(ENAMETOOLONG):
case(ENOENT):
case(ENOMEM):
case(ENOTDIR):
case(EROFS): {
sif::error << "TmTcUnixBridge::handleBindError: Socket creation failed"
<< " with " << strerror(errno) << std::endl;
break;
}
default:
sif::error << "TmTcUnixBridge::handleBindError: Unknown error"
<< std::endl;
break;
}
}
void TmTcUnixUdpBridge::handleSendError() {
switch(errno) {
default:
sif::error << "TmTcUnixBridge::handleSendError: "
<< strerror(errno) << std::endl;
}
}

View File

@ -0,0 +1,48 @@
#ifndef FRAMEWORK_OSAL_LINUX_TMTCUNIXUDPBRIDGE_H_
#define FRAMEWORK_OSAL_LINUX_TMTCUNIXUDPBRIDGE_H_
#include "../../tmtcservices/AcceptsTelecommandsIF.h"
#include "../../tmtcservices/TmTcBridge.h"
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/udp.h>
class TmTcUnixUdpBridge: public TmTcBridge {
friend class TcUnixUdpPollingTask;
public:
// The ports chosen here should not be used by any other process.
// List of used ports on Linux: /etc/services
static constexpr uint16_t DEFAULT_UDP_SERVER_PORT = 7301;
static constexpr uint16_t DEFAULT_UDP_CLIENT_PORT = 7302;
TmTcUnixUdpBridge(object_id_t objectId, object_id_t tcDestination,
object_id_t tmStoreId, object_id_t tcStoreId,
uint16_t serverPort = 0xFFFF,uint16_t clientPort = 0xFFFF);
virtual~ TmTcUnixUdpBridge();
void checkAndSetClientAddress(sockaddr_in clientAddress);
protected:
virtual ReturnValue_t sendTm(const uint8_t * data, size_t dataLen) override;
private:
int serverSocket = 0;
const int serverSocketOptions = 0;
struct sockaddr_in clientAddress;
socklen_t clientAddressLen = 0;
struct sockaddr_in serverAddress;
socklen_t serverAddressLen = 0;
//! Access to the client address is mutex protected as it is set
//! by another task.
MutexIF* mutex;
void handleSocketError();
void handleBindError();
void handleSendError();
};
#endif /* FRAMEWORK_OSAL_LINUX_TMTCUNIXUDPBRIDGE_H_ */

View File

@ -1,12 +1,27 @@
#ifndef HASPARAMETERSIF_H_ #ifndef FSFW_PARAMETERS_HASPARAMETERSIF_H_
#define HASPARAMETERSIF_H_ #define FSFW_PARAMETERS_HASPARAMETERSIF_H_
#include "ParameterWrapper.h" #include "../parameters/ParameterWrapper.h"
#include "../returnvalues/HasReturnvaluesIF.h" #include "../returnvalues/HasReturnvaluesIF.h"
#include <stdint.h> #include <stdint.h>
/** Each parameter is identified with a unique parameter ID */
typedef uint32_t ParameterId_t; typedef uint32_t ParameterId_t;
/**
* @brief This interface is used by components which have modifiable
* parameters, e.g. atittude controllers
* @details
* Each parameter has a unique parameter ID. The first byte of the parameter
* ID is the domain ID which can be used to identify unqiue spacecraft domains
* (e.g. control and sensor domain in the AOCS controller).
*
* The second and third byte represent the matrix ID, which can represent
* a 8-bit row and column number and the last byte...
*
* Yeah, it it matrix ID oder parameter ID now and is index a 16 bit number
* of a 8 bit number now?
*/
class HasParametersIF { class HasParametersIF {
public: public:
static const uint8_t INTERFACE_ID = CLASS_ID::HAS_PARAMETERS_IF; static const uint8_t INTERFACE_ID = CLASS_ID::HAS_PARAMETERS_IF;
@ -32,13 +47,11 @@ public:
return (domainId << 24) + (parameterId << 8) + index; return (domainId << 24) + (parameterId << 8) + index;
} }
virtual ~HasParametersIF() { virtual ~HasParametersIF() {}
}
/** /**
* Always set parameter before checking newValues! * Always set parameter before checking newValues!
* *
*
* @param domainId * @param domainId
* @param parameterId * @param parameterId
* @param parameterWrapper * @param parameterWrapper
@ -51,4 +64,4 @@ public:
const ParameterWrapper *newValues, uint16_t startAtIndex) = 0; const ParameterWrapper *newValues, uint16_t startAtIndex) = 0;
}; };
#endif /* HASPARAMETERSIF_H_ */ #endif /* FSFW_PARAMETERS_HASPARAMETERSIF_H_ */

View File

@ -1,11 +1,9 @@
#include "../objectmanager/ObjectManagerIF.h"
#include "ParameterHelper.h" #include "ParameterHelper.h"
#include "ParameterMessage.h" #include "ParameterMessage.h"
#include "../objectmanager/ObjectManagerIF.h"
ParameterHelper::ParameterHelper(ReceivesParameterMessagesIF* owner) : ParameterHelper::ParameterHelper(ReceivesParameterMessagesIF* owner) :
owner(owner), storage(NULL) { owner(owner) {}
}
ParameterHelper::~ParameterHelper() { ParameterHelper::~ParameterHelper() {
} }
@ -28,7 +26,6 @@ ReturnValue_t ParameterHelper::handleParameterMessage(CommandMessage *message) {
} }
break; break;
case ParameterMessage::CMD_PARAMETER_LOAD: { case ParameterMessage::CMD_PARAMETER_LOAD: {
uint8_t domain = HasParametersIF::getDomain( uint8_t domain = HasParametersIF::getDomain(
ParameterMessage::getParameterId(message)); ParameterMessage::getParameterId(message));
uint16_t parameterId = HasParametersIF::getMatrixId( uint16_t parameterId = HasParametersIF::getMatrixId(
@ -36,12 +33,14 @@ ReturnValue_t ParameterHelper::handleParameterMessage(CommandMessage *message) {
uint8_t index = HasParametersIF::getIndex( uint8_t index = HasParametersIF::getIndex(
ParameterMessage::getParameterId(message)); ParameterMessage::getParameterId(message));
const uint8_t *storedStream; const uint8_t *storedStream = nullptr;
size_t storedStreamSize; size_t storedStreamSize = 0;
result = storage->getData( result = storage->getData(
ParameterMessage::getStoreId(message), &storedStream, ParameterMessage::getStoreId(message), &storedStream,
&storedStreamSize); &storedStreamSize);
if (result != HasReturnvaluesIF::RETURN_OK) { if (result != HasReturnvaluesIF::RETURN_OK) {
sif::error << "ParameterHelper::handleParameterMessage: Getting"
" store data failed for load command." << std::endl;
break; break;
} }
@ -125,7 +124,8 @@ ReturnValue_t ParameterHelper::initialize() {
} }
} }
void ParameterHelper::rejectCommand(MessageQueueId_t to, ReturnValue_t reason, Command_t initialCommand) { void ParameterHelper::rejectCommand(MessageQueueId_t to, ReturnValue_t reason,
Command_t initialCommand) {
CommandMessage reply; CommandMessage reply;
reply.setReplyRejected(reason, initialCommand); reply.setReplyRejected(reason, initialCommand);
MessageQueueSenderIF::sendMessage(to, &reply, ownerQueueId); MessageQueueSenderIF::sendMessage(to, &reply, ownerQueueId);

View File

@ -1,9 +1,16 @@
#ifndef PARAMETERHELPER_H_ #ifndef FSFW_PARAMETERS_PARAMETERHELPER_H_
#define PARAMETERHELPER_H_ #define FSFW_PARAMETERS_PARAMETERHELPER_H_
#include "ParameterMessage.h" #include "ParameterMessage.h"
#include "ReceivesParameterMessagesIF.h" #include "ReceivesParameterMessagesIF.h"
#include "../ipc/MessageQueueIF.h"
/**
* @brief Helper class to handle parameter messages.
* @details
* This class simplfies handling of parameter messages, which are sent
* to a class which implements ReceivesParameterMessagesIF.
*/
class ParameterHelper { class ParameterHelper {
public: public:
ParameterHelper(ReceivesParameterMessagesIF *owner); ParameterHelper(ReceivesParameterMessagesIF *owner);
@ -15,13 +22,15 @@ public:
private: private:
ReceivesParameterMessagesIF *owner; ReceivesParameterMessagesIF *owner;
MessageQueueId_t ownerQueueId; MessageQueueId_t ownerQueueId = MessageQueueIF::NO_QUEUE;
StorageManagerIF *storage; StorageManagerIF *storage = nullptr;
ReturnValue_t sendParameter(MessageQueueId_t to, uint32_t id, const ParameterWrapper *description); ReturnValue_t sendParameter(MessageQueueId_t to, uint32_t id,
const ParameterWrapper *description);
void rejectCommand(MessageQueueId_t to, ReturnValue_t reason, Command_t initialCommand); void rejectCommand(MessageQueueId_t to, ReturnValue_t reason,
Command_t initialCommand);
}; };
#endif /* PARAMETERHELPER_H_ */ #endif /* FSFW_PARAMETERS_PARAMETERHELPER_H_ */

View File

@ -1,4 +1,4 @@
#include "ParameterMessage.h" #include "../parameters/ParameterMessage.h"
#include "../objectmanager/ObjectManagerIF.h" #include "../objectmanager/ObjectManagerIF.h"
ParameterId_t ParameterMessage::getParameterId(const CommandMessage* message) { ParameterId_t ParameterMessage::getParameterId(const CommandMessage* message) {

View File

@ -1,8 +1,8 @@
#ifndef PARAMETERMESSAGE_H_ #ifndef FSFW_PARAMETERS_PARAMETERMESSAGE_H_
#define PARAMETERMESSAGE_H_ #define FSFW_PARAMETERS_PARAMETERMESSAGE_H_
#include "../ipc/CommandMessage.h"
#include "HasParametersIF.h" #include "HasParametersIF.h"
#include "../ipc/CommandMessage.h"
#include "../storagemanager/StorageManagerIF.h" #include "../storagemanager/StorageManagerIF.h"
class ParameterMessage { class ParameterMessage {
@ -26,4 +26,4 @@ public:
}; };
#endif /* PARAMETERMESSAGE_H_ */ #endif /* FSFW_PARAMETERS_PARAMETERMESSAGE_H_ */

View File

@ -1,20 +1,19 @@
#include "ParameterWrapper.h" #include "ParameterWrapper.h"
ParameterWrapper::ParameterWrapper() : ParameterWrapper::ParameterWrapper() :
pointsToStream(false), type(Type::UNKNOWN_TYPE), rows(0), columns(0), data( pointsToStream(false), type(Type::UNKNOWN_TYPE) {
NULL), readonlyData(NULL) {
} }
ParameterWrapper::ParameterWrapper(Type type, uint8_t rows, uint8_t columns, ParameterWrapper::ParameterWrapper(Type type, uint8_t rows, uint8_t columns,
void *data) : void *data) :
pointsToStream(false), type(type), rows(rows), columns(columns), data( pointsToStream(false), type(type), rows(rows), columns(columns),
data), readonlyData(data) { data(data), readonlyData(data) {
} }
ParameterWrapper::ParameterWrapper(Type type, uint8_t rows, uint8_t columns, ParameterWrapper::ParameterWrapper(Type type, uint8_t rows, uint8_t columns,
const void *data) : const void *data) :
pointsToStream(false), type(type), rows(rows), columns(columns), data( pointsToStream(false), type(type), rows(rows), columns(columns),
NULL), readonlyData(data) { data(nullptr), readonlyData(data) {
} }
ParameterWrapper::~ParameterWrapper() { ParameterWrapper::~ParameterWrapper() {
@ -141,6 +140,7 @@ ReturnValue_t ParameterWrapper::deSerializeData(uint8_t startingRow,
} }
ReturnValue_t ParameterWrapper::deSerialize(const uint8_t **buffer, ReturnValue_t ParameterWrapper::deSerialize(const uint8_t **buffer,
size_t *size, Endianness streamEndianness) { size_t *size, Endianness streamEndianness) {
return deSerialize(buffer, size, streamEndianness, 0); return deSerialize(buffer, size, streamEndianness, 0);
@ -184,16 +184,16 @@ ReturnValue_t ParameterWrapper::set(const uint8_t *stream, size_t streamSize,
return SerializeIF::STREAM_TOO_SHORT; return SerializeIF::STREAM_TOO_SHORT;
} }
data = NULL; data = nullptr;
readonlyData = stream; readonlyData = stream;
pointsToStream = true; pointsToStream = true;
stream += dataSize; stream += dataSize;
if (remainingStream != NULL) { if (remainingStream != nullptr) {
*remainingStream = stream; *remainingStream = stream;
} }
streamSize -= dataSize; streamSize -= dataSize;
if (remainingSize != NULL) { if (remainingSize != nullptr) {
*remainingSize = streamSize; *remainingSize = streamSize;
} }
@ -265,15 +265,15 @@ ReturnValue_t ParameterWrapper::copyFrom(const ParameterWrapper *from,
result = UNKNOW_DATATYPE; result = UNKNOW_DATATYPE;
break; break;
} }
} else { }
else {
//need a type to do arithmetic //need a type to do arithmetic
uint8_t *toDataWithType = (uint8_t*) data; uint8_t* typedData = static_cast<uint8_t*>(data);
for (uint8_t fromRow = 0; fromRow < from->rows; fromRow++) { for (uint8_t fromRow = 0; fromRow < from->rows; fromRow++) {
memcpy( size_t offset = (((startingRow + fromRow) * columns) +
toDataWithType startingColumn) * typeSize;
+ (((startingRow + fromRow) * columns) std::memcpy(typedData + offset, from->readonlyData,
+ startingColumn) * typeSize, typeSize * from->columns);
from->readonlyData, typeSize * from->columns);
} }
} }

View File

@ -1,12 +1,16 @@
#ifndef PARAMETERWRAPPER_H_ #ifndef FSFW_PARAMETERS_PARAMETERWRAPPER_H_
#define PARAMETERWRAPPER_H_ #define FSFW_PARAMETERS_PARAMETERWRAPPER_H_
#include "../returnvalues/HasReturnvaluesIF.h" #include "../returnvalues/HasReturnvaluesIF.h"
#include "../serialize/SerializeAdapter.h" #include "../serialize/SerializeAdapter.h"
#include "../serialize/SerializeIF.h" #include "../serialize/SerializeIF.h"
#include <stddef.h>
#include "../globalfunctions/Type.h" #include "../globalfunctions/Type.h"
#include <cstddef>
/**
* @brief
* @details
*/
class ParameterWrapper: public SerializeIF { class ParameterWrapper: public SerializeIF {
friend class DataPoolParameterWrapper; friend class DataPoolParameterWrapper;
public: public:
@ -36,32 +40,21 @@ public:
virtual ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size, virtual ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size,
Endianness streamEndianness, uint16_t startWritingAtIndex = 0); Endianness streamEndianness, uint16_t startWritingAtIndex = 0);
/**
* Get a specific parameter value by supplying the row and the column.
* @tparam T Type of target data
* @param value [out] Pointer to storage location
* @param row
* @param column
* @return
* -@c RETURN_OK if element was retrieved successfully
* -@c NOT_SET data has not been set yet
* -@c DATATYPE_MISSMATCH Invalid supplied type
* -@c OUT_OF_BOUNDS Invalid row and/or column.
*/
template<typename T> template<typename T>
ReturnValue_t getElement(T *value, uint8_t row = 0, uint8_t column = 0) const { ReturnValue_t getElement(T *value, uint8_t row = 0,
if (readonlyData == NULL){ uint8_t column = 0) const;
return NOT_SET;
}
if (PodTypeConversion<T>::type != type) {
return DATATYPE_MISSMATCH;
}
if ((row >= rows) || (column >= columns)) {
return OUT_OF_BOUNDS;
}
if (pointsToStream) {
const uint8_t *streamWithtype = (const uint8_t *) readonlyData;
streamWithtype += (row * columns + column) * type.getSize();
int32_t size = type.getSize();
return SerializeAdapter::deSerialize(value, &streamWithtype,
&size, true);
} else {
const T *dataWithType = (const T *) readonlyData;
*value = dataWithType[row * columns + column];
return HasReturnvaluesIF::RETURN_OK;
}
}
template<typename T> template<typename T>
void set(T *data, uint8_t rows, uint8_t columns) { void set(T *data, uint8_t rows, uint8_t columns) {
@ -111,21 +104,22 @@ public:
void setMatrix(const T& member) { void setMatrix(const T& member) {
this->set(member[0], sizeof(member)/sizeof(member[0]), sizeof(member[0])/sizeof(member[0][0])); this->set(member[0], sizeof(member)/sizeof(member[0]), sizeof(member[0])/sizeof(member[0][0]));
} }
ReturnValue_t set(const uint8_t *stream, size_t streamSize, ReturnValue_t set(const uint8_t *stream, size_t streamSize,
const uint8_t **remainingStream = NULL, size_t *remainingSize = const uint8_t **remainingStream = nullptr,
NULL); size_t *remainingSize = nullptr);
ReturnValue_t copyFrom(const ParameterWrapper *from, ReturnValue_t copyFrom(const ParameterWrapper *from,
uint16_t startWritingAtIndex); uint16_t startWritingAtIndex);
private: private:
bool pointsToStream; bool pointsToStream = false;
Type type; Type type;
uint8_t rows; uint8_t rows = 0;
uint8_t columns; uint8_t columns = 0;
void *data; void *data = nullptr;
const void *readonlyData; const void *readonlyData = nullptr;
template<typename T> template<typename T>
ReturnValue_t serializeData(uint8_t** buffer, size_t* size, ReturnValue_t serializeData(uint8_t** buffer, size_t* size,
@ -136,4 +130,33 @@ private:
const void *from, uint8_t fromRows, uint8_t fromColumns); const void *from, uint8_t fromRows, uint8_t fromColumns);
}; };
#endif /* PARAMETERWRAPPER_H_ */ template <typename T>
inline ReturnValue_t ParameterWrapper::getElement(T *value, uint8_t row,
uint8_t column) const {
if (readonlyData == nullptr){
return NOT_SET;
}
if (PodTypeConversion<T>::type != type) {
return DATATYPE_MISSMATCH;
}
if ((row >= rows) or (column >= columns)) {
return OUT_OF_BOUNDS;
}
if (pointsToStream) {
const uint8_t *streamWithType = static_cast<const uint8_t*>(readonlyData);
streamWithType += (row * columns + column) * type.getSize();
int32_t size = type.getSize();
return SerializeAdapter::deSerialize(value, &streamWithType,
&size, true);
}
else {
const T *dataWithType = static_cast<const T*>(readonlyData);
*value = dataWithType[row * columns + column];
return HasReturnvaluesIF::RETURN_OK;
}
}
#endif /* FSFW_PARAMETERS_PARAMETERWRAPPER_H_ */

View File

@ -1,5 +1,5 @@
#ifndef RECEIVESPARAMETERMESSAGESIF_H_ #ifndef FSFW_PARAMETERS_RECEIVESPARAMETERMESSAGESIF_H_
#define RECEIVESPARAMETERMESSAGESIF_H_ #define FSFW_PARAMETERS_RECEIVESPARAMETERMESSAGESIF_H_
#include "HasParametersIF.h" #include "HasParametersIF.h"
@ -16,4 +16,4 @@ public:
}; };
#endif /* RECEIVESPARAMETERMESSAGESIF_H_ */ #endif /* FSFW_PARAMETERS_RECEIVESPARAMETERMESSAGESIF_H_ */

View File

@ -64,6 +64,7 @@ enum {
LOCAL_POOL_OWNER_IF, //LPIF 58 LOCAL_POOL_OWNER_IF, //LPIF 58
POOL_VARIABLE_IF, //PVA 59 POOL_VARIABLE_IF, //PVA 59
HOUSEKEEPING_MANAGER, //HKM 60 HOUSEKEEPING_MANAGER, //HKM 60
DLE_ENCODER, //DLEE 61
FW_CLASS_ID_COUNT //is actually count + 1 ! FW_CLASS_ID_COUNT //is actually count + 1 !
}; };

View File

@ -1,5 +1,5 @@
#ifndef ENDIANSWAPPER_H_ #ifndef FSFW_SERIALIZE_ENDIANCONVERTER_H_
#define ENDIANSWAPPER_H_ #define FSFW_SERIALIZE_ENDIANCONVERTER_H_
#include "../osal/Endiness.h" #include "../osal/Endiness.h"
#include <cstring> #include <cstring>
@ -35,9 +35,7 @@
*/ */
class EndianConverter { class EndianConverter {
private: private:
EndianConverter() { EndianConverter() {};
}
;
public: public:
/** /**
* Convert a typed variable between big endian and machine endian. * Convert a typed variable between big endian and machine endian.
@ -123,4 +121,4 @@ public:
} }
}; };
#endif /* ENDIANSWAPPER_H_ */ #endif /* FSFW_SERIALIZE_ENDIANCONVERTER_H_ */

View File

@ -1,13 +1,14 @@
#ifndef FRAMEWORK_SERIALIZE_SERIALARRAYLISTADAPTER_H_ #ifndef FSFW_SERIALIZE_SERIALARRAYLISTADAPTER_H_
#define FRAMEWORK_SERIALIZE_SERIALARRAYLISTADAPTER_H_ #define FSFW_SERIALIZE_SERIALARRAYLISTADAPTER_H_
#include "../container/ArrayList.h"
#include "SerializeIF.h" #include "SerializeIF.h"
#include "../container/ArrayList.h"
#include <utility> #include <utility>
/** /**
* @ingroup serialize * Also serializes length field !
* @author baetz * @author baetz
* @ingroup serialize
*/ */
template<typename T, typename count_t = uint8_t> template<typename T, typename count_t = uint8_t>
class SerialArrayListAdapter : public SerializeIF { class SerialArrayListAdapter : public SerializeIF {
@ -27,8 +28,8 @@ public:
buffer, size, maxSize, streamEndianness); buffer, size, maxSize, streamEndianness);
count_t i = 0; count_t i = 0;
while ((result == HasReturnvaluesIF::RETURN_OK) && (i < list->size)) { while ((result == HasReturnvaluesIF::RETURN_OK) && (i < list->size)) {
result = SerializeAdapter::serialize(&list->entries[i], buffer, result = SerializeAdapter::serialize(&list->entries[i], buffer, size,
size, maxSize, streamEndianness); maxSize, streamEndianness);
++i; ++i;
} }
return result; return result;
@ -66,6 +67,7 @@ public:
if (tempSize > list->maxSize()) { if (tempSize > list->maxSize()) {
return SerializeIF::TOO_MANY_ELEMENTS; return SerializeIF::TOO_MANY_ELEMENTS;
} }
list->size = tempSize; list->size = tempSize;
count_t i = 0; count_t i = 0;
while ((result == HasReturnvaluesIF::RETURN_OK) && (i < list->size)) { while ((result == HasReturnvaluesIF::RETURN_OK) && (i < list->size)) {
@ -76,10 +78,9 @@ public:
} }
return result; return result;
} }
private: private:
ArrayList<T, count_t> *adaptee; ArrayList<T, count_t> *adaptee;
}; };
#endif /* FSFW_SERIALIZE_SERIALARRAYLISTADAPTER_H_ */
#endif /* FRAMEWORK_SERIALIZE_SERIALARRAYLISTADAPTER_H_ */

View File

@ -1,31 +1,57 @@
#ifndef SERIALFIXEDARRAYLISTADAPTER_H_ #ifndef FSFW_SERIALIZE_SERIALFIXEDARRAYLISTADAPTER_H_
#define SERIALFIXEDARRAYLISTADAPTER_H_ #define FSFW_SERIALIZE_SERIALFIXEDARRAYLISTADAPTER_H_
#include "../container/FixedArrayList.h"
#include "SerialArrayListAdapter.h" #include "SerialArrayListAdapter.h"
#include "../container/FixedArrayList.h"
/** /**
* \ingroup serialize * @brief This adapter provides an interface for SerializeIF to serialize and
* deserialize buffers with a header containing the buffer length.
* @details
* Can be used by SerialLinkedListAdapter by declaring
* as a linked element with SerializeElement<SerialFixedArrayListAdapter<...>>.
* The sequence of objects is defined in the constructor by
* using the setStart and setNext functions.
*
* @tparam BUFFER_TYPE: Specifies the data type of the buffer
* @tparam MAX_SIZE: Specifies the maximum allowed number of elements
* (not bytes!)
* @tparam count_t: specifies the type/size of the length field which defaults
* to one byte.
* @ingroup serialize
*/ */
template<typename T, uint32_t MAX_SIZE, typename count_t = uint8_t> template<typename BUFFER_TYPE, uint32_t MAX_SIZE, typename count_t = uint8_t>
class SerialFixedArrayListAdapter : public FixedArrayList<T, MAX_SIZE, count_t>, public SerializeIF { class SerialFixedArrayListAdapter :
public FixedArrayList<BUFFER_TYPE, MAX_SIZE, count_t>,
public SerializeIF {
public: public:
/**
* Constructor arguments are forwarded to FixedArrayList constructor.
* Refer to the fixed array list constructors for different options.
* @param args
*/
template<typename... Args> template<typename... Args>
SerialFixedArrayListAdapter(Args... args) : FixedArrayList<T, MAX_SIZE, count_t>(std::forward<Args>(args)...) { SerialFixedArrayListAdapter(Args... args) :
} FixedArrayList<BUFFER_TYPE, MAX_SIZE, count_t>(
std::forward<Args>(args)...){}
ReturnValue_t serialize(uint8_t** buffer, size_t* size, ReturnValue_t serialize(uint8_t** buffer, size_t* size,
size_t maxSize, Endianness streamEndianness) const { size_t maxSize, Endianness streamEndianness) const {
return SerialArrayListAdapter<T, count_t>::serialize(this, buffer, size, maxSize, streamEndianness); return SerialArrayListAdapter<BUFFER_TYPE, count_t>::serialize(this,
buffer, size, maxSize, streamEndianness);
} }
size_t getSerializedSize() const { size_t getSerializedSize() const {
return SerialArrayListAdapter<T, count_t>::getSerializedSize(this); return SerialArrayListAdapter<BUFFER_TYPE, count_t>::
getSerializedSize(this);
} }
ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size, ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size,
Endianness streamEndianness) { Endianness streamEndianness) {
return SerialArrayListAdapter<T, count_t>::deSerialize(this, buffer, size, streamEndianness); return SerialArrayListAdapter<BUFFER_TYPE, count_t>::deSerialize(this,
buffer, size, streamEndianness);
} }
}; };
#endif /* FSFW_SERIALIZE_SERIALFIXEDARRAYLISTADAPTER_H_ */
#endif /* SERIALFIXEDARRAYLISTADAPTER_H_ */

View File

@ -1,32 +1,52 @@
/** #ifndef FSFW_SERIALIZE_SERIALLINKEDLISTADAPTER_H_
* @file SerialLinkedListAdapter.h #define FSFW_SERIALIZE_SERIALLINKEDLISTADAPTER_H_
* @brief This file defines the SerialLinkedListAdapter class.
* @date 22.07.2014
* @author baetz
*/
#ifndef SERIALLINKEDLISTADAPTER_H_
#define SERIALLINKEDLISTADAPTER_H_
#include "../container/SinglyLinkedList.h" #include "../container/SinglyLinkedList.h"
#include "SerializeAdapter.h" #include "SerializeAdapter.h"
#include "SerializeElement.h" #include "SerializeElement.h"
#include "SerializeIF.h" #include "SerializeIF.h"
//This is where we need the SerializeAdapter!
/** /**
* \ingroup serialize * @brief Implement the conversion of object data to data streams
* or vice-versa, using linked lists.
* @details
* An alternative to the AutoSerializeAdapter functions
* - All object members with a datatype are declared as
* SerializeElement<element_type> members inside the class
* implementing this adapter.
* - The element type can also be a SerialBufferAdapter to
* de-/serialize buffers.
* - The element type can also be a SerialFixedArrayListAdapter to
* de-/serialize buffers with a size header, which is scanned automatically.
*
* The sequence of objects is defined in the constructor by using
* the setStart and setNext functions.
*
* 1. The serialization process is done by instantiating the class and
* calling serialize after all SerializeElement entries have been set by
* using the constructor or setter functions. An additional size variable
* can be supplied which is calculated/incremented automatically.
* 2. The deserialization process is done by instantiating the class and
* supplying a buffer with the data which is converted into an object.
* The size of data to serialize can be supplied and is
* decremented in the function. Range checking is done internally.
* @author baetz
* @ingroup serialize
*/ */
template<typename T, typename count_t = uint8_t> template<typename T, typename count_t = uint8_t>
class SerialLinkedListAdapter: public SinglyLinkedList<T>, public SerializeIF { class SerialLinkedListAdapter: public SinglyLinkedList<T>, public SerializeIF {
public: public:
SerialLinkedListAdapter(typename LinkedElement<T>::Iterator start, SerialLinkedListAdapter(typename LinkedElement<T>::Iterator start,
bool printCount = false) : bool printCount = false) :
SinglyLinkedList<T>(start), printCount(printCount) { SinglyLinkedList<T>(start), printCount(printCount) {
} }
SerialLinkedListAdapter(LinkedElement<T>* first, bool printCount = false) : SerialLinkedListAdapter(LinkedElement<T>* first, bool printCount = false) :
SinglyLinkedList<T>(first), printCount(printCount) { SinglyLinkedList<T>(first), printCount(printCount) {
} }
SerialLinkedListAdapter(bool printCount = false) : SerialLinkedListAdapter(bool printCount = false) :
SinglyLinkedList<T>(), printCount(printCount) { SinglyLinkedList<T>(), printCount(printCount) {
} }
@ -49,13 +69,14 @@ public:
uint8_t** buffer, size_t* size, size_t maxSize, uint8_t** buffer, size_t* size, size_t maxSize,
Endianness streamEndianness) { Endianness streamEndianness) {
ReturnValue_t result = HasReturnvaluesIF::RETURN_OK; ReturnValue_t result = HasReturnvaluesIF::RETURN_OK;
while ((result == HasReturnvaluesIF::RETURN_OK) && (element != NULL)) { while ((result == HasReturnvaluesIF::RETURN_OK) and (element != nullptr)) {
result = element->value->serialize(buffer, size, maxSize, result = element->value->serialize(buffer, size, maxSize,
streamEndianness); streamEndianness);
element = element->getNext(); element = element->getNext();
} }
return result; return result;
} }
virtual size_t getSerializedSize() const override { virtual size_t getSerializedSize() const override {
if (printCount) { if (printCount) {
return SerialLinkedListAdapter<T>::getSerializedSize() return SerialLinkedListAdapter<T>::getSerializedSize()
@ -64,32 +85,44 @@ public:
return getSerializedSize(SinglyLinkedList<T>::start); return getSerializedSize(SinglyLinkedList<T>::start);
} }
} }
static size_t getSerializedSize(const LinkedElement<T> *element) { static size_t getSerializedSize(const LinkedElement<T> *element) {
size_t size = 0; size_t size = 0;
while (element != NULL) { while (element != nullptr) {
size += element->value->getSerializedSize(); size += element->value->getSerializedSize();
element = element->getNext(); element = element->getNext();
} }
return size; return size;
} }
virtual ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size, virtual ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size,
Endianness streamEndianness) override { Endianness streamEndianness) override {
return deSerialize(SinglyLinkedList<T>::start, buffer, size, streamEndianness); return deSerialize(SinglyLinkedList<T>::start, buffer, size,
streamEndianness);
} }
static ReturnValue_t deSerialize(LinkedElement<T>* element, static ReturnValue_t deSerialize(LinkedElement<T>* element,
const uint8_t** buffer, size_t* size, Endianness streamEndianness) { const uint8_t** buffer, size_t* size, Endianness streamEndianness) {
ReturnValue_t result = HasReturnvaluesIF::RETURN_OK; ReturnValue_t result = HasReturnvaluesIF::RETURN_OK;
while ((result == HasReturnvaluesIF::RETURN_OK) && (element != NULL)) { while ((result == HasReturnvaluesIF::RETURN_OK) and (element != nullptr)) {
result = element->value->deSerialize(buffer, size, streamEndianness); result = element->value->deSerialize(buffer, size, streamEndianness);
element = element->getNext(); element = element->getNext();
} }
return result; return result;
} }
bool printCount; /**
* Copying is forbidden by deleting the copy constructor and the copy
* assignment operator because of the pointers to the linked list members.
* Unless the child class implements an own copy constructor or
* copy assignment operator, these operation will throw a compiler error.
* @param
*/
SerialLinkedListAdapter(const SerialLinkedListAdapter &) = delete;
SerialLinkedListAdapter& operator=(const SerialLinkedListAdapter&) = delete;
bool printCount;
}; };
#endif /* SERIALLINKEDLISTADAPTER_H_ */ #endif /* FSFW_SERIALIZE_SERIALLINKEDLISTADAPTER_H_ */

View File

@ -1,48 +1,114 @@
#ifndef SERIALIZEADAPTER_H_ #ifndef _FSFW_SERIALIZE_SERIALIZEADAPTER_H_
#define SERIALIZEADAPTER_H_ #define _FSFW_SERIALIZE_SERIALIZEADAPTER_H_
#include "../container/IsDerivedFrom.h"
#include "../returnvalues/HasReturnvaluesIF.h" #include "../returnvalues/HasReturnvaluesIF.h"
#include "EndianConverter.h" #include "EndianConverter.h"
#include "SerializeIF.h" #include "SerializeIF.h"
#include <string.h> #include <cstddef>
#include <type_traits>
/** /**
* \ingroup serialize * @brief These adapters provides an interface to use the SerializeIF functions
* with arbitrary template objects to facilitate and simplify the
* serialization of classes with different multiple different data types
* into buffers and vice-versa.
* @details
* The correct serialization or deserialization function is chosen at
* compile time with template type deduction.
*
* @ingroup serialize
*/ */
class SerializeAdapter { class SerializeAdapter {
public: public:
/***
* This function can be used to serialize a trivial copy-able type or a
* child of SerializeIF.
* The right template to be called is determined in the function itself.
* For objects of non trivial copy-able type this function is almost never
* called by the user directly. Instead helpers for specific types like
* SerialArrayListAdapter or SerialLinkedListAdapter is the right choice here.
*
* @param[in] object Object to serialize, the used type is deduced from this pointer
* @param[in/out] buffer Buffer to serialize into. Will be moved by the function.
* @param[in/out] size Size of current written buffer. Will be incremented by the function.
* @param[in] maxSize Max size of Buffer
* @param[in] streamEndianness Endianness of serialized element as in according to SerializeIF::Endianness
* @return
* - @c BUFFER_TOO_SHORT The given buffer in is too short
* - @c RETURN_FAILED Generic Error
* - @c RETURN_OK Successful serialization
*/
template<typename T> template<typename T>
static ReturnValue_t serialize(const T *object, uint8_t **buffer, static ReturnValue_t serialize(const T *object, uint8_t **buffer,
size_t *size, size_t maxSize, SerializeIF::Endianness streamEndianness) { size_t *size, size_t maxSize,
InternalSerializeAdapter<T, IsDerivedFrom<T, SerializeIF>::Is> adapter; SerializeIF::Endianness streamEndianness) {
InternalSerializeAdapter<T, std::is_base_of<SerializeIF, T>::value> adapter;
return adapter.serialize(object, buffer, size, maxSize, return adapter.serialize(object, buffer, size, maxSize,
streamEndianness); streamEndianness);
} }
/**
* Function to return the serialized size of the object in the pointer.
* May be a trivially copy-able object or a Child of SerializeIF
*
* @param object Pointer to Object
* @return Serialized size of object
*/
template<typename T> template<typename T>
static uint32_t getSerializedSize(const T *object) { static size_t getSerializedSize(const T *object){
InternalSerializeAdapter<T, IsDerivedFrom<T, SerializeIF>::Is> adapter; InternalSerializeAdapter<T, std::is_base_of<SerializeIF, T>::value> adapter;
return adapter.getSerializedSize(object); return adapter.getSerializedSize(object);
} }
/**
* @brief
* Deserializes a object from a given buffer of given size.
* Object Must be trivially copy-able or a child of SerializeIF.
*
* @details
* Buffer will be moved to the current read location. Size will be decreased by the function.
*
* @param[in/out] buffer Buffer to deSerialize from. Will be moved by the function.
* @param[in/out] size Remaining size of the buffer to read from. Will be decreased by function.
* @param[in] streamEndianness Endianness as in according to SerializeIF::Endianness
* @return
* - @c STREAM_TOO_SHORT The input stream is too short to deSerialize the object
* - @c TOO_MANY_ELEMENTS The buffer has more inputs than expected
* - @c RETURN_FAILED Generic Error
* - @c RETURN_OK Successful deserialization
*/
template<typename T> template<typename T>
static ReturnValue_t deSerialize(T *object, const uint8_t **buffer, static ReturnValue_t deSerialize(T *object, const uint8_t **buffer,
size_t *size, SerializeIF::Endianness streamEndianness) { size_t *size, SerializeIF::Endianness streamEndianness) {
InternalSerializeAdapter<T, IsDerivedFrom<T, SerializeIF>::Is> adapter; InternalSerializeAdapter<T, std::is_base_of<SerializeIF, T>::value> adapter;
return adapter.deSerialize(object, buffer, size, streamEndianness); return adapter.deSerialize(object, buffer, size, streamEndianness);
} }
private: private:
template<typename T, int> /**
class InternalSerializeAdapter { * Internal template to deduce the right function calls at compile time
*/
template<typename T, bool> class InternalSerializeAdapter;
/**
* Template to be used if T is not a child of SerializeIF
*
* @tparam T T must be trivially_copyable
*/
template<typename T>
class InternalSerializeAdapter<T, false> {
static_assert (std::is_trivially_copyable<T>::value,
"If a type needs to be serialized it must be a child of "
"SerializeIF or trivially copy-able");
public: public:
static ReturnValue_t serialize(const T *object, uint8_t **buffer, static ReturnValue_t serialize(const T *object, uint8_t **buffer,
size_t *size, size_t max_size, SerializeIF::Endianness streamEndianness) { size_t *size, size_t max_size,
SerializeIF::Endianness streamEndianness) {
size_t ignoredSize = 0; size_t ignoredSize = 0;
if (size == NULL) { if (size == nullptr) {
size = &ignoredSize; size = &ignoredSize;
} }
//TODO check integer overflow of *size // Check remaining size is large enough and check integer
if (sizeof(T) + *size <= max_size) { // overflow of *size
size_t newSize = sizeof(T) + *size;
if ((newSize <= max_size) and (newSize > *size)) {
T tmp; T tmp;
switch (streamEndianness) { switch (streamEndianness) {
case SerializeIF::Endianness::BIG: case SerializeIF::Endianness::BIG:
@ -56,7 +122,7 @@ private:
tmp = *object; tmp = *object;
break; break;
} }
memcpy(*buffer, &tmp, sizeof(T)); std::memcpy(*buffer, &tmp, sizeof(T));
*size += sizeof(T); *size += sizeof(T);
(*buffer) += sizeof(T); (*buffer) += sizeof(T);
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
@ -70,7 +136,7 @@ private:
T tmp; T tmp;
if (*size >= sizeof(T)) { if (*size >= sizeof(T)) {
*size -= sizeof(T); *size -= sizeof(T);
memcpy(&tmp, *buffer, sizeof(T)); std::memcpy(&tmp, *buffer, sizeof(T));
switch (streamEndianness) { switch (streamEndianness) {
case SerializeIF::Endianness::BIG: case SerializeIF::Endianness::BIG:
*object = EndianConverter::convertBigEndian<T>(tmp); *object = EndianConverter::convertBigEndian<T>(tmp);
@ -94,22 +160,26 @@ private:
uint32_t getSerializedSize(const T *object) { uint32_t getSerializedSize(const T *object) {
return sizeof(T); return sizeof(T);
} }
}; };
/**
* Template for objects that inherit from SerializeIF
*
* @tparam T A child of SerializeIF
*/
template<typename T> template<typename T>
class InternalSerializeAdapter<T, 1> { class InternalSerializeAdapter<T, true> {
public: public:
ReturnValue_t serialize(const T *object, uint8_t **buffer, ReturnValue_t serialize(const T *object, uint8_t **buffer, size_t *size,
size_t *size, size_t max_size, size_t max_size,
SerializeIF::Endianness streamEndianness) const { SerializeIF::Endianness streamEndianness) const {
size_t ignoredSize = 0; size_t ignoredSize = 0;
if (size == NULL) { if (size == nullptr) {
size = &ignoredSize; size = &ignoredSize;
} }
return object->serialize(buffer, size, max_size, streamEndianness); return object->serialize(buffer, size, max_size, streamEndianness);
} }
uint32_t getSerializedSize(const T *object) const { size_t getSerializedSize(const T *object) const {
return object->getSerializedSize(); return object->getSerializedSize();
} }
@ -120,4 +190,4 @@ private:
}; };
}; };
#endif /* SERIALIZEADAPTER_H_ */ #endif /* _FSFW_SERIALIZE_SERIALIZEADAPTER_H_ */

View File

@ -1,12 +1,20 @@
#ifndef SERIALIZEELEMENT_H_ #ifndef FSFW_SERIALIZE_SERIALIZEELEMENT_H_
#define SERIALIZEELEMENT_H_ #define FSFW_SERIALIZE_SERIALIZEELEMENT_H_
#include "../container/SinglyLinkedList.h"
#include "SerializeAdapter.h" #include "SerializeAdapter.h"
#include "../container/SinglyLinkedList.h"
#include <utility> #include <utility>
/** /**
* \ingroup serialize * @brief This class is used to mark datatypes for serialization with the
* SerialLinkedListAdapter
* @details
* Used by declaring any arbitrary datatype with SerializeElement<T> myVariable,
* inside a SerialLinkedListAdapter implementation and setting the sequence
* of objects with setNext() and setStart().
* Serialization and Deserialization is then performed automatically in
* specified sequence order.
* @ingroup serialize
*/ */
template<typename T> template<typename T>
class SerializeElement: public SerializeIF, public LinkedElement<SerializeIF> { class SerializeElement: public SerializeIF, public LinkedElement<SerializeIF> {
@ -19,7 +27,7 @@ public:
SerializeElement() : SerializeElement() :
LinkedElement<SerializeIF>(this) { LinkedElement<SerializeIF>(this) {
} }
T entry;
ReturnValue_t serialize(uint8_t **buffer, size_t *size, size_t maxSize, ReturnValue_t serialize(uint8_t **buffer, size_t *size, size_t maxSize,
Endianness streamEndianness) const override { Endianness streamEndianness) const override {
return SerializeAdapter::serialize(&entry, buffer, size, maxSize, return SerializeAdapter::serialize(&entry, buffer, size, maxSize,
@ -35,6 +43,7 @@ public:
return SerializeAdapter::deSerialize(&entry, buffer, size, return SerializeAdapter::deSerialize(&entry, buffer, size,
streamEndianness); streamEndianness);
} }
operator T() { operator T() {
return entry; return entry;
} }
@ -43,9 +52,12 @@ public:
entry = newValue; entry = newValue;
return *this; return *this;
} }
T* operator->() { T* operator->() {
return &entry; return &entry;
} }
T entry;
}; };
#endif /* SERIALIZEELEMENT_H_ */ #endif /* FSFW_SERIALIZE_SERIALIZEELEMENT_H_ */

View File

@ -1,17 +1,20 @@
#ifndef SERIALIZEIF_H_ #ifndef FSFW_SERIALIZE_SERIALIZEIF_H_
#define SERIALIZEIF_H_ #define FSFW_SERIALIZE_SERIALIZEIF_H_
#include "../returnvalues/HasReturnvaluesIF.h" #include "../returnvalues/HasReturnvaluesIF.h"
#include <stddef.h> #include <cstddef>
/** /**
* \defgroup serialize Serialization * @defgroup serialize Serialization
* Contains serialisation services. * Contains serialization services.
*/ */
/** /**
* Translation of objects into data streams. * @brief Translation of objects into data streams and from data streams.
* \ingroup serialize * @details
* Also provides options to convert from/to data with different endianness.
* variables.
* @ingroup serialize
*/ */
class SerializeIF { class SerializeIF {
public: public:
@ -20,21 +23,65 @@ public:
}; };
static const uint8_t INTERFACE_ID = CLASS_ID::SERIALIZE_IF; static const uint8_t INTERFACE_ID = CLASS_ID::SERIALIZE_IF;
static const ReturnValue_t BUFFER_TOO_SHORT = MAKE_RETURN_CODE(1); static const ReturnValue_t BUFFER_TOO_SHORT = MAKE_RETURN_CODE(1); // !< The given buffer in serialize is too short
static const ReturnValue_t STREAM_TOO_SHORT = MAKE_RETURN_CODE(2); static const ReturnValue_t STREAM_TOO_SHORT = MAKE_RETURN_CODE(2); // !< The input stream in deserialize is too short
static const ReturnValue_t TOO_MANY_ELEMENTS = MAKE_RETURN_CODE(3); static const ReturnValue_t TOO_MANY_ELEMENTS = MAKE_RETURN_CODE(3);// !< There are too many elements to be deserialized
virtual ~SerializeIF() { virtual ~SerializeIF() {
} }
/**
* @brief
* Function to serialize the object into a buffer with maxSize. Size represents the written amount.
* If a part of the buffer has been used already, size must be set to the used amount of bytes.
*
* @details
* Implementations of this function must increase the size variable and move the buffer pointer.
* MaxSize must be checked by implementations of this function
* and BUFFER_TOO_SHORT has to be returned if size would be larger than maxSize.
*
* Custom implementations might use additional return values.
*
* @param[in/out] buffer Buffer to serialize into, will be set to the current write location
* @param[in/out] size Size that has been used in the buffer already, will be increased by the function
* @param[in] maxSize The size of the buffer that is allowed to be used for serialize.
* @param[in] streamEndianness Endianness of the serialized data according to SerializeIF::Endianness
* @return
* - @c BUFFER_TOO_SHORT The given buffer in is too short
* - @c RETURN_FAILED Generic error
* - @c RETURN_OK Successful serialization
*/
virtual ReturnValue_t serialize(uint8_t **buffer, size_t *size, virtual ReturnValue_t serialize(uint8_t **buffer, size_t *size,
size_t maxSize, Endianness streamEndianness) const = 0; size_t maxSize, Endianness streamEndianness) const = 0;
/**
* Gets the size of a object if it would be serialized in a buffer
* @return Size of serialized object
*/
virtual size_t getSerializedSize() const = 0; virtual size_t getSerializedSize() const = 0;
/**
* @brief
* Deserializes a object from a given buffer of given size.
*
* @details
* Buffer must be moved to the current read location by the implementation
* of this function. Size must be decreased by the implementation.
* Implementations are not allowed to alter the buffer as indicated by const pointer.
*
* Custom implementations might use additional return values.
*
* @param[in/out] buffer Buffer to deSerialize from. Will be moved by the function.
* @param[in/out] size Remaining size of the buffer to read from. Will be decreased by function.
* @param[in] streamEndianness Endianness as in according to SerializeIF::Endianness
* @return
* - @c STREAM_TOO_SHORT The input stream is too short to deSerialize the object
* - @c TOO_MANY_ELEMENTS The buffer has more inputs than expected
* - @c RETURN_FAILED Generic Error
* - @c RETURN_OK Successful deserialization
*/
virtual ReturnValue_t deSerialize(const uint8_t **buffer, size_t *size, virtual ReturnValue_t deSerialize(const uint8_t **buffer, size_t *size,
Endianness streamEndianness) = 0; Endianness streamEndianness) = 0;
}; };
#endif /* SERIALIZEIF_H_ */ #endif /* FSFW_SERIALIZE_SERIALIZEIF_H_ */

View File

@ -151,7 +151,6 @@ HybridIterator<ModeListEntry> Subsystem::getTable(Mode_t id) {
} }
ReturnValue_t Subsystem::handleCommandMessage(CommandMessage *message) { ReturnValue_t Subsystem::handleCommandMessage(CommandMessage *message) {
ReturnValue_t result;
switch (message->getCommand()) { switch (message->getCommand()) {
case HealthMessage::HEALTH_INFO: { case HealthMessage::HEALTH_INFO: {
HealthState health = HealthMessage::getHealth(message); HealthState health = HealthMessage::getHealth(message);
@ -166,7 +165,7 @@ ReturnValue_t Subsystem::handleCommandMessage(CommandMessage *message) {
FixedArrayList<ModeListEntry, MAX_LENGTH_OF_TABLE_OR_SEQUENCE> sequence; FixedArrayList<ModeListEntry, MAX_LENGTH_OF_TABLE_OR_SEQUENCE> sequence;
const uint8_t *pointer; const uint8_t *pointer;
size_t sizeRead; size_t sizeRead;
result = IPCStore->getData( ReturnValue_t result = IPCStore->getData(
ModeSequenceMessage::getStoreAddress(message), &pointer, ModeSequenceMessage::getStoreAddress(message), &pointer,
&sizeRead); &sizeRead);
if (result == RETURN_OK) { if (result == RETURN_OK) {
@ -193,7 +192,7 @@ ReturnValue_t Subsystem::handleCommandMessage(CommandMessage *message) {
FixedArrayList<ModeListEntry, MAX_LENGTH_OF_TABLE_OR_SEQUENCE> table; FixedArrayList<ModeListEntry, MAX_LENGTH_OF_TABLE_OR_SEQUENCE> table;
const uint8_t *pointer; const uint8_t *pointer;
size_t sizeRead; size_t sizeRead;
result = IPCStore->getData( ReturnValue_t result = IPCStore->getData(
ModeSequenceMessage::getStoreAddress(message), &pointer, ModeSequenceMessage::getStoreAddress(message), &pointer,
&sizeRead); &sizeRead);
if (result == RETURN_OK) { if (result == RETURN_OK) {
@ -210,21 +209,23 @@ ReturnValue_t Subsystem::handleCommandMessage(CommandMessage *message) {
} }
break; break;
case ModeSequenceMessage::DELETE_SEQUENCE: case ModeSequenceMessage::DELETE_SEQUENCE:{
if (isInTransition) { if (isInTransition) {
replyToCommand(IN_TRANSITION, 0); replyToCommand(IN_TRANSITION, 0);
break; break;
} }
result = deleteSequence(ModeSequenceMessage::getSequenceId(message)); ReturnValue_t result = deleteSequence(ModeSequenceMessage::getSequenceId(message));
replyToCommand(result, 0); replyToCommand(result, 0);
}
break; break;
case ModeSequenceMessage::DELETE_TABLE: case ModeSequenceMessage::DELETE_TABLE:{
if (isInTransition) { if (isInTransition) {
replyToCommand(IN_TRANSITION, 0); replyToCommand(IN_TRANSITION, 0);
break; break;
} }
result = deleteTable(ModeSequenceMessage::getTableId(message)); ReturnValue_t result = deleteTable(ModeSequenceMessage::getTableId(message));
replyToCommand(result, 0); replyToCommand(result, 0);
}
break; break;
case ModeSequenceMessage::LIST_SEQUENCES: { case ModeSequenceMessage::LIST_SEQUENCES: {
SerialFixedArrayListAdapter<Mode_t, MAX_NUMBER_OF_TABLES_OR_SEQUENCES> sequences; SerialFixedArrayListAdapter<Mode_t, MAX_NUMBER_OF_TABLES_OR_SEQUENCES> sequences;
@ -549,7 +550,7 @@ Mode_t Subsystem::getFallbackSequence(Mode_t sequence) {
for (FixedMap<Mode_t, SequenceInfo>::Iterator iter = modeSequences.begin(); for (FixedMap<Mode_t, SequenceInfo>::Iterator iter = modeSequences.begin();
iter != modeSequences.end(); ++iter) { iter != modeSequences.end(); ++iter) {
if (iter.value->first == sequence) { if (iter.value->first == sequence) {
return iter->fallbackSequence; return iter->second.fallbackSequence;
} }
} }
return -1; return -1;
@ -558,7 +559,7 @@ Mode_t Subsystem::getFallbackSequence(Mode_t sequence) {
bool Subsystem::isFallbackSequence(Mode_t SequenceId) { bool Subsystem::isFallbackSequence(Mode_t SequenceId) {
for (FixedMap<Mode_t, SequenceInfo>::Iterator iter = modeSequences.begin(); for (FixedMap<Mode_t, SequenceInfo>::Iterator iter = modeSequences.begin();
iter != modeSequences.end(); iter++) { iter != modeSequences.end(); iter++) {
if (iter->fallbackSequence == SequenceId) { if (iter->second.fallbackSequence == SequenceId) {
return true; return true;
} }
} }

View File

@ -1,7 +1,8 @@
#include "CCSDSTime.h" #include "../timemanager/CCSDSTime.h"
#include <stdio.h> #include <cstdio>
#include <inttypes.h> #include <cinttypes>
#include <math.h> #include <cmath>
CCSDSTime::CCSDSTime() { CCSDSTime::CCSDSTime() {
} }
@ -119,7 +120,7 @@ ReturnValue_t CCSDSTime::convertFromCCS(Clock::TimeOfDay_t* to, const uint8_t* f
if (temp->pField & (1 << 3)) { //day of year variation if (temp->pField & (1 << 3)) { //day of year variation
uint16_t tempDay = (temp->month << 8) + temp->day; uint16_t tempDay = (temp->month << 8) + temp->day;
ReturnValue_t result = convertDaysOfYear(tempDay, to->year, result = convertDaysOfYear(tempDay, to->year,
&(temp->month), &(temp->day)); &(temp->month), &(temp->day));
if (result != RETURN_OK) { if (result != RETURN_OK) {
return result; return result;

View File

@ -5,7 +5,7 @@
#include "Clock.h" #include "Clock.h"
#include "../returnvalues/HasReturnvaluesIF.h" #include "../returnvalues/HasReturnvaluesIF.h"
#include <stdint.h> #include <cstdint>
bool operator<(const timeval& lhs, const timeval& rhs); bool operator<(const timeval& lhs, const timeval& rhs);
bool operator<=(const timeval& lhs, const timeval& rhs); bool operator<=(const timeval& lhs, const timeval& rhs);

View File

@ -122,8 +122,8 @@ void CommandingServiceBase::handleCommandMessage(CommandMessage* reply) {
// Implemented by child class, specifies what to do with reply. // Implemented by child class, specifies what to do with reply.
ReturnValue_t result = handleReply(reply, iter->command, &iter->state, ReturnValue_t result = handleReply(reply, iter->second.command, &iter->second.state,
&nextCommand, iter->objectId, &isStep); &nextCommand, iter->second.objectId, &isStep);
/* If the child implementation does not implement special handling for /* If the child implementation does not implement special handling for
* rejected replies (RETURN_FAILED or INVALID_REPLY is returned), a * rejected replies (RETURN_FAILED or INVALID_REPLY is returned), a
@ -132,7 +132,7 @@ void CommandingServiceBase::handleCommandMessage(CommandMessage* reply) {
if((reply->getCommand() == CommandMessage::REPLY_REJECTED) and if((reply->getCommand() == CommandMessage::REPLY_REJECTED) and
(result == RETURN_FAILED or result == INVALID_REPLY)) { (result == RETURN_FAILED or result == INVALID_REPLY)) {
result = reply->getReplyRejectedReason(); result = reply->getReplyRejectedReason();
failureParameter1 = iter->command; failureParameter1 = iter->second.command;
} }
switch (result) { switch (result) {
@ -149,14 +149,14 @@ void CommandingServiceBase::handleCommandMessage(CommandMessage* reply) {
default: default:
if (isStep) { if (isStep) {
verificationReporter.sendFailureReport( verificationReporter.sendFailureReport(
TC_VERIFY::PROGRESS_FAILURE, iter->tcInfo.ackFlags, TC_VERIFY::PROGRESS_FAILURE, iter->second.tcInfo.ackFlags,
iter->tcInfo.tcPacketId, iter->tcInfo.tcSequenceControl, iter->second.tcInfo.tcPacketId, iter->second.tcInfo.tcSequenceControl,
result, ++iter->step, failureParameter1, result, ++iter->second.step, failureParameter1,
failureParameter2); failureParameter2);
} else { } else {
verificationReporter.sendFailureReport( verificationReporter.sendFailureReport(
TC_VERIFY::COMPLETION_FAILURE, iter->tcInfo.ackFlags, TC_VERIFY::COMPLETION_FAILURE, iter->second.tcInfo.ackFlags,
iter->tcInfo.tcPacketId, iter->tcInfo.tcSequenceControl, iter->second.tcInfo.tcPacketId, iter->second.tcInfo.tcSequenceControl,
result, 0, failureParameter1, failureParameter2); result, 0, failureParameter1, failureParameter2);
} }
failureParameter1 = 0; failureParameter1 = 0;
@ -170,7 +170,7 @@ void CommandingServiceBase::handleCommandMessage(CommandMessage* reply) {
void CommandingServiceBase::handleReplyHandlerResult(ReturnValue_t result, void CommandingServiceBase::handleReplyHandlerResult(ReturnValue_t result,
CommandMapIter iter, CommandMessage* nextCommand, CommandMapIter iter, CommandMessage* nextCommand,
CommandMessage* reply, bool& isStep) { CommandMessage* reply, bool& isStep) {
iter->command = nextCommand->getCommand(); iter->second.command = nextCommand->getCommand();
// In case a new command is to be sent immediately, this is performed here. // In case a new command is to be sent immediately, this is performed here.
// If no new command is sent, only analyse reply result by initializing // If no new command is sent, only analyse reply result by initializing
@ -185,14 +185,14 @@ void CommandingServiceBase::handleReplyHandlerResult(ReturnValue_t result,
if (isStep and result != NO_STEP_MESSAGE) { if (isStep and result != NO_STEP_MESSAGE) {
verificationReporter.sendSuccessReport( verificationReporter.sendSuccessReport(
TC_VERIFY::PROGRESS_SUCCESS, TC_VERIFY::PROGRESS_SUCCESS,
iter->tcInfo.ackFlags, iter->tcInfo.tcPacketId, iter->second.tcInfo.ackFlags, iter->second.tcInfo.tcPacketId,
iter->tcInfo.tcSequenceControl, ++iter->step); iter->second.tcInfo.tcSequenceControl, ++iter->second.step);
} }
else { else {
verificationReporter.sendSuccessReport( verificationReporter.sendSuccessReport(
TC_VERIFY::COMPLETION_SUCCESS, TC_VERIFY::COMPLETION_SUCCESS,
iter->tcInfo.ackFlags, iter->tcInfo.tcPacketId, iter->second.tcInfo.ackFlags, iter->second.tcInfo.tcPacketId,
iter->tcInfo.tcSequenceControl, 0); iter->second.tcInfo.tcSequenceControl, 0);
checkAndExecuteFifo(iter); checkAndExecuteFifo(iter);
} }
} }
@ -200,16 +200,16 @@ void CommandingServiceBase::handleReplyHandlerResult(ReturnValue_t result,
if (isStep) { if (isStep) {
nextCommand->clearCommandMessage(); nextCommand->clearCommandMessage();
verificationReporter.sendFailureReport( verificationReporter.sendFailureReport(
TC_VERIFY::PROGRESS_FAILURE, iter->tcInfo.ackFlags, TC_VERIFY::PROGRESS_FAILURE, iter->second.tcInfo.ackFlags,
iter->tcInfo.tcPacketId, iter->second.tcInfo.tcPacketId,
iter->tcInfo.tcSequenceControl, sendResult, iter->second.tcInfo.tcSequenceControl, sendResult,
++iter->step, failureParameter1, failureParameter2); ++iter->second.step, failureParameter1, failureParameter2);
} else { } else {
nextCommand->clearCommandMessage(); nextCommand->clearCommandMessage();
verificationReporter.sendFailureReport( verificationReporter.sendFailureReport(
TC_VERIFY::COMPLETION_FAILURE, TC_VERIFY::COMPLETION_FAILURE,
iter->tcInfo.ackFlags, iter->tcInfo.tcPacketId, iter->second.tcInfo.ackFlags, iter->second.tcInfo.tcPacketId,
iter->tcInfo.tcSequenceControl, sendResult, 0, iter->second.tcInfo.tcSequenceControl, sendResult, 0,
failureParameter1, failureParameter2); failureParameter1, failureParameter2);
} }
failureParameter1 = 0; failureParameter1 = 0;
@ -248,7 +248,7 @@ void CommandingServiceBase::handleRequestQueue() {
iter = commandMap.find(queue); iter = commandMap.find(queue);
if (iter != commandMap.end()) { if (iter != commandMap.end()) {
result = iter->fifo.insert(address); result = iter->second.fifo.insert(address);
if (result != RETURN_OK) { if (result != RETURN_OK) {
rejectPacket(TC_VERIFY::START_FAILURE, &packet, OBJECT_BUSY); rejectPacket(TC_VERIFY::START_FAILURE, &packet, OBJECT_BUSY);
} }
@ -316,11 +316,11 @@ void CommandingServiceBase::startExecution(TcPacketStored *storedPacket,
CommandMapIter iter) { CommandMapIter iter) {
ReturnValue_t result = RETURN_OK; ReturnValue_t result = RETURN_OK;
CommandMessage command; CommandMessage command;
iter->subservice = storedPacket->getSubService(); iter->second.subservice = storedPacket->getSubService();
result = prepareCommand(&command, iter->subservice, result = prepareCommand(&command, iter->second.subservice,
storedPacket->getApplicationData(), storedPacket->getApplicationData(),
storedPacket->getApplicationDataSize(), &iter->state, storedPacket->getApplicationDataSize(), &iter->second.state,
iter->objectId); iter->second.objectId);
ReturnValue_t sendResult = RETURN_OK; ReturnValue_t sendResult = RETURN_OK;
switch (result) { switch (result) {
@ -330,13 +330,13 @@ void CommandingServiceBase::startExecution(TcPacketStored *storedPacket,
&command); &command);
} }
if (sendResult == RETURN_OK) { if (sendResult == RETURN_OK) {
Clock::getUptime(&iter->uptimeOfStart); Clock::getUptime(&iter->second.uptimeOfStart);
iter->step = 0; iter->second.step = 0;
iter->subservice = storedPacket->getSubService(); iter->second.subservice = storedPacket->getSubService();
iter->command = command.getCommand(); iter->second.command = command.getCommand();
iter->tcInfo.ackFlags = storedPacket->getAcknowledgeFlags(); iter->second.tcInfo.ackFlags = storedPacket->getAcknowledgeFlags();
iter->tcInfo.tcPacketId = storedPacket->getPacketId(); iter->second.tcInfo.tcPacketId = storedPacket->getPacketId();
iter->tcInfo.tcSequenceControl = iter->second.tcInfo.tcSequenceControl =
storedPacket->getPacketSequenceControl(); storedPacket->getPacketSequenceControl();
acceptPacket(TC_VERIFY::START_SUCCESS, storedPacket); acceptPacket(TC_VERIFY::START_SUCCESS, storedPacket);
} else { } else {
@ -386,7 +386,7 @@ void CommandingServiceBase::acceptPacket(uint8_t reportId,
void CommandingServiceBase::checkAndExecuteFifo(CommandMapIter iter) { void CommandingServiceBase::checkAndExecuteFifo(CommandMapIter iter) {
store_address_t address; store_address_t address;
if (iter->fifo.retrieve(&address) != RETURN_OK) { if (iter->second.fifo.retrieve(&address) != RETURN_OK) {
commandMap.erase(&iter); commandMap.erase(&iter);
} else { } else {
TcPacketStored newPacket(address); TcPacketStored newPacket(address);
@ -412,10 +412,10 @@ void CommandingServiceBase::checkTimeout() {
Clock::getUptime(&uptime); Clock::getUptime(&uptime);
CommandMapIter iter; CommandMapIter iter;
for (iter = commandMap.begin(); iter != commandMap.end(); ++iter) { for (iter = commandMap.begin(); iter != commandMap.end(); ++iter) {
if ((iter->uptimeOfStart + (timeoutSeconds * 1000)) < uptime) { if ((iter->second.uptimeOfStart + (timeoutSeconds * 1000)) < uptime) {
verificationReporter.sendFailureReport( verificationReporter.sendFailureReport(
TC_VERIFY::COMPLETION_FAILURE, iter->tcInfo.ackFlags, TC_VERIFY::COMPLETION_FAILURE, iter->second.tcInfo.ackFlags,
iter->tcInfo.tcPacketId, iter->tcInfo.tcSequenceControl, iter->second.tcInfo.tcPacketId, iter->second.tcInfo.tcSequenceControl,
TIMEOUT); TIMEOUT);
checkAndExecuteFifo(iter); checkAndExecuteFifo(iter);
} }

View File

@ -1,5 +1,5 @@
#ifndef FRAMEWORK_TMTCSERVICES_COMMANDINGSERVICEBASE_H_ #ifndef FSFW_TMTCSERVICES_COMMANDINGSERVICEBASE_H_
#define FRAMEWORK_TMTCSERVICES_COMMANDINGSERVICEBASE_H_ #define FSFW_TMTCSERVICES_COMMANDINGSERVICEBASE_H_
#include "../objectmanager/SystemObject.h" #include "../objectmanager/SystemObject.h"
#include "../storagemanager/StorageManagerIF.h" #include "../storagemanager/StorageManagerIF.h"
@ -211,8 +211,7 @@ protected:
virtual void doPeriodicOperation(); virtual void doPeriodicOperation();
struct CommandInfo: public SerializeIF{
struct CommandInfo {
struct tcInfo { struct tcInfo {
uint8_t ackFlags; uint8_t ackFlags;
uint16_t tcPacketId; uint16_t tcPacketId;
@ -225,6 +224,20 @@ protected:
Command_t command; Command_t command;
object_id_t objectId; object_id_t objectId;
FIFO<store_address_t, 3> fifo; FIFO<store_address_t, 3> fifo;
virtual ReturnValue_t serialize(uint8_t **buffer, size_t *size,
size_t maxSize, Endianness streamEndianness) const override{
return HasReturnvaluesIF::RETURN_FAILED;
};
virtual size_t getSerializedSize() const override {
return 0;
};
virtual ReturnValue_t deSerialize(const uint8_t **buffer, size_t *size,
Endianness streamEndianness) override{
return HasReturnvaluesIF::RETURN_FAILED;
};
}; };
using CommandMapIter = FixedMap<MessageQueueId_t, using CommandMapIter = FixedMap<MessageQueueId_t,
@ -345,4 +358,4 @@ private:
void checkTimeout(); void checkTimeout();
}; };
#endif /* COMMANDINGSERVICEBASE_H_ */ #endif /* FSFW_TMTCSERVICES_COMMANDINGSERVICEBASE_H_ */

View File

@ -1,7 +1,7 @@
#include "TmTcBridge.h" #include "../tmtcservices/TmTcBridge.h"
#include "../ipc/QueueFactory.h" #include "../ipc/QueueFactory.h"
#include "AcceptsTelecommandsIF.h" #include "../tmtcservices/AcceptsTelecommandsIF.h"
#include "../serviceinterface/ServiceInterfaceStream.h" #include "../serviceinterface/ServiceInterfaceStream.h"
#include "../globalfunctions/arrayprinter.h" #include "../globalfunctions/arrayprinter.h"
@ -66,6 +66,8 @@ ReturnValue_t TmTcBridge::initialize() {
return ObjectManagerIF::CHILD_INIT_FAILED; return ObjectManagerIF::CHILD_INIT_FAILED;
} }
tmFifo = new DynamicFIFO<store_address_t>(maxNumberOfPacketsStored);
tmTcReceptionQueue->setDefaultDestination(tcDistributor->getRequestQueue()); tmTcReceptionQueue->setDefaultDestination(tcDistributor->getRequestQueue());
return RETURN_OK; return RETURN_OK;
} }
@ -90,102 +92,122 @@ ReturnValue_t TmTcBridge::handleTc() {
} }
ReturnValue_t TmTcBridge::handleTm() { ReturnValue_t TmTcBridge::handleTm() {
ReturnValue_t status = HasReturnvaluesIF::RETURN_OK;
ReturnValue_t result = handleTmQueue(); ReturnValue_t result = handleTmQueue();
if(result != RETURN_OK) { if(result != RETURN_OK) {
sif::warning << "TmTcBridge: Reading TM Queue failed" << std::endl; sif::error << "TmTcBridge::handleTm: Error handling TM queue!"
return RETURN_FAILED; << std::endl;
status = result;
} }
if(tmStored and communicationLinkUp) { if(tmStored and communicationLinkUp and
(packetSentCounter < sentPacketsPerCycle)) {
result = handleStoredTm(); result = handleStoredTm();
if(result != RETURN_OK) {
sif::error << "TmTcBridge::handleTm: Error handling stored TMs!"
<< std::endl;
status = result;
} }
return result; }
packetSentCounter = 0;
return status;
} }
ReturnValue_t TmTcBridge::handleTmQueue() { ReturnValue_t TmTcBridge::handleTmQueue() {
TmTcMessage message; TmTcMessage message;
const uint8_t* data = nullptr; const uint8_t* data = nullptr;
size_t size = 0; size_t size = 0;
ReturnValue_t status = HasReturnvaluesIF::RETURN_OK;
for (ReturnValue_t result = tmTcReceptionQueue->receiveMessage(&message); for (ReturnValue_t result = tmTcReceptionQueue->receiveMessage(&message);
result == RETURN_OK; result = tmTcReceptionQueue->receiveMessage(&message)) result == HasReturnvaluesIF::RETURN_OK;
result = tmTcReceptionQueue->receiveMessage(&message))
{ {
if(communicationLinkUp == false) { //sif::info << (int) packetSentCounter << std::endl;
result = storeDownlinkData(&message); if(communicationLinkUp == false or
return result; packetSentCounter >= sentPacketsPerCycle) {
storeDownlinkData(&message);
continue;
} }
result = tmStore->getData(message.getStorageId(), &data, &size); result = tmStore->getData(message.getStorageId(), &data, &size);
if (result != HasReturnvaluesIF::RETURN_OK) { if (result != HasReturnvaluesIF::RETURN_OK) {
status = result;
continue; continue;
} }
result = sendTm(data, size); result = sendTm(data, size);
if (result != RETURN_OK) { if (result != HasReturnvaluesIF::RETURN_OK) {
sif::warning << "TmTcBridge: Could not send TM packet" << std::endl; status = result;
tmStore->deleteData(message.getStorageId());
return result;
} }
else {
tmStore->deleteData(message.getStorageId()); tmStore->deleteData(message.getStorageId());
packetSentCounter++;
} }
return RETURN_OK; }
return status;
} }
ReturnValue_t TmTcBridge::storeDownlinkData(TmTcMessage *message) { ReturnValue_t TmTcBridge::storeDownlinkData(TmTcMessage *message) {
store_address_t storeId = 0; store_address_t storeId = 0;
if(tmFifo.full()) { if(tmFifo->full()) {
sif::error << "TmTcBridge::storeDownlinkData: TM downlink max. number " sif::debug << "TmTcBridge::storeDownlinkData: TM downlink max. number "
<< "of stored packet IDs reached! " << "of stored packet IDs reached! " << std::endl;
<< "Overwriting old data" << std::endl; if(overwriteOld) {
tmFifo.retrieve(&storeId); tmFifo->retrieve(&storeId);
tmStore->deleteData(storeId); tmStore->deleteData(storeId);
} }
else {
return HasReturnvaluesIF::RETURN_FAILED;
}
}
storeId = message->getStorageId(); storeId = message->getStorageId();
tmFifo.insert(storeId); tmFifo->insert(storeId);
tmStored = true; tmStored = true;
return RETURN_OK; return RETURN_OK;
} }
ReturnValue_t TmTcBridge::handleStoredTm() { ReturnValue_t TmTcBridge::handleStoredTm() {
uint8_t counter = 0; ReturnValue_t status = RETURN_OK;
ReturnValue_t result = RETURN_OK; while(not tmFifo->empty() and packetSentCounter < sentPacketsPerCycle) {
while(not tmFifo.empty() and counter < sentPacketsPerCycle) { //sif::info << "TMTC Bridge: Sending stored TM data. There are "
//info << "TMTC Bridge: Sending stored TM data. There are " // << (int) tmFifo->size() << " left to send\r\n" << std::flush;
// << (int) fifo.size() << " left to send\r\n" << std::flush;
store_address_t storeId; store_address_t storeId;
const uint8_t* data = nullptr; const uint8_t* data = nullptr;
size_t size = 0; size_t size = 0;
tmFifo.retrieve(&storeId); tmFifo->retrieve(&storeId);
result = tmStore->getData(storeId, &data, &size); ReturnValue_t result = tmStore->getData(storeId, &data, &size);
if(result != HasReturnvaluesIF::RETURN_OK) {
sendTm(data,size); status = result;
}
result = sendTm(data,size);
if(result != RETURN_OK) { if(result != RETURN_OK) {
sif::error << "TMTC Bridge: Could not send stored downlink data" sif::error << "TMTC Bridge: Could not send stored downlink data"
<< std::endl; << std::endl;
result = RETURN_FAILED; status = result;
} }
counter ++; packetSentCounter ++;
if(tmFifo.empty()) { if(tmFifo->empty()) {
tmStored = false; tmStored = false;
} }
tmStore->deleteData(storeId); tmStore->deleteData(storeId);
} }
return result; return status;
} }
void TmTcBridge::registerCommConnect() { void TmTcBridge::registerCommConnect() {
if(not communicationLinkUp) { if(not communicationLinkUp) {
//info << "TMTC Bridge: Registered Comm Link Connect" << std::endl; //sif::info << "TMTC Bridge: Registered Comm Link Connect" << std::endl;
communicationLinkUp = true; communicationLinkUp = true;
} }
} }
void TmTcBridge::registerCommDisconnect() { void TmTcBridge::registerCommDisconnect() {
//info << "TMTC Bridge: Registered Comm Link Disconnect" << std::endl; //sif::info << "TMTC Bridge: Registered Comm Link Disconnect" << std::endl;
if(communicationLinkUp) { if(communicationLinkUp) {
communicationLinkUp = false; communicationLinkUp = false;
} }
@ -209,3 +231,7 @@ MessageQueueId_t TmTcBridge::getRequestQueue() {
// Default implementation: Relay TC messages to TC distributor directly. // Default implementation: Relay TC messages to TC distributor directly.
return tmTcReceptionQueue->getDefaultDestination(); return tmTcReceptionQueue->getDefaultDestination();
} }
void TmTcBridge::setFifoToOverwriteOldData(bool overwriteOld) {
this->overwriteOld = overwriteOld;
}

View File

@ -1,15 +1,15 @@
#ifndef FRAMEWORK_TMTCSERVICES_TMTCBRIDGE_H_ #ifndef FRAMEWORK_TMTCSERVICES_TMTCBRIDGE_H_
#define FRAMEWORK_TMTCSERVICES_TMTCBRIDGE_H_ #define FRAMEWORK_TMTCSERVICES_TMTCBRIDGE_H_
#include "../objectmanager/SystemObject.h" #include "../objectmanager/SystemObject.h"
#include "AcceptsTelemetryIF.h" #include "../tmtcservices/AcceptsTelemetryIF.h"
#include "../tasks/ExecutableObjectIF.h" #include "../tasks/ExecutableObjectIF.h"
#include "../ipc/MessageQueueIF.h" #include "../ipc/MessageQueueIF.h"
#include "../storagemanager/StorageManagerIF.h" #include "../storagemanager/StorageManagerIF.h"
#include "AcceptsTelecommandsIF.h" #include "../tmtcservices/AcceptsTelecommandsIF.h"
#include "../container/DynamicFIFO.h"
#include "../container/FIFO.h" #include "../tmtcservices/TmTcMessage.h"
#include "TmTcMessage.h"
class TmTcBridge : public AcceptsTelemetryIF, class TmTcBridge : public AcceptsTelemetryIF,
public AcceptsTelecommandsIF, public AcceptsTelecommandsIF,
@ -46,6 +46,12 @@ public:
*/ */
ReturnValue_t setMaxNumberOfPacketsStored(uint8_t maxNumberOfPacketsStored); ReturnValue_t setMaxNumberOfPacketsStored(uint8_t maxNumberOfPacketsStored);
/**
* This will set up the bridge to overwrite old data in the FIFO.
* @param overwriteOld
*/
void setFifoToOverwriteOldData(bool overwriteOld);
virtual void registerCommConnect(); virtual void registerCommConnect();
virtual void registerCommDisconnect(); virtual void registerCommDisconnect();
@ -86,6 +92,8 @@ protected:
//! by default, so telemetry will be handled immediately. //! by default, so telemetry will be handled immediately.
bool communicationLinkUp = true; bool communicationLinkUp = true;
bool tmStored = false; bool tmStored = false;
bool overwriteOld = true;
uint8_t packetSentCounter = 0;
/** /**
* @brief Handle TC reception * @brief Handle TC reception
@ -145,7 +153,7 @@ protected:
* This fifo can be used to store downlink data * This fifo can be used to store downlink data
* which can not be sent at the moment. * which can not be sent at the moment.
*/ */
FIFO<store_address_t, LIMIT_DOWNLINK_PACKETS_STORED> tmFifo; DynamicFIFO<store_address_t>* tmFifo = nullptr;
uint8_t sentPacketsPerCycle = DEFAULT_STORED_DATA_SENT_PER_CYCLE; uint8_t sentPacketsPerCycle = DEFAULT_STORED_DATA_SENT_PER_CYCLE;
uint8_t maxNumberOfPacketsStored = DEFAULT_DOWNLINK_PACKETS_STORED; uint8_t maxNumberOfPacketsStored = DEFAULT_DOWNLINK_PACKETS_STORED;
}; };