1
0
forked from fsfw/fsfw

Merge branch 'master' into mueller/sharedRingBufferPullRequest

This commit is contained in:
Steffen Gaisser 2020-09-08 14:31:40 +02:00
commit e24e080f31
75 changed files with 3202 additions and 907 deletions
action
container
devicehandlers
events
fdir
globalfunctions
health
ipc
memory
modes
monitoring
objectmanager
osal
parameters
serialize
subsystem
tasks
timemanager
tmstorage
tmtcservices

@ -10,7 +10,7 @@ class ActionMessage {
private: private:
ActionMessage(); ActionMessage();
public: public:
static const uint8_t MESSAGE_ID = MESSAGE_TYPE::ACTION; static const uint8_t MESSAGE_ID = messagetypes::ACTION;
static const Command_t EXECUTE_ACTION = MAKE_COMMAND_ID(1); static const Command_t EXECUTE_ACTION = MAKE_COMMAND_ID(1);
static const Command_t STEP_SUCCESS = MAKE_COMMAND_ID(2); static const Command_t STEP_SUCCESS = MAKE_COMMAND_ID(2);
static const Command_t STEP_FAILED = MAKE_COMMAND_ID(3); static const Command_t STEP_FAILED = MAKE_COMMAND_ID(3);

42
container/DynamicFIFO.h Normal file

@ -0,0 +1,42 @@
#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.
*/
DynamicFIFO(const DynamicFIFO& other): FIFOBase<T>(other),
fifoVector(other.maxCapacity) {
this->setContainer(fifoVector.data());
}
private:
std::vector<T> fifoVector;
};
#endif /* FSFW_CONTAINER_DYNAMICFIFO_H_ */

@ -1,82 +1,35 @@
#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->setContainer(fifoArray.data());
} }
bool empty() { private:
return (currentSize == 0); std::array<T, capacity> fifoArray;
}
bool full() {
return (currentSize == capacity);
}
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

@ -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

@ -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

@ -1,18 +1,23 @@
#include "SimpleRingBuffer.h" #include "SimpleRingBuffer.h"
#include <string.h> #include <string.h>
SimpleRingBuffer::SimpleRingBuffer(uint32_t size, bool overwriteOld) : SimpleRingBuffer::SimpleRingBuffer(const size_t size, bool overwriteOld) :
RingBufferBase<>(0, size, overwriteOld), buffer(NULL) { RingBufferBase<>(0, size, overwriteOld) {
buffer = new uint8_t[size]; buffer = new uint8_t[size];
} }
SimpleRingBuffer::SimpleRingBuffer(uint8_t *buffer, const size_t size,
bool overwriteOld):
RingBufferBase<>(0, size, overwriteOld), buffer(buffer) {}
SimpleRingBuffer::~SimpleRingBuffer() { SimpleRingBuffer::~SimpleRingBuffer() {
delete[] buffer; delete[] buffer;
} }
ReturnValue_t SimpleRingBuffer::writeData(const uint8_t* data, ReturnValue_t SimpleRingBuffer::writeData(const uint8_t* data,
uint32_t amount) { uint32_t amount) {
if (availableWriteSpace() >= amount || overwriteOld) { if (availableWriteSpace() >= amount or overwriteOld) {
uint32_t amountTillWrap = writeTillWrap(); uint32_t amountTillWrap = writeTillWrap();
if (amountTillWrap >= amount) { if (amountTillWrap >= amount) {
memcpy(&buffer[write], data, amount); memcpy(&buffer[write], data, amount);
@ -38,7 +43,7 @@ ReturnValue_t SimpleRingBuffer::readData(uint8_t* data, uint32_t amount,
return HasReturnvaluesIF::RETURN_FAILED; return HasReturnvaluesIF::RETURN_FAILED;
} }
} }
if (trueAmount != NULL) { if (trueAmount != nullptr) {
*trueAmount = amount; *trueAmount = amount;
} }
if (amountTillWrap >= amount) { if (amountTillWrap >= amount) {
@ -60,9 +65,10 @@ ReturnValue_t SimpleRingBuffer::deleteData(uint32_t amount,
return HasReturnvaluesIF::RETURN_FAILED; return HasReturnvaluesIF::RETURN_FAILED;
} }
} }
if (trueAmount != NULL) { if (trueAmount != nullptr) {
*trueAmount = amount; *trueAmount = amount;
} }
incrementRead(amount, READ_PTR); incrementRead(amount, READ_PTR);
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
} }

@ -4,17 +4,64 @@
#include "RingBufferBase.h" #include "RingBufferBase.h"
#include <stddef.h> #include <stddef.h>
/**
* @brief Circular buffer implementation, useful for buffering
* into data streams.
* @details
* Note that the deleteData() has to be called to increment the read pointer.
* This class allocated dynamically, so
* @ingroup containers
*/
class SimpleRingBuffer: public RingBufferBase<> { class SimpleRingBuffer: public RingBufferBase<> {
public: public:
SimpleRingBuffer(uint32_t size, bool overwriteOld); /**
* This constructor allocates a new internal buffer with the supplied size.
* @param size
* @param overwriteOld
*/
SimpleRingBuffer(const size_t size, bool overwriteOld);
/**
* This constructor takes an external buffer with the specified size.
* @param buffer
* @param size
* @param overwriteOld
*/
SimpleRingBuffer(uint8_t* buffer, const size_t size, bool overwriteOld);
virtual ~SimpleRingBuffer(); virtual ~SimpleRingBuffer();
/**
* Write to circular buffer and increment write pointer by amount
* @param data
* @param amount
* @return
*/
ReturnValue_t writeData(const uint8_t* data, uint32_t amount); ReturnValue_t writeData(const uint8_t* data, uint32_t amount);
ReturnValue_t readData(uint8_t* data, uint32_t amount, bool readRemaining = false, uint32_t* trueAmount = NULL);
ReturnValue_t deleteData(uint32_t amount, bool deleteRemaining = false, uint32_t* trueAmount = NULL); /**
* Read from circular buffer at read pointer
* @param data
* @param amount
* @param readRemaining
* @param trueAmount
* @return
*/
ReturnValue_t readData(uint8_t* data, uint32_t amount,
bool readRemaining = false, uint32_t* trueAmount = nullptr);
/**
* Delete data starting by incrementing read pointer
* @param amount
* @param deleteRemaining
* @param trueAmount
* @return
*/
ReturnValue_t deleteData(uint32_t amount, bool deleteRemaining = false,
uint32_t* trueAmount = nullptr);
private: private:
// static const uint8_t TEMP_READ_PTR = 1; // static const uint8_t TEMP_READ_PTR = 1;
static const uint8_t READ_PTR = 0; static const uint8_t READ_PTR = 0;
uint8_t* buffer; uint8_t* buffer = nullptr;
}; };
#endif /* FRAMEWORK_CONTAINER_SIMPLERINGBUFFER_H_ */ #endif /* FRAMEWORK_CONTAINER_SIMPLERINGBUFFER_H_ */

@ -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;

@ -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_ */

@ -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,27 +124,40 @@ 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;
} }
AcceptsDeviceResponsesIF *rawReceiver = objectManager->get< if(rawDataReceiverId != objects::NO_OBJECT) {
AcceptsDeviceResponsesIF>(rawDataReceiverId); AcceptsDeviceResponsesIF *rawReceiver = objectManager->get<
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 == nullptr) {
if (powerSwitcher == NULL) { sif::error << "DeviceHandlerBase::initialize: Power switcher "
return RETURN_FAILED; << "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();
if (result != RETURN_OK) { if (result != RETURN_OK) {
return result; return result;
} }
result = modeHelper.initialize(); result = modeHelper.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) {
return;
}
result = modeHelper.handleModeCommand(&command);
if (result == RETURN_OK) { if (result == RETURN_OK) {
return; return;
} }
result = modeHelper.handleModeCommand(&message); result = actionHelper.handleActionMessage(&command);
if (result == RETURN_OK) { if (result == RETURN_OK) {
return; return;
} }
result = actionHelper.handleActionMessage(&message); result = parameterHelper.handleParameterMessage(&command);
if (result == RETURN_OK) { if (result == RETURN_OK) {
return; return;
} }
result = parameterHelper.handleParameterMessage(&message); // result = hkManager.handleHousekeepingMessage(&command);
// if (result == RETURN_OK) {
// return;
// }
result = handleDeviceHandlerMessage(&command);
if (result == RETURN_OK) { if (result == RETURN_OK) {
return; return;
} }
result = handleDeviceHandlerMessage(&message); result = letChildHandleMessage(&command);
if (result == RETURN_OK) {
return;
}
result = letChildHandleMessage(&message);
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,51 +638,101 @@ 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);
uint32_t remainingLength = receivedDataLen; }
for (uint32_t count = 0; count < receivedDataLen; count++) { }
result = scanForReply(receivedData, remainingLength, &foundId,
&foundLen); void DeviceHandlerBase::parseReply(const uint8_t* receivedData,
switch (result) { size_t receivedDataLen) {
case RETURN_OK: ReturnValue_t result = HasReturnvaluesIF::RETURN_FAILED;
handleReply(receivedData, foundId, foundLen); DeviceCommandId_t foundId = 0xFFFFFFFF;
break; size_t foundLen = 0;
case APERIODIC_REPLY: { // The loop may not execute more often than the number of received bytes
result = interpretDeviceReply(foundId, receivedData); // (worst case). This approach avoids infinite loops due to buggy
if (result != RETURN_OK) { // scanForReply routines.
replyRawReplyIfnotWiretapped(receivedData, foundLen); uint32_t remainingLength = receivedDataLen;
triggerEvent(DEVICE_INTERPRETING_REPLY_FAILED, result, for (uint32_t count = 0; count < receivedDataLen; count++) {
foundId); result = scanForReply(receivedData, remainingLength, &foundId,
} &foundLen);
} switch (result) {
break; case RETURN_OK:
case IGNORE_REPLY_DATA: handleReply(receivedData, foundId, foundLen);
break; break;
case IGNORE_FULL_PACKET: case APERIODIC_REPLY: {
return; result = interpretDeviceReply(foundId, receivedData);
default: if (result != RETURN_OK) {
//We need to wait for timeout.. don't know what command failed and who sent it.
replyRawReplyIfnotWiretapped(receivedData, foundLen); replyRawReplyIfnotWiretapped(receivedData, foundLen);
triggerEvent(DEVICE_READING_REPLY_FAILED, result, foundLen); triggerEvent(DEVICE_INTERPRETING_REPLY_FAILED, result,
break; foundId);
}
receivedData += foundLen;
if (remainingLength > foundLen) {
remainingLength -= foundLen;
} else {
return;
} }
} }
break;
case IGNORE_REPLY_DATA:
break;
case IGNORE_FULL_PACKET:
return;
default:
//We need to wait for timeout.. don't know what command failed and who sent it.
replyRawReplyIfnotWiretapped(receivedData, foundLen);
triggerEvent(DEVICE_READING_REPLY_FAILED, result, foundLen);
break;
}
receivedData += foundLen;
if (remainingLength > foundLen) {
remainingLength -= foundLen;
} else {
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) {
@ -997,8 +1029,8 @@ HasHealthIF::HealthState DeviceHandlerBase::getHealth() {
} }
ReturnValue_t DeviceHandlerBase::setHealth(HealthState health) { ReturnValue_t DeviceHandlerBase::setHealth(HealthState health) {
healthHelper.setHealth(health); healthHelper.setHealth(health);
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
} }
void DeviceHandlerBase::checkSwitchState() { void DeviceHandlerBase::checkSwitchState() {
@ -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)) {
// 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,
true);
} }
} else { //unrequested/aperiodic replies else if (forceDirectTm and (defaultRawReceiver != queueId) and
if (wiretappingMode == TM) { (defaultRawReceiver != MessageQueueIF::NO_QUEUE))
actionHelper.reportData(requestedRawTraffic, replyId, &wrapper); {
} else if (forceDirectTm) { // hiding of sender needed so the service will handle it as
// hiding of sender needed so the service will handle it as unexpected Data, no matter what state // unexpected Data, no matter what state (progress or completed)
//(progress or completed) it is in // it is in
actionHelper.reportData(defaultRawReceiver, replyId, &wrapper, actionHelper.reportData(defaultRawReceiver, replyId, &wrapper,
true); true);
} }
} }
//Try to cast to DataSet and commit data. //unrequested/aperiodic replies
else
{
if (wiretappingMode == TM) {
actionHelper.reportData(requestedRawTraffic, replyId, &wrapper);
}
else if (forceDirectTm and defaultRawReceiver !=
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,
true);
}
}
//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;
} }
@ -1281,11 +1330,22 @@ void DeviceHandlerBase::changeHK(Mode_t mode, Submode_t submode, bool enable) {
} }
void DeviceHandlerBase::setTaskIF(PeriodicTaskIF* task_){ void DeviceHandlerBase::setTaskIF(PeriodicTaskIF* task_){
executingTask = task_; executingTask = task_;
} }
// Default implementations empty. // Default implementations empty.
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;
}

@ -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_ */

@ -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,9 +76,11 @@ ReturnValue_t DeviceHandlerFailureIsolation::eventReceived(EventMessage* event)
break; break;
//****Power***** //****Power*****
case PowerSwitchIF::SWITCH_WENT_OFF: case PowerSwitchIF::SWITCH_WENT_OFF:
result = sendConfirmationRequest(event, powerConfirmation); if(powerConfirmation != MessageQueueIF::NO_QUEUE) {
if (result == RETURN_OK) { result = sendConfirmationRequest(event, powerConfirmation);
setFdirState(DEVICE_MIGHT_BE_OFF); if (result == RETURN_OK) {
setFdirState(DEVICE_MIGHT_BE_OFF);
}
} }
break; break;
case Fuse::FUSE_WENT_OFF: case Fuse::FUSE_WENT_OFF:
@ -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;
} }

@ -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_ */

@ -25,7 +25,7 @@ public:
/** /**
* These are the commands that can be sent to a DeviceHandlerBase * These are the commands that can be sent to a DeviceHandlerBase
*/ */
static const uint8_t MESSAGE_ID = MESSAGE_TYPE::DEVICE_HANDLER_COMMAND; static const uint8_t MESSAGE_ID = messagetypes::DEVICE_HANDLER_COMMAND;
static const Command_t CMD_RAW = MAKE_COMMAND_ID( 1 ); //!< Sends a raw command, setParameter is a ::store_id_t containing the raw packet to send static const Command_t CMD_RAW = MAKE_COMMAND_ID( 1 ); //!< Sends a raw command, setParameter is a ::store_id_t containing the raw packet to send
// static const Command_t CMD_DIRECT = MAKE_COMMAND_ID( 2 ); //!< Sends a direct command, setParameter is a ::DeviceCommandId_t, setParameter2 is a ::store_id_t containing the data needed for the command // static const Command_t CMD_DIRECT = MAKE_COMMAND_ID( 2 ); //!< Sends a direct command, setParameter is a ::DeviceCommandId_t, setParameter2 is a ::store_id_t containing the data needed for the command
static const Command_t CMD_SWITCH_IOBOARD = MAKE_COMMAND_ID( 3 ); //!< Requests a IO-Board switch, setParameter() is the IO-Board identifier static const Command_t CMD_SWITCH_IOBOARD = MAKE_COMMAND_ID( 3 ); //!< Requests a IO-Board switch, setParameter() is the IO-Board identifier

@ -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

@ -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;

@ -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;

@ -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:

@ -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;
}

@ -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_ */

@ -6,7 +6,7 @@
class HealthMessage { class HealthMessage {
public: public:
static const uint8_t MESSAGE_ID = MESSAGE_TYPE::HEALTH_COMMAND; static const uint8_t MESSAGE_ID = messagetypes::HEALTH_COMMAND;
static const Command_t HEALTH_SET = MAKE_COMMAND_ID(1);//REPLY_COMMAND_OK/REPLY_REJECTED static const Command_t HEALTH_SET = MAKE_COMMAND_ID(1);//REPLY_COMMAND_OK/REPLY_REJECTED
static const Command_t HEALTH_ANNOUNCE = MAKE_COMMAND_ID(3); //NO REPLY! static const Command_t HEALTH_ANNOUNCE = MAKE_COMMAND_ID(3); //NO REPLY!
static const Command_t HEALTH_INFO = MAKE_COMMAND_ID(5); static const Command_t HEALTH_INFO = MAKE_COMMAND_ID(5);

@ -15,7 +15,7 @@
#include "../tmstorage/TmStoreMessage.h" #include "../tmstorage/TmStoreMessage.h"
#include "../parameters/ParameterMessage.h" #include "../parameters/ParameterMessage.h"
namespace MESSAGE_TYPE { namespace messagetypes {
void clearMissionMessage(CommandMessage* message); void clearMissionMessage(CommandMessage* message);
} }
@ -67,35 +67,35 @@ void CommandMessage::setParameter2(uint32_t parameter2) {
void CommandMessage::clearCommandMessage() { void CommandMessage::clearCommandMessage() {
switch((getCommand()>>8) & 0xff){ switch((getCommand()>>8) & 0xff){
case MESSAGE_TYPE::MODE_COMMAND: case messagetypes::MODE_COMMAND:
ModeMessage::clear(this); ModeMessage::clear(this);
break; break;
case MESSAGE_TYPE::HEALTH_COMMAND: case messagetypes::HEALTH_COMMAND:
HealthMessage::clear(this); HealthMessage::clear(this);
break; break;
case MESSAGE_TYPE::MODE_SEQUENCE: case messagetypes::MODE_SEQUENCE:
ModeSequenceMessage::clear(this); ModeSequenceMessage::clear(this);
break; break;
case MESSAGE_TYPE::ACTION: case messagetypes::ACTION:
ActionMessage::clear(this); ActionMessage::clear(this);
break; break;
case MESSAGE_TYPE::DEVICE_HANDLER_COMMAND: case messagetypes::DEVICE_HANDLER_COMMAND:
DeviceHandlerMessage::clear(this); DeviceHandlerMessage::clear(this);
break; break;
case MESSAGE_TYPE::MEMORY: case messagetypes::MEMORY:
MemoryMessage::clear(this); MemoryMessage::clear(this);
break; break;
case MESSAGE_TYPE::MONITORING: case messagetypes::MONITORING:
MonitoringMessage::clear(this); MonitoringMessage::clear(this);
break; break;
case MESSAGE_TYPE::TM_STORE: case messagetypes::TM_STORE:
TmStoreMessage::clear(this); TmStoreMessage::clear(this);
break; break;
case MESSAGE_TYPE::PARAMETER: case messagetypes::PARAMETER:
ParameterMessage::clear(this); ParameterMessage::clear(this);
break; break;
default: default:
MESSAGE_TYPE::clearMissionMessage(this); messagetypes::clearMissionMessage(this);
break; break;
} }
} }

@ -23,7 +23,7 @@ public:
static const ReturnValue_t UNKNOWN_COMMAND = MAKE_RETURN_CODE(0x01); static const ReturnValue_t UNKNOWN_COMMAND = MAKE_RETURN_CODE(0x01);
static const uint8_t MESSAGE_ID = MESSAGE_TYPE::COMMAND; static const uint8_t MESSAGE_ID = messagetypes::COMMAND;
static const Command_t CMD_NONE = MAKE_COMMAND_ID( 0 );//!< Used internally, will be ignored static const Command_t CMD_NONE = MAKE_COMMAND_ID( 0 );//!< Used internally, will be ignored
static const Command_t REPLY_COMMAND_OK = MAKE_COMMAND_ID( 3 ); static const Command_t REPLY_COMMAND_OK = MAKE_COMMAND_ID( 3 );
static const Command_t REPLY_REJECTED = MAKE_COMMAND_ID( 0xD1 );//!< Reply indicating that the current command was rejected, par1 should contain the error code static const Command_t REPLY_REJECTED = MAKE_COMMAND_ID( 0xD1 );//!< Reply indicating that the current command was rejected, par1 should contain the error code

@ -1,7 +1,7 @@
#ifndef FRAMEWORK_IPC_FWMESSAGETYPES_H_ #ifndef FRAMEWORK_IPC_FWMESSAGETYPES_H_
#define FRAMEWORK_IPC_FWMESSAGETYPES_H_ #define FRAMEWORK_IPC_FWMESSAGETYPES_H_
namespace MESSAGE_TYPE { namespace messagetypes {
//Remember to add new Message Types to the clearCommandMessage function! //Remember to add new Message Types to the clearCommandMessage function!
enum FW_MESSAGE_TYPE { enum FW_MESSAGE_TYPE {
COMMAND = 0, COMMAND = 0,

@ -9,7 +9,7 @@ class MemoryMessage {
private: private:
MemoryMessage(); //A private ctor inhibits instantiation MemoryMessage(); //A private ctor inhibits instantiation
public: public:
static const uint8_t MESSAGE_ID = MESSAGE_TYPE::MEMORY; static const uint8_t MESSAGE_ID = messagetypes::MEMORY;
static const Command_t CMD_MEMORY_LOAD = MAKE_COMMAND_ID( 0x01 ); static const Command_t CMD_MEMORY_LOAD = MAKE_COMMAND_ID( 0x01 );
static const Command_t CMD_MEMORY_DUMP = MAKE_COMMAND_ID( 0x02 ); static const Command_t CMD_MEMORY_DUMP = MAKE_COMMAND_ID( 0x02 );
static const Command_t CMD_MEMORY_CHECK = MAKE_COMMAND_ID( 0x03 ); static const Command_t CMD_MEMORY_CHECK = MAKE_COMMAND_ID( 0x03 );

@ -17,7 +17,7 @@ class ModeMessage {
private: private:
ModeMessage(); ModeMessage();
public: public:
static const uint8_t MESSAGE_ID = MESSAGE_TYPE::MODE_COMMAND; static const uint8_t MESSAGE_ID = messagetypes::MODE_COMMAND;
static const Command_t CMD_MODE_COMMAND = MAKE_COMMAND_ID(0x01);//!> Command to set the specified Mode, replies are: REPLY_MODE_REPLY, REPLY_WRONG_MODE_REPLY, and REPLY_REJECTED; don't add any replies, as this will break the subsystem mode machine!! static const Command_t CMD_MODE_COMMAND = MAKE_COMMAND_ID(0x01);//!> Command to set the specified Mode, replies are: REPLY_MODE_REPLY, REPLY_WRONG_MODE_REPLY, and REPLY_REJECTED; don't add any replies, as this will break the subsystem mode machine!!
static const Command_t CMD_MODE_COMMAND_FORCED = MAKE_COMMAND_ID(0xF1);//!> Command to set the specified Mode, regardless of external control flag, replies are: REPLY_MODE_REPLY, REPLY_WRONG_MODE_REPLY, and REPLY_REJECTED; don't add any replies, as this will break the subsystem mode machine!! static const Command_t CMD_MODE_COMMAND_FORCED = MAKE_COMMAND_ID(0xF1);//!> Command to set the specified Mode, regardless of external control flag, replies are: REPLY_MODE_REPLY, REPLY_WRONG_MODE_REPLY, and REPLY_REJECTED; don't add any replies, as this will break the subsystem mode machine!!
static const Command_t REPLY_MODE_REPLY = MAKE_COMMAND_ID(0x02);//!> Reply to a CMD_MODE_COMMAND or CMD_MODE_READ static const Command_t REPLY_MODE_REPLY = MAKE_COMMAND_ID(0x02);//!> Reply to a CMD_MODE_COMMAND or CMD_MODE_READ

@ -6,7 +6,7 @@
class MonitoringMessage: public CommandMessage { class MonitoringMessage: public CommandMessage {
public: public:
static const uint8_t MESSAGE_ID = MESSAGE_TYPE::MONITORING; static const uint8_t MESSAGE_ID = messagetypes::MONITORING;
//Object id could be useful, but we better manage that on service level (register potential reporters). //Object id could be useful, but we better manage that on service level (register potential reporters).
static const Command_t LIMIT_VIOLATION_REPORT = MAKE_COMMAND_ID(10); static const Command_t LIMIT_VIOLATION_REPORT = MAKE_COMMAND_ID(10);
virtual ~MonitoringMessage(); virtual ~MonitoringMessage();

@ -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;

@ -0,0 +1,95 @@
#include "../../osal/FreeRTOS/BinSemaphUsingTask.h"
#include "../../osal/FreeRTOS/TaskManagement.h"
#include "../../serviceinterface/ServiceInterfaceStream.h"
BinarySemaphoreUsingTask::BinarySemaphoreUsingTask() {
handle = TaskManagement::getCurrentTaskHandle();
if(handle == nullptr) {
sif::error << "Could not retrieve task handle. Please ensure the"
"constructor was called inside a task." << std::endl;
}
xTaskNotifyGive(handle);
}
BinarySemaphoreUsingTask::~BinarySemaphoreUsingTask() {
// Clear notification value on destruction.
xTaskNotifyAndQuery(handle, 0, eSetValueWithOverwrite, nullptr);
}
ReturnValue_t BinarySemaphoreUsingTask::acquire(TimeoutType timeoutType,
uint32_t timeoutMs) {
TickType_t timeout = 0;
if(timeoutType == TimeoutType::POLLING) {
timeout = 0;
}
else if(timeoutType == TimeoutType::WAITING){
timeout = pdMS_TO_TICKS(timeoutMs);
}
else {
timeout = portMAX_DELAY;
}
return acquireWithTickTimeout(timeoutType, timeout);
}
ReturnValue_t BinarySemaphoreUsingTask::acquireWithTickTimeout(
TimeoutType timeoutType, TickType_t timeoutTicks) {
BaseType_t returncode = ulTaskNotifyTake(pdTRUE, timeoutTicks);
if (returncode == pdPASS) {
return HasReturnvaluesIF::RETURN_OK;
}
else {
return SemaphoreIF::SEMAPHORE_TIMEOUT;
}
}
ReturnValue_t BinarySemaphoreUsingTask::release() {
return release(this->handle);
}
ReturnValue_t BinarySemaphoreUsingTask::release(
TaskHandle_t taskHandle) {
if(getSemaphoreCounter(taskHandle) == 1) {
return SemaphoreIF::SEMAPHORE_NOT_OWNED;
}
BaseType_t returncode = xTaskNotifyGive(taskHandle);
if (returncode == pdPASS) {
return HasReturnvaluesIF::RETURN_OK;
}
else {
// This should never happen.
return HasReturnvaluesIF::RETURN_FAILED;
}
}
TaskHandle_t BinarySemaphoreUsingTask::getTaskHandle() {
return handle;
}
uint8_t BinarySemaphoreUsingTask::getSemaphoreCounter() const {
return getSemaphoreCounter(this->handle);
}
uint8_t BinarySemaphoreUsingTask::getSemaphoreCounter(
TaskHandle_t taskHandle) {
uint32_t notificationValue;
xTaskNotifyAndQuery(taskHandle, 0, eNoAction, &notificationValue);
return notificationValue;
}
// Be careful with the stack size here. This is called from an ISR!
ReturnValue_t BinarySemaphoreUsingTask::releaseFromISR(
TaskHandle_t taskHandle, BaseType_t * higherPriorityTaskWoken) {
if(getSemaphoreCounterFromISR(taskHandle, higherPriorityTaskWoken) == 1) {
return SemaphoreIF::SEMAPHORE_NOT_OWNED;
}
vTaskNotifyGiveFromISR(taskHandle, higherPriorityTaskWoken);
return HasReturnvaluesIF::RETURN_OK;
}
uint8_t BinarySemaphoreUsingTask::getSemaphoreCounterFromISR(
TaskHandle_t taskHandle, BaseType_t* higherPriorityTaskWoken) {
uint32_t notificationValue = 0;
xTaskNotifyAndQueryFromISR(taskHandle, 0, eNoAction, &notificationValue,
higherPriorityTaskWoken);
return notificationValue;
}

@ -0,0 +1,76 @@
#ifndef FRAMEWORK_OSAL_FREERTOS_BINSEMAPHUSINGTASK_H_
#define FRAMEWORK_OSAL_FREERTOS_BINSEMAPHUSINGTASK_H_
#include "../../returnvalues/HasReturnvaluesIF.h"
#include "../../tasks/SemaphoreIF.h"
#include <freertos/FreeRTOS.h>
#include <freertos/task.h>
/**
* @brief Binary Semaphore implementation using the task notification value.
* The notification value should therefore not be used
* for other purposes.
* @details
* Additional information: https://www.freertos.org/RTOS-task-notifications.html
* and general semaphore documentation.
*/
class BinarySemaphoreUsingTask: public SemaphoreIF,
public HasReturnvaluesIF {
public:
static const uint8_t INTERFACE_ID = CLASS_ID::SEMAPHORE_IF;
//! @brief Default ctor
BinarySemaphoreUsingTask();
//! @brief Default dtor
virtual~ BinarySemaphoreUsingTask();
ReturnValue_t acquire(TimeoutType timeoutType = TimeoutType::BLOCKING,
uint32_t timeoutMs = portMAX_DELAY) override;
ReturnValue_t release() override;
uint8_t getSemaphoreCounter() const override;
static uint8_t getSemaphoreCounter(TaskHandle_t taskHandle);
static uint8_t getSemaphoreCounterFromISR(TaskHandle_t taskHandle,
BaseType_t* higherPriorityTaskWoken);
/**
* Same as acquire() with timeout in FreeRTOS ticks.
* @param timeoutTicks
* @return - @c RETURN_OK on success
* - @c RETURN_FAILED on failure
*/
ReturnValue_t acquireWithTickTimeout(
TimeoutType timeoutType = TimeoutType::BLOCKING,
TickType_t timeoutTicks = portMAX_DELAY);
/**
* Get handle to the task related to the semaphore.
* @return
*/
TaskHandle_t getTaskHandle();
/**
* Wrapper function to give back semaphore from handle
* @param semaphore
* @return - @c RETURN_OK on success
* - @c RETURN_FAILED on failure
*/
static ReturnValue_t release(TaskHandle_t taskToNotify);
/**
* Wrapper function to give back semaphore from handle when called from an ISR
* @param semaphore
* @param higherPriorityTaskWoken This will be set to pdPASS if a task with
* a higher priority was unblocked. A context switch should be requested
* from an ISR if this is the case (see TaskManagement functions)
* @return - @c RETURN_OK on success
* - @c RETURN_FAILED on failure
*/
static ReturnValue_t releaseFromISR(TaskHandle_t taskToNotify,
BaseType_t * higherPriorityTaskWoken);
protected:
TaskHandle_t handle;
};
#endif /* FRAMEWORK_OSAL_FREERTOS_BINSEMAPHUSINGTASK_H_ */

@ -0,0 +1,108 @@
#include "../../osal/FreeRTOS/BinarySemaphore.h"
#include "../../osal/FreeRTOS/TaskManagement.h"
#include "../../serviceinterface/ServiceInterfaceStream.h"
BinarySemaphore::BinarySemaphore() {
handle = xSemaphoreCreateBinary();
if(handle == nullptr) {
sif::error << "Semaphore: Binary semaph creation failure" << std::endl;
}
// Initiated semaphore must be given before it can be taken.
xSemaphoreGive(handle);
}
BinarySemaphore::~BinarySemaphore() {
vSemaphoreDelete(handle);
}
BinarySemaphore::BinarySemaphore(BinarySemaphore&& s) {
handle = xSemaphoreCreateBinary();
if(handle == nullptr) {
sif::error << "Binary semaphore creation failure" << std::endl;
}
xSemaphoreGive(handle);
}
BinarySemaphore& BinarySemaphore::operator =(
BinarySemaphore&& s) {
if(&s != this) {
handle = xSemaphoreCreateBinary();
if(handle == nullptr) {
sif::error << "Binary semaphore creation failure" << std::endl;
}
xSemaphoreGive(handle);
}
return *this;
}
ReturnValue_t BinarySemaphore::acquire(TimeoutType timeoutType,
uint32_t timeoutMs) {
TickType_t timeout = 0;
if(timeoutType == TimeoutType::POLLING) {
timeout = 0;
}
else if(timeoutType == TimeoutType::WAITING){
timeout = pdMS_TO_TICKS(timeoutMs);
}
else {
timeout = portMAX_DELAY;
}
return acquireWithTickTimeout(timeoutType, timeout);
}
ReturnValue_t BinarySemaphore::acquireWithTickTimeout(TimeoutType timeoutType,
TickType_t timeoutTicks) {
if(handle == nullptr) {
return SemaphoreIF::SEMAPHORE_INVALID;
}
BaseType_t returncode = xSemaphoreTake(handle, timeoutTicks);
if (returncode == pdPASS) {
return HasReturnvaluesIF::RETURN_OK;
}
else {
return SemaphoreIF::SEMAPHORE_TIMEOUT;
}
}
ReturnValue_t BinarySemaphore::release() {
return release(handle);
}
ReturnValue_t BinarySemaphore::release(SemaphoreHandle_t semaphore) {
if (semaphore == nullptr) {
return SemaphoreIF::SEMAPHORE_INVALID;
}
BaseType_t returncode = xSemaphoreGive(semaphore);
if (returncode == pdPASS) {
return HasReturnvaluesIF::RETURN_OK;
}
else {
return SemaphoreIF::SEMAPHORE_NOT_OWNED;
}
}
uint8_t BinarySemaphore::getSemaphoreCounter() const {
return uxSemaphoreGetCount(handle);
}
SemaphoreHandle_t BinarySemaphore::getSemaphore() {
return handle;
}
// Be careful with the stack size here. This is called from an ISR!
ReturnValue_t BinarySemaphore::releaseFromISR(
SemaphoreHandle_t semaphore, BaseType_t * higherPriorityTaskWoken) {
if (semaphore == nullptr) {
return SemaphoreIF::SEMAPHORE_INVALID;
}
BaseType_t returncode = xSemaphoreGiveFromISR(semaphore,
higherPriorityTaskWoken);
if (returncode == pdPASS) {
return HasReturnvaluesIF::RETURN_OK;
}
else {
return SemaphoreIF::SEMAPHORE_NOT_OWNED;
}
}

@ -0,0 +1,107 @@
#ifndef FRAMEWORK_OSAL_FREERTOS_BINARYSEMPAHORE_H_
#define FRAMEWORK_OSAL_FREERTOS_BINARYSEMPAHORE_H_
#include "../../returnvalues/HasReturnvaluesIF.h"
#include "../../tasks/SemaphoreIF.h"
#include <freertos/FreeRTOS.h>
#include <freertos/semphr.h>
/**
* @brief OS Tool to achieve synchronization of between tasks or between
* task and ISR. The default semaphore implementation creates a
* binary semaphore, which can only be taken once.
* @details
* Documentation: https://www.freertos.org/Embedded-RTOS-Binary-Semaphores.html
*
* Please note that if the semaphore implementation is only related to
* the synchronization of one task, the new task notifications can be used,
* also see the BinSemaphUsingTask and CountingSemaphUsingTask classes.
* These use the task notification value instead of a queue and are
* faster and more efficient.
*
* @author R. Mueller
* @ingroup osal
*/
class BinarySemaphore: public SemaphoreIF,
public HasReturnvaluesIF {
public:
static const uint8_t INTERFACE_ID = CLASS_ID::SEMAPHORE_IF;
//! @brief Default ctor
BinarySemaphore();
//! @brief Copy ctor, deleted explicitely.
BinarySemaphore(const BinarySemaphore&) = delete;
//! @brief Copy assignment, deleted explicitely.
BinarySemaphore& operator=(const BinarySemaphore&) = delete;
//! @brief Move ctor
BinarySemaphore (BinarySemaphore &&);
//! @brief Move assignment
BinarySemaphore & operator=(BinarySemaphore &&);
//! @brief Destructor
virtual ~BinarySemaphore();
uint8_t getSemaphoreCounter() const override;
/**
* Take the binary semaphore.
* If the semaphore has already been taken, the task will be blocked
* for a maximum of #timeoutMs or until the semaphore is given back,
* for example by an ISR or another task.
* @param timeoutMs
* @return -@c RETURN_OK on success
* -@c SemaphoreIF::SEMAPHORE_TIMEOUT on timeout
*/
ReturnValue_t acquire(TimeoutType timeoutType =
TimeoutType::BLOCKING, uint32_t timeoutMs = portMAX_DELAY) override;
/**
* Same as lockBinarySemaphore() with timeout in FreeRTOS ticks.
* @param timeoutTicks
* @return -@c RETURN_OK on success
* -@c SemaphoreIF::SEMAPHORE_TIMEOUT on timeout
*/
ReturnValue_t acquireWithTickTimeout(TimeoutType timeoutType =
TimeoutType::BLOCKING, TickType_t timeoutTicks = portMAX_DELAY);
/**
* Release the binary semaphore.
* @return -@c RETURN_OK on success
* -@c SemaphoreIF::SEMAPHORE_NOT_OWNED if the semaphores is
* already available.
*/
ReturnValue_t release() override;
/**
* Get Handle to the semaphore.
* @return
*/
SemaphoreHandle_t getSemaphore();
/**
* Wrapper function to give back semaphore from handle
* @param semaphore
* @return -@c RETURN_OK on success
* -@c SemaphoreIF::SEMAPHORE_NOT_OWNED if the semaphores is
* already available.
*/
static ReturnValue_t release(SemaphoreHandle_t semaphore);
/**
* Wrapper function to give back semaphore from handle when called from an ISR
* @param semaphore
* @param higherPriorityTaskWoken This will be set to pdPASS if a task with
* a higher priority was unblocked. A context switch from an ISR should
* then be requested (see TaskManagement functions)
* @return -@c RETURN_OK on success
* -@c SemaphoreIF::SEMAPHORE_NOT_OWNED if the semaphores is
* already available.
*/
static ReturnValue_t releaseFromISR(SemaphoreHandle_t semaphore,
BaseType_t * higherPriorityTaskWoken);
protected:
SemaphoreHandle_t handle;
};
#endif /* FRAMEWORK_OSAL_FREERTOS_BINARYSEMPAHORE_H_ */

@ -0,0 +1,114 @@
#include "../../osal/FreeRTOS/CountingSemaphUsingTask.h"
#include "../../osal/FreeRTOS/TaskManagement.h"
#include "../../serviceinterface/ServiceInterfaceStream.h"
CountingSemaphoreUsingTask::CountingSemaphoreUsingTask(const uint8_t maxCount,
uint8_t initCount): maxCount(maxCount) {
if(initCount > maxCount) {
sif::error << "CountingSemaphoreUsingTask: Max count bigger than "
"intial cout. Setting initial count to max count." << std::endl;
initCount = maxCount;
}
handle = TaskManagement::getCurrentTaskHandle();
if(handle == nullptr) {
sif::error << "CountingSemaphoreUsingTask: Could not retrieve task "
"handle. Please ensure the constructor was called inside a "
"task." << std::endl;
}
uint32_t oldNotificationValue;
xTaskNotifyAndQuery(handle, 0, eSetValueWithOverwrite,
&oldNotificationValue);
if(oldNotificationValue != 0) {
sif::warning << "CountinSemaphoreUsingTask: Semaphore initiated but "
"current notification value is not 0. Please ensure the "
"notification value is not used for other purposes!" << std::endl;
}
for(int i = 0; i < initCount; i++) {
xTaskNotifyGive(handle);
}
}
CountingSemaphoreUsingTask::~CountingSemaphoreUsingTask() {
// Clear notification value on destruction.
// If this is not desired, don't call the destructor
// (or implement a boolean which disables the reset)
xTaskNotifyAndQuery(handle, 0, eSetValueWithOverwrite, nullptr);
}
ReturnValue_t CountingSemaphoreUsingTask::acquire(TimeoutType timeoutType,
uint32_t timeoutMs) {
TickType_t timeout = 0;
if(timeoutType == TimeoutType::POLLING) {
timeout = 0;
}
else if(timeoutType == TimeoutType::WAITING){
timeout = pdMS_TO_TICKS(timeoutMs);
}
else {
timeout = portMAX_DELAY;
}
return acquireWithTickTimeout(timeoutType, timeout);
}
ReturnValue_t CountingSemaphoreUsingTask::acquireWithTickTimeout(
TimeoutType timeoutType, TickType_t timeoutTicks) {
// Decrement notfication value without resetting it.
BaseType_t oldCount = ulTaskNotifyTake(pdFALSE, timeoutTicks);
if (getSemaphoreCounter() == oldCount - 1) {
return HasReturnvaluesIF::RETURN_OK;
}
else {
return SemaphoreIF::SEMAPHORE_TIMEOUT;
}
}
ReturnValue_t CountingSemaphoreUsingTask::release() {
if(getSemaphoreCounter() == maxCount) {
return SemaphoreIF::SEMAPHORE_NOT_OWNED;
}
return release(handle);
}
ReturnValue_t CountingSemaphoreUsingTask::release(
TaskHandle_t taskToNotify) {
BaseType_t returncode = xTaskNotifyGive(taskToNotify);
if (returncode == pdPASS) {
return HasReturnvaluesIF::RETURN_OK;
}
else {
// This should never happen.
return HasReturnvaluesIF::RETURN_FAILED;
}
}
uint8_t CountingSemaphoreUsingTask::getSemaphoreCounter() const {
uint32_t notificationValue = 0;
xTaskNotifyAndQuery(handle, 0, eNoAction, &notificationValue);
return notificationValue;
}
TaskHandle_t CountingSemaphoreUsingTask::getTaskHandle() {
return handle;
}
ReturnValue_t CountingSemaphoreUsingTask::releaseFromISR(
TaskHandle_t taskToNotify, BaseType_t* higherPriorityTaskWoken) {
vTaskNotifyGiveFromISR(taskToNotify, higherPriorityTaskWoken);
return HasReturnvaluesIF::RETURN_OK;
}
uint8_t CountingSemaphoreUsingTask::getSemaphoreCounterFromISR(
TaskHandle_t task, BaseType_t* higherPriorityTaskWoken) {
uint32_t notificationValue;
xTaskNotifyAndQueryFromISR(task, 0, eNoAction, &notificationValue,
higherPriorityTaskWoken);
return notificationValue;
}
uint8_t CountingSemaphoreUsingTask::getMaxCount() const {
return maxCount;
}

@ -0,0 +1,102 @@
#ifndef FRAMEWORK_OSAL_FREERTOS_COUNTINGSEMAPHUSINGTASK_H_
#define FRAMEWORK_OSAL_FREERTOS_COUNTINGSEMAPHUSINGTASK_H_
#include "../../osal/FreeRTOS/CountingSemaphUsingTask.h"
#include "../../tasks/SemaphoreIF.h"
extern "C" {
#include <freertos/FreeRTOS.h>
#include <freertos/task.h>
}
/**
* @brief Couting Semaphore implementation which uses the notification value
* of the task. The notification value should therefore not be used
* for other purposes.
* @details
* Additional information: https://www.freertos.org/RTOS-task-notifications.html
* and general semaphore documentation.
*/
class CountingSemaphoreUsingTask: public SemaphoreIF {
public:
CountingSemaphoreUsingTask(const uint8_t maxCount, uint8_t initCount);
virtual ~CountingSemaphoreUsingTask();
/**
* Acquire the counting semaphore.
* If no semaphores are available, the task will be blocked
* for a maximum of #timeoutMs or until one is given back,
* for example by an ISR or another task.
* @param timeoutMs
* @return -@c RETURN_OK on success
* -@c SemaphoreIF::SEMAPHORE_TIMEOUT on timeout
*/
ReturnValue_t acquire(TimeoutType timeoutType = TimeoutType::BLOCKING,
uint32_t timeoutMs = portMAX_DELAY) override;
/**
* Release a semaphore, increasing the number of available counting
* semaphores up to the #maxCount value.
* @return -@c RETURN_OK on success
* -@c SemaphoreIF::SEMAPHORE_NOT_OWNED if #maxCount semaphores are
* already available.
*/
ReturnValue_t release() override;
uint8_t getSemaphoreCounter() const override;
/**
* Get the semaphore counter from an ISR.
* @param task
* @param higherPriorityTaskWoken This will be set to pdPASS if a task with
* a higher priority was unblocked. A context switch should be requested
* from an ISR if this is the case (see TaskManagement functions)
* @return
*/
static uint8_t getSemaphoreCounterFromISR(TaskHandle_t task,
BaseType_t* higherPriorityTaskWoken);
/**
* Acquire with a timeout value in ticks
* @param timeoutTicks
* @return -@c RETURN_OK on success
* -@c SemaphoreIF::SEMAPHORE_TIMEOUT on timeout
*/
ReturnValue_t acquireWithTickTimeout(
TimeoutType timeoutType = TimeoutType::BLOCKING,
TickType_t timeoutTicks = portMAX_DELAY);
/**
* Get handle to the task related to the semaphore.
* @return
*/
TaskHandle_t getTaskHandle();
/**
* Release semaphore of task by supplying task handle
* @param taskToNotify
* @return -@c RETURN_OK on success
* -@c SemaphoreIF::SEMAPHORE_NOT_OWNED if #maxCount semaphores are
* already available.
*/
static ReturnValue_t release(TaskHandle_t taskToNotify);
/**
* Release seamphore of a task from an ISR.
* @param taskToNotify
* @param higherPriorityTaskWoken This will be set to pdPASS if a task with
* a higher priority was unblocked. A context switch should be requested
* from an ISR if this is the case (see TaskManagement functions)
* @return -@c RETURN_OK on success
* -@c SemaphoreIF::SEMAPHORE_NOT_OWNED if #maxCount semaphores are
* already available.
*/
static ReturnValue_t releaseFromISR(TaskHandle_t taskToNotify,
BaseType_t* higherPriorityTaskWoken);
uint8_t getMaxCount() const;
private:
TaskHandle_t handle;
const uint8_t maxCount;
};
#endif /* FRAMEWORK_OSAL_FREERTOS_COUNTINGSEMAPHUSINGTASK_H_ */

@ -0,0 +1,43 @@
#include "../../osal/FreeRTOS/CountingSemaphore.h"
#include "../../serviceinterface/ServiceInterfaceStream.h"
#include "../../osal/FreeRTOS/TaskManagement.h"
#include <freertos/semphr.h>
// Make sure #define configUSE_COUNTING_SEMAPHORES 1 is set in
// free FreeRTOSConfig.h file.
CountingSemaphore::CountingSemaphore(const uint8_t maxCount, uint8_t initCount):
maxCount(maxCount), initCount(initCount) {
if(initCount > maxCount) {
sif::error << "CountingSemaphoreUsingTask: Max count bigger than "
"intial cout. Setting initial count to max count." << std::endl;
initCount = maxCount;
}
handle = xSemaphoreCreateCounting(maxCount, initCount);
if(handle == nullptr) {
sif::error << "CountingSemaphore: Creation failure" << std::endl;
}
}
CountingSemaphore::CountingSemaphore(CountingSemaphore&& other):
maxCount(other.maxCount), initCount(other.initCount) {
handle = xSemaphoreCreateCounting(other.maxCount, other.initCount);
if(handle == nullptr) {
sif::error << "CountingSemaphore: Creation failure" << std::endl;
}
}
CountingSemaphore& CountingSemaphore::operator =(
CountingSemaphore&& other) {
handle = xSemaphoreCreateCounting(other.maxCount, other.initCount);
if(handle == nullptr) {
sif::error << "CountingSemaphore: Creation failure" << std::endl;
}
return * this;
}
uint8_t CountingSemaphore::getMaxCount() const {
return maxCount;
}

@ -0,0 +1,34 @@
#ifndef FRAMEWORK_OSAL_FREERTOS_COUNTINGSEMAPHORE_H_
#define FRAMEWORK_OSAL_FREERTOS_COUNTINGSEMAPHORE_H_
#include "../../osal/FreeRTOS/BinarySemaphore.h"
/**
* @brief Counting semaphores, which can be acquire more than once.
* @details
* See: https://www.freertos.org/CreateCounting.html
* API of counting semaphores is almost identical to binary semaphores,
* so we just inherit from binary semaphore and provide the respective
* constructors.
*/
class CountingSemaphore: public BinarySemaphore {
public:
CountingSemaphore(const uint8_t maxCount, uint8_t initCount);
//! @brief Copy ctor, disabled
CountingSemaphore(const CountingSemaphore&) = delete;
//! @brief Copy assignment, disabled
CountingSemaphore& operator=(const CountingSemaphore&) = delete;
//! @brief Move ctor
CountingSemaphore (CountingSemaphore &&);
//! @brief Move assignment
CountingSemaphore & operator=(CountingSemaphore &&);
/* Same API as binary semaphore otherwise. acquire() can be called
* until there are not semaphores left and release() can be called
* until maxCount is reached. */
uint8_t getMaxCount() const;
private:
const uint8_t maxCount;
uint8_t initCount = 0;
};
#endif /* FRAMEWORK_OSAL_FREERTOS_COUNTINGSEMAPHORE_H_ */

@ -5,11 +5,12 @@
uint32_t FixedTimeslotTask::deadlineMissedCount = 0; uint32_t FixedTimeslotTask::deadlineMissedCount = 0;
const size_t PeriodicTaskIF::MINIMUM_STACK_SIZE = configMINIMAL_STACK_SIZE; const size_t PeriodicTaskIF::MINIMUM_STACK_SIZE = configMINIMAL_STACK_SIZE;
FixedTimeslotTask::FixedTimeslotTask(const char *name, TaskPriority setPriority, FixedTimeslotTask::FixedTimeslotTask(TaskName name, TaskPriority setPriority,
TaskStackSize setStack, TaskPeriod overallPeriod, TaskStackSize setStack, TaskPeriod overallPeriod,
void (*setDeadlineMissedFunc)()) : void (*setDeadlineMissedFunc)()) :
started(false), handle(NULL), pst(overallPeriod * 1000) { started(false), handle(NULL), pst(overallPeriod * 1000) {
xTaskCreate(taskEntryPoint, name, setStack, this, setPriority, &handle); configSTACK_DEPTH_TYPE stackSize = setStack / sizeof(configSTACK_DEPTH_TYPE);
xTaskCreate(taskEntryPoint, name, stackSize, this, setPriority, &handle);
// All additional attributes are applied to the object. // All additional attributes are applied to the object.
this->deadlineMissedFunc = setDeadlineMissedFunc; this->deadlineMissedFunc = setDeadlineMissedFunc;
} }
@ -82,7 +83,7 @@ ReturnValue_t FixedTimeslotTask::checkSequence() const {
void FixedTimeslotTask::taskFunctionality() { void FixedTimeslotTask::taskFunctionality() {
// A local iterator for the Polling Sequence Table is created to find the // A local iterator for the Polling Sequence Table is created to find the
// start time for the first entry. // start time for the first entry.
FixedSlotSequence::SlotListIter slotListIter = pst.current; auto slotListIter = pst.current;
//The start time for the first entry is read. //The start time for the first entry is read.
uint32_t intervalMs = slotListIter->pollingTimeMs; uint32_t intervalMs = slotListIter->pollingTimeMs;
@ -155,3 +156,7 @@ ReturnValue_t FixedTimeslotTask::sleepFor(uint32_t ms) {
vTaskDelay(pdMS_TO_TICKS(ms)); vTaskDelay(pdMS_TO_TICKS(ms));
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
} }
TaskHandle_t FixedTimeslotTask::getTaskHandle() {
return handle;
}

@ -1,14 +1,16 @@
#ifndef FRAMEWORK_OSAL_FREERTOS_FIXEDTIMESLOTTASK_H_ #ifndef FRAMEWORK_OSAL_FREERTOS_FIXEDTIMESLOTTASK_H_
#define FRAMEWORK_OSAL_FREERTOS_FIXEDTIMESLOTTASK_H_ #define FRAMEWORK_OSAL_FREERTOS_FIXEDTIMESLOTTASK_H_
#include "FreeRTOSTaskIF.h"
#include "../../devicehandlers/FixedSlotSequence.h" #include "../../devicehandlers/FixedSlotSequence.h"
#include "../../tasks/FixedTimeslotTaskIF.h" #include "../../tasks/FixedTimeslotTaskIF.h"
#include "../../tasks/Typedef.h" #include "../../tasks/Typedef.h"
#include <freertos/FreeRTOS.h> #include <freertos/FreeRTOS.h>
#include <freertos/task.h> #include <freertos/task.h>
class FixedTimeslotTask: public FixedTimeslotTaskIF { class FixedTimeslotTask: public FixedTimeslotTaskIF, public FreeRTOSTaskIF {
public: public:
/** /**
@ -23,7 +25,7 @@ public:
* @param setDeadlineMissedFunc Callback if a deadline was missed. * @param setDeadlineMissedFunc Callback if a deadline was missed.
* @return Pointer to the newly created task. * @return Pointer to the newly created task.
*/ */
FixedTimeslotTask(const char *name, TaskPriority setPriority, FixedTimeslotTask(TaskName name, TaskPriority setPriority,
TaskStackSize setStack, TaskPeriod overallPeriod, TaskStackSize setStack, TaskPeriod overallPeriod,
void (*setDeadlineMissedFunc)()); void (*setDeadlineMissedFunc)());
@ -57,6 +59,8 @@ public:
ReturnValue_t sleepFor(uint32_t ms) override; ReturnValue_t sleepFor(uint32_t ms) override;
TaskHandle_t getTaskHandle() override;
protected: protected:
bool started; bool started;
TaskHandle_t handle; TaskHandle_t handle;

@ -0,0 +1,13 @@
#ifndef FRAMEWORK_OSAL_FREERTOS_FREERTOSTASKIF_H_
#define FRAMEWORK_OSAL_FREERTOS_FREERTOSTASKIF_H_
#include <freertos/FreeRTOS.h>
#include <freertos/task.h>
class FreeRTOSTaskIF {
public:
virtual~ FreeRTOSTaskIF() {}
virtual TaskHandle_t getTaskHandle() = 0;
};
#endif /* FRAMEWORK_OSAL_FREERTOS_FREERTOSTASKIF_H_ */

@ -1,4 +1,4 @@
#include <framework/osal/FreeRTOS/Mutex.h> #include "Mutex.h"
#include "../../serviceinterface/ServiceInterfaceStream.h" #include "../../serviceinterface/ServiceInterfaceStream.h"

@ -5,12 +5,13 @@
PeriodicTask::PeriodicTask(const char *name, TaskPriority setPriority, PeriodicTask::PeriodicTask(const char *name, TaskPriority setPriority,
TaskStackSize setStack, TaskPeriod setPeriod, TaskStackSize setStack, TaskPeriod setPeriod,
void (*setDeadlineMissedFunc)()) : TaskDeadlineMissedFunction deadlineMissedFunc) :
started(false), handle(NULL), period(setPeriod), deadlineMissedFunc( started(false), handle(NULL), period(setPeriod), deadlineMissedFunc(
setDeadlineMissedFunc) deadlineMissedFunc)
{ {
configSTACK_DEPTH_TYPE stackSize = setStack / sizeof(configSTACK_DEPTH_TYPE);
BaseType_t status = xTaskCreate(taskEntryPoint, name, BaseType_t status = xTaskCreate(taskEntryPoint, name,
setStack, this, setPriority, &handle); stackSize, this, setPriority, &handle);
if(status != pdPASS){ if(status != pdPASS){
sif::debug << "PeriodicTask Insufficient heap memory remaining. " sif::debug << "PeriodicTask Insufficient heap memory remaining. "
"Status: " << status << std::endl; "Status: " << status << std::endl;
@ -86,12 +87,12 @@ ReturnValue_t PeriodicTask::addComponent(object_id_t object) {
object); object);
if (newObject == nullptr) { if (newObject == nullptr) {
sif::error << "PeriodicTask::addComponent: Invalid object. Make sure" sif::error << "PeriodicTask::addComponent: Invalid object. Make sure"
"it implements ExecutableObjectIF!" << std::endl; "it implement ExecutableObjectIF" << std::endl;
return HasReturnvaluesIF::RETURN_FAILED; return HasReturnvaluesIF::RETURN_FAILED;
} }
objectList.push_back(newObject); objectList.push_back(newObject);
newObject->setTaskIF(this); newObject->setTaskIF(this);
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
} }
@ -122,6 +123,10 @@ void PeriodicTask::checkMissedDeadline(const TickType_t xLastWakeTime,
} }
} }
TaskHandle_t PeriodicTask::getTaskHandle() {
return handle;
}
void PeriodicTask::handleMissedDeadline() { void PeriodicTask::handleMissedDeadline() {
#ifdef DEBUG #ifdef DEBUG
sif::warning << "PeriodicTask: " << pcTaskGetName(NULL) << sif::warning << "PeriodicTask: " << pcTaskGetName(NULL) <<

@ -4,6 +4,8 @@
#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>
@ -17,7 +19,7 @@ class ExecutableObjectIF;
* periodic activities of multiple objects. * periodic activities of multiple objects.
* @ingroup task_handling * @ingroup task_handling
*/ */
class PeriodicTask: public PeriodicTaskIF { class PeriodicTask: public PeriodicTaskIF, public FreeRTOSTaskIF {
public: public:
/** /**
* Keep in Mind that you need to call before this vTaskStartScheduler()! * Keep in Mind that you need to call before this vTaskStartScheduler()!
@ -38,9 +40,9 @@ public:
* The function pointer to the deadline missed function that shall * The function pointer to the deadline missed function that shall
* be assigned. * be assigned.
*/ */
PeriodicTask(const char *name, TaskPriority setPriority, PeriodicTask(TaskName name, TaskPriority setPriority,
TaskStackSize setStack, TaskPeriod setPeriod, TaskStackSize setStack, TaskPeriod setPeriod,
void (*setDeadlineMissedFunc)()); TaskDeadlineMissedFunction deadlineMissedFunc);
/** /**
* @brief Currently, the executed object's lifetime is not coupled with * @brief Currently, the executed object's lifetime is not coupled with
* the task object's lifetime, so the destructor is empty. * the task object's lifetime, so the destructor is empty.
@ -68,6 +70,8 @@ public:
uint32_t getPeriodMs() const override; uint32_t getPeriodMs() const override;
ReturnValue_t sleepFor(uint32_t ms) override; ReturnValue_t sleepFor(uint32_t ms) override;
TaskHandle_t getTaskHandle() override;
protected: protected:
bool started; bool started;
TaskHandle_t handle; TaskHandle_t handle;

@ -0,0 +1,59 @@
#include "../../osal/FreeRTOS/BinarySemaphore.h"
#include "../../osal/FreeRTOS/BinSemaphUsingTask.h"
#include "../../osal/FreeRTOS/CountingSemaphore.h"
#include "../../osal/FreeRTOS/CountingSemaphUsingTask.h"
#include "../../tasks/SemaphoreFactory.h"
#include "../../serviceinterface/ServiceInterfaceStream.h"
SemaphoreFactory* SemaphoreFactory::factoryInstance = nullptr;
static const uint32_t USE_REGULAR_SEMAPHORES = 0;
static const uint32_t USE_TASK_NOTIFICATIONS = 1;
SemaphoreFactory::SemaphoreFactory() {
}
SemaphoreFactory::~SemaphoreFactory() {
delete factoryInstance;
}
SemaphoreFactory* SemaphoreFactory::instance() {
if (factoryInstance == nullptr){
factoryInstance = new SemaphoreFactory();
}
return SemaphoreFactory::factoryInstance;
}
SemaphoreIF* SemaphoreFactory::createBinarySemaphore(uint32_t argument) {
if(argument == USE_REGULAR_SEMAPHORES) {
return new BinarySemaphore();
}
else if(argument == USE_TASK_NOTIFICATIONS) {
return new BinarySemaphoreUsingTask();
}
else {
sif::warning << "SemaphoreFactory: Invalid argument, return regular"
"binary semaphore" << std::endl;
return new BinarySemaphore();
}
}
SemaphoreIF* SemaphoreFactory::createCountingSemaphore(uint8_t maxCount,
uint8_t initCount, uint32_t argument) {
if(argument == USE_REGULAR_SEMAPHORES) {
return new CountingSemaphore(maxCount, initCount);
}
else if(argument == USE_TASK_NOTIFICATIONS) {
return new CountingSemaphoreUsingTask(maxCount, initCount);
}
else {
sif::warning << "SemaphoreFactory: Invalid argument, return regular"
"binary semaphore" << std::endl;
return new CountingSemaphore(maxCount, initCount);
}
}
void SemaphoreFactory::deleteSemaphore(SemaphoreIF* semaphore) {
delete semaphore;
}

@ -0,0 +1,24 @@
#include "../../osal/FreeRTOS/TaskManagement.h"
void TaskManagement::vRequestContextSwitchFromTask() {
vTaskDelay(0);
}
void TaskManagement::requestContextSwitch(
CallContext callContext = CallContext::TASK) {
if(callContext == CallContext::ISR) {
// This function depends on the partmacro.h definition for the specific device
vRequestContextSwitchFromISR();
} else {
vRequestContextSwitchFromTask();
}
}
TaskHandle_t TaskManagement::getCurrentTaskHandle() {
return xTaskGetCurrentTaskHandle();
}
size_t TaskManagement::getTaskStackHighWatermark(
TaskHandle_t task) {
return uxTaskGetStackHighWaterMark(task) * sizeof(StackType_t);
}

@ -0,0 +1,64 @@
#ifndef FRAMEWORK_OSAL_FREERTOS_TASKMANAGEMENT_H_
#define FRAMEWORK_OSAL_FREERTOS_TASKMANAGEMENT_H_
#include "../../returnvalues/HasReturnvaluesIF.h"
extern "C" {
#include <freertos/FreeRTOS.h>
#include <freertos/task.h>
}
#include <cstdint>
/**
* Architecture dependant portmacro.h function call.
* Should be implemented in bsp.
*/
extern void vRequestContextSwitchFromISR();
/*!
* Used by functions to tell if they are being called from
* within an ISR or from a regular task. This is required because FreeRTOS
* has different functions for handling semaphores and messages from within
* an ISR and task.
*/
enum class CallContext {
TASK = 0x00,//!< task_context
ISR = 0xFF //!< isr_context
};
class TaskManagement {
public:
/**
* @brief In this function, a function dependant on the portmacro.h header
* function calls to request a context switch can be specified.
* This can be used if sending to the queue from an ISR caused a task
* to unblock and a context switch is required.
*/
static void requestContextSwitch(CallContext callContext);
/**
* If task preemption in FreeRTOS is disabled, a context switch
* can be requested manually by calling this function.
*/
static void vRequestContextSwitchFromTask(void);
/**
* @return The current task handle
*/
static TaskHandle_t getCurrentTaskHandle();
/**
* Get returns the minimum amount of remaining stack space in words
* that was a available to the task since the task started executing.
* Please note that the actual value in bytes depends
* on the stack depth type.
* E.g. on a 32 bit machine, a value of 200 means 800 bytes.
* @return Smallest value of stack remaining since the task was started in
* words.
*/
static size_t getTaskStackHighWatermark(
TaskHandle_t task = nullptr);
};
#endif /* FRAMEWORK_OSAL_FREERTOS_TASKMANAGEMENT_H_ */

@ -0,0 +1,149 @@
#include "../../osal/linux/BinarySemaphore.h"
#include "../../serviceinterface/ServiceInterfaceStream.h"
extern "C" {
#include <errno.h>
#include <string.h>
}
BinarySemaphore::BinarySemaphore() {
// Using unnamed semaphores for now
initSemaphore();
}
BinarySemaphore::~BinarySemaphore() {
sem_destroy(&handle);
}
BinarySemaphore::BinarySemaphore(BinarySemaphore&& s) {
initSemaphore();
}
BinarySemaphore& BinarySemaphore::operator =(
BinarySemaphore&& s) {
initSemaphore();
return * this;
}
ReturnValue_t BinarySemaphore::acquire(TimeoutType timeoutType,
uint32_t timeoutMs) {
int result = 0;
if(timeoutType == TimeoutType::POLLING) {
result = sem_trywait(&handle);
}
else if(timeoutType == TimeoutType::BLOCKING) {
result = sem_wait(&handle);
}
else if(timeoutType == TimeoutType::WAITING){
timespec timeOut;
clock_gettime(CLOCK_REALTIME, &timeOut);
uint64_t nseconds = timeOut.tv_sec * 1000000000 + timeOut.tv_nsec;
nseconds += timeoutMs * 1000000;
timeOut.tv_sec = nseconds / 1000000000;
timeOut.tv_nsec = nseconds - timeOut.tv_sec * 1000000000;
result = sem_timedwait(&handle, &timeOut);
if(result != 0 and errno == EINVAL) {
sif::debug << "BinarySemaphore::acquire: Invalid time value possible"
<< std::endl;
}
}
if(result == 0) {
return HasReturnvaluesIF::RETURN_OK;
}
switch(errno) {
case(EAGAIN):
// Operation could not be performed without blocking (for sem_trywait)
case(ETIMEDOUT):
// Semaphore is 0
return SemaphoreIF::SEMAPHORE_TIMEOUT;
case(EINVAL):
// Semaphore invalid
return SemaphoreIF::SEMAPHORE_INVALID;
case(EINTR):
// Call was interrupted by signal handler
sif::debug << "BinarySemaphore::acquire: Signal handler interrupted."
"Code " << strerror(errno) << std::endl;
/* No break */
default:
return HasReturnvaluesIF::RETURN_FAILED;
}
}
ReturnValue_t BinarySemaphore::release() {
return BinarySemaphore::release(&this->handle);
}
ReturnValue_t BinarySemaphore::release(sem_t *handle) {
ReturnValue_t countResult = checkCount(handle, 1);
if(countResult != HasReturnvaluesIF::RETURN_OK) {
return countResult;
}
int result = sem_post(handle);
if(result == 0) {
return HasReturnvaluesIF::RETURN_OK;
}
switch(errno) {
case(EINVAL):
// Semaphore invalid
return SemaphoreIF::SEMAPHORE_INVALID;
case(EOVERFLOW):
// SEM_MAX_VALUE overflow. This should never happen
default:
return HasReturnvaluesIF::RETURN_FAILED;
}
}
uint8_t BinarySemaphore::getSemaphoreCounter() const {
// And another ugly cast :-D
return getSemaphoreCounter(const_cast<sem_t*>(&this->handle));
}
uint8_t BinarySemaphore::getSemaphoreCounter(sem_t *handle) {
int value = 0;
int result = sem_getvalue(handle, &value);
if (result == 0) {
return value;
}
else if(result != 0 and errno == EINVAL) {
// Could be called from interrupt, use lightweight printf
printf("BinarySemaphore::getSemaphoreCounter: Invalid semaphore\n");
return 0;
}
else {
// This should never happen.
return 0;
}
}
void BinarySemaphore::initSemaphore(uint8_t initCount) {
auto result = sem_init(&handle, true, initCount);
if(result == -1) {
switch(errno) {
case(EINVAL):
// Value exceeds SEM_VALUE_MAX
case(ENOSYS):
// System does not support process-shared semaphores
sif::error << "BinarySemaphore: Init failed with" << strerror(errno)
<< std::endl;
}
}
}
ReturnValue_t BinarySemaphore::checkCount(sem_t* handle, uint8_t maxCount) {
int value = getSemaphoreCounter(handle);
if(value >= maxCount) {
if(maxCount == 1 and value > 1) {
// Binary Semaphore special case.
// This is a config error use lightweight printf is this is called
// from an interrupt
printf("BinarySemaphore::release: Value of binary semaphore greater"
" than 1!\n");
return HasReturnvaluesIF::RETURN_FAILED;
}
return SemaphoreIF::SEMAPHORE_NOT_OWNED;
}
return HasReturnvaluesIF::RETURN_OK;
}

@ -0,0 +1,81 @@
#ifndef FRAMEWORK_OSAL_LINUX_BINARYSEMPAHORE_H_
#define FRAMEWORK_OSAL_LINUX_BINARYSEMPAHORE_H_
#include "../../returnvalues/HasReturnvaluesIF.h"
#include "../../tasks/SemaphoreIF.h"
extern "C" {
#include <semaphore.h>
}
/**
* @brief OS Tool to achieve synchronization of between tasks or between
* task and ISR. The default semaphore implementation creates a
* binary semaphore, which can only be taken once.
* @details
* See: http://www.man7.org/linux/man-pages/man7/sem_overview.7.html
* @author R. Mueller
* @ingroup osal
*/
class BinarySemaphore: public SemaphoreIF,
public HasReturnvaluesIF {
public:
static const uint8_t INTERFACE_ID = CLASS_ID::SEMAPHORE_IF;
//! @brief Default ctor
BinarySemaphore();
//! @brief Copy ctor, deleted explicitely.
BinarySemaphore(const BinarySemaphore&) = delete;
//! @brief Copy assignment, deleted explicitely.
BinarySemaphore& operator=(const BinarySemaphore&) = delete;
//! @brief Move ctor
BinarySemaphore (BinarySemaphore &&);
//! @brief Move assignment
BinarySemaphore & operator=(BinarySemaphore &&);
//! @brief Destructor
virtual ~BinarySemaphore();
void initSemaphore(uint8_t initCount = 1);
uint8_t getSemaphoreCounter() const override;
static uint8_t getSemaphoreCounter(sem_t* handle);
/**
* Take the binary semaphore.
* If the semaphore has already been taken, the task will be blocked
* for a maximum of #timeoutMs or until the semaphore is given back,
* for example by an ISR or another task.
* @param timeoutMs
* @return -@c RETURN_OK on success
* -@c SemaphoreIF::SEMAPHORE_TIMEOUT on timeout
*/
ReturnValue_t acquire(TimeoutType timeoutType = TimeoutType::BLOCKING,
uint32_t timeoutMs = 0) override;
/**
* Release the binary semaphore.
* @return -@c RETURN_OK on success
* -@c SemaphoreIF::SEMAPHORE_NOT_OWNED if the semaphores is
* already available.
*/
virtual ReturnValue_t release() override;
/**
* This static function can be used to release a semaphore by providing
* its handle.
* @param handle
* @return
*/
static ReturnValue_t release(sem_t* handle);
/** Checks the validity of the semaphore count against a specified
* known maxCount
* @param handle
* @param maxCount
* @return
*/
static ReturnValue_t checkCount(sem_t* handle, uint8_t maxCount);
protected:
sem_t handle;
};
#endif /* FRAMEWORK_OSAL_FREERTOS_BINARYSEMPAHORE_H_ */

@ -0,0 +1,54 @@
#include "../../osal/linux/CountingSemaphore.h"
#include "../../serviceinterface/ServiceInterfaceStream.h"
CountingSemaphore::CountingSemaphore(const uint8_t maxCount, uint8_t initCount):
maxCount(maxCount), initCount(initCount) {
if(initCount > maxCount) {
sif::error << "CountingSemaphoreUsingTask: Max count bigger than "
"intial cout. Setting initial count to max count." << std::endl;
initCount = maxCount;
}
initSemaphore(initCount);
}
CountingSemaphore::CountingSemaphore(CountingSemaphore&& other):
maxCount(other.maxCount), initCount(other.initCount) {
initSemaphore(initCount);
}
CountingSemaphore& CountingSemaphore::operator =(
CountingSemaphore&& other) {
initSemaphore(other.initCount);
return * this;
}
ReturnValue_t CountingSemaphore::release() {
ReturnValue_t result = checkCount(&handle, maxCount);
if(result != HasReturnvaluesIF::RETURN_OK) {
return result;
}
return CountingSemaphore::release(&this->handle);
}
ReturnValue_t CountingSemaphore::release(sem_t* handle) {
int result = sem_post(handle);
if(result == 0) {
return HasReturnvaluesIF::RETURN_OK;
}
switch(errno) {
case(EINVAL):
// Semaphore invalid
return SemaphoreIF::SEMAPHORE_INVALID;
case(EOVERFLOW):
// SEM_MAX_VALUE overflow. This should never happen
default:
return HasReturnvaluesIF::RETURN_FAILED;
}
}
uint8_t CountingSemaphore::getMaxCount() const {
return maxCount;
}

@ -0,0 +1,37 @@
#ifndef FRAMEWORK_OSAL_LINUX_COUNTINGSEMAPHORE_H_
#define FRAMEWORK_OSAL_LINUX_COUNTINGSEMAPHORE_H_
#include "../../osal/linux/BinarySemaphore.h"
/**
* @brief Counting semaphores, which can be acquired more than once.
* @details
* See: https://www.freertos.org/CreateCounting.html
* API of counting semaphores is almost identical to binary semaphores,
* so we just inherit from binary semaphore and provide the respective
* constructors.
*/
class CountingSemaphore: public BinarySemaphore {
public:
CountingSemaphore(const uint8_t maxCount, uint8_t initCount);
//! @brief Copy ctor, disabled
CountingSemaphore(const CountingSemaphore&) = delete;
//! @brief Copy assignment, disabled
CountingSemaphore& operator=(const CountingSemaphore&) = delete;
//! @brief Move ctor
CountingSemaphore (CountingSemaphore &&);
//! @brief Move assignment
CountingSemaphore & operator=(CountingSemaphore &&);
ReturnValue_t release() override;
static ReturnValue_t release(sem_t* sem);
/* Same API as binary semaphore otherwise. acquire() can be called
* until there are not semaphores left and release() can be called
* until maxCount is reached. */
uint8_t getMaxCount() const;
private:
const uint8_t maxCount;
uint8_t initCount = 0;
};
#endif /* FRAMEWORK_OSAL_FREERTOS_COUNTINGSEMAPHORE_H_ */

@ -0,0 +1,33 @@
#include "../../tasks/SemaphoreFactory.h"
#include "BinarySemaphore.h"
#include "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) {
return new BinarySemaphore();
}
SemaphoreIF* SemaphoreFactory::createCountingSemaphore(const uint8_t maxCount,
uint8_t initCount, uint32_t arguments) {
return new CountingSemaphore(maxCount, initCount);
}
void SemaphoreFactory::deleteSemaphore(SemaphoreIF* semaphore) {
delete semaphore;
}

@ -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;
}
}
}

@ -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_ */

@ -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;
}
}

@ -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_ */

@ -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_ */

@ -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);

@ -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_ */

@ -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) {

@ -1,15 +1,15 @@
#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 {
private: private:
ParameterMessage(); ParameterMessage();
public: public:
static const uint8_t MESSAGE_ID = MESSAGE_TYPE::PARAMETER; static const uint8_t MESSAGE_ID = messagetypes::PARAMETER;
static const Command_t CMD_PARAMETER_LOAD = MAKE_COMMAND_ID( 0x01 ); static const Command_t CMD_PARAMETER_LOAD = MAKE_COMMAND_ID( 0x01 );
static const Command_t CMD_PARAMETER_DUMP = MAKE_COMMAND_ID( 0x02 ); static const Command_t CMD_PARAMETER_DUMP = MAKE_COMMAND_ID( 0x02 );
static const Command_t REPLY_PARAMETER_DUMP = MAKE_COMMAND_ID( 0x03 ); static const Command_t REPLY_PARAMETER_DUMP = MAKE_COMMAND_ID( 0x03 );
@ -26,4 +26,4 @@ public:
}; };
#endif /* PARAMETERMESSAGE_H_ */ #endif /* FSFW_PARAMETERS_PARAMETERMESSAGE_H_ */

@ -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);
} }
} }

@ -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_ */

@ -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_ */

@ -1,89 +1,123 @@
#include "SerialBufferAdapter.h" #include "../serialize/SerialBufferAdapter.h"
#include "../serviceinterface/ServiceInterfaceStream.h"
#include <cstring> #include <cstring>
template<typename count_t>
SerialBufferAdapter<count_t>::SerialBufferAdapter(const uint8_t* buffer,
count_t bufferLength, bool serializeLength) :
serializeLength(serializeLength),
constBuffer(buffer), buffer(nullptr),
bufferLength(bufferLength) {}
template<typename count_t>
SerialBufferAdapter<count_t>::SerialBufferAdapter(uint8_t* buffer,
count_t bufferLength, bool serializeLength) :
serializeLength(serializeLength), constBuffer(buffer), buffer(buffer),
bufferLength(bufferLength) {}
template<typename T> template<typename count_t>
SerialBufferAdapter<T>::SerialBufferAdapter(const uint8_t* buffer, SerialBufferAdapter<count_t>::~SerialBufferAdapter() {
T bufferLength, bool serializeLenght) :
serializeLength(serializeLenght), constBuffer(buffer), buffer(NULL), bufferLength(
bufferLength) {
} }
template<typename T> template<typename count_t>
SerialBufferAdapter<T>::SerialBufferAdapter(uint8_t* buffer, T bufferLength, ReturnValue_t SerialBufferAdapter<count_t>::serialize(uint8_t** buffer,
bool serializeLenght) : size_t* size, size_t maxSize, Endianness streamEndianness) const {
serializeLength(serializeLenght), constBuffer(NULL), buffer(buffer), bufferLength(
bufferLength) {
}
template<typename T>
SerialBufferAdapter<T>::~SerialBufferAdapter() {
}
template<typename T>
ReturnValue_t SerialBufferAdapter<T>::serialize(uint8_t** buffer, size_t* size,
size_t maxSize, Endianness streamEndianness) const {
uint32_t serializedLength = bufferLength;
if (serializeLength) { if (serializeLength) {
serializedLength += SerializeAdapter::getSerializedSize( ReturnValue_t result = SerializeAdapter::serialize(&bufferLength,
&bufferLength); buffer, size, maxSize, streamEndianness);
if(result != HasReturnvaluesIF::RETURN_OK) {
return result;
}
} }
if (*size + serializedLength > maxSize) {
if (*size + bufferLength > maxSize) {
return BUFFER_TOO_SHORT; return BUFFER_TOO_SHORT;
} else {
if (serializeLength) {
SerializeAdapter::serialize(&bufferLength, buffer, size,
maxSize, streamEndianness);
}
if (this->constBuffer != NULL) {
memcpy(*buffer, this->constBuffer, bufferLength);
} else if (this->buffer != NULL) {
memcpy(*buffer, this->buffer, bufferLength);
} else {
return HasReturnvaluesIF::RETURN_FAILED;
}
*size += bufferLength;
(*buffer) += bufferLength;
return HasReturnvaluesIF::RETURN_OK;
} }
if (this->constBuffer != nullptr) {
std::memcpy(*buffer, this->constBuffer, bufferLength);
}
else if (this->buffer != nullptr) {
// This will propably be never reached, constBuffer should always be
// set if non-const buffer is set.
std::memcpy(*buffer, this->buffer, bufferLength);
}
else {
return HasReturnvaluesIF::RETURN_FAILED;
}
*size += bufferLength;
(*buffer) += bufferLength;
return HasReturnvaluesIF::RETURN_OK;
} }
template<typename T> template<typename count_t>
size_t SerialBufferAdapter<T>::getSerializedSize() const { size_t SerialBufferAdapter<count_t>::getSerializedSize() const {
if (serializeLength) { if (serializeLength) {
return bufferLength + SerializeAdapter::getSerializedSize(&bufferLength); return bufferLength + SerializeAdapter::getSerializedSize(&bufferLength);
} else { } else {
return bufferLength; return bufferLength;
} }
} }
template<typename T>
ReturnValue_t SerialBufferAdapter<T>::deSerialize(const uint8_t** buffer, template<typename count_t>
ReturnValue_t SerialBufferAdapter<count_t>::deSerialize(const uint8_t** buffer,
size_t* size, Endianness streamEndianness) { size_t* size, Endianness streamEndianness) {
//TODO Ignores Endian flag! if (this->buffer == nullptr) {
if (buffer != NULL) {
if(serializeLength){
T serializedSize = SerializeAdapter::getSerializedSize(
&bufferLength);
if((*size - bufferLength - serializedSize) >= 0){
*buffer += serializedSize;
*size -= serializedSize;
}else{
return STREAM_TOO_SHORT;
}
}
//No Else If, go on with buffer
if (*size - bufferLength >= 0) {
*size -= bufferLength;
memcpy(this->buffer, *buffer, bufferLength);
(*buffer) += bufferLength;
return HasReturnvaluesIF::RETURN_OK;
} else {
return STREAM_TOO_SHORT;
}
} else {
return HasReturnvaluesIF::RETURN_FAILED; return HasReturnvaluesIF::RETURN_FAILED;
} }
if(serializeLength){
count_t lengthField = 0;
ReturnValue_t result = SerializeAdapter::deSerialize(&lengthField,
buffer, size, streamEndianness);
if(result != HasReturnvaluesIF::RETURN_OK) {
return result;
}
if(lengthField > bufferLength) {
return TOO_MANY_ELEMENTS;
}
bufferLength = lengthField;
}
if (bufferLength <= *size) {
*size -= bufferLength;
std::memcpy(this->buffer, *buffer, bufferLength);
(*buffer) += bufferLength;
return HasReturnvaluesIF::RETURN_OK;
}
else {
return STREAM_TOO_SHORT;
}
}
template<typename count_t>
uint8_t * SerialBufferAdapter<count_t>::getBuffer() {
if(buffer == nullptr) {
sif::error << "Wrong access function for stored type !"
" Use getConstBuffer()." << std::endl;
return nullptr;
}
return buffer;
}
template<typename count_t>
const uint8_t * SerialBufferAdapter<count_t>::getConstBuffer() {
if(constBuffer == nullptr) {
sif::error << "SerialBufferAdapter::getConstBuffer:"
" Buffers are unitialized!" << std::endl;
return nullptr;
}
return constBuffer;
}
template<typename count_t>
void SerialBufferAdapter<count_t>::setBuffer(uint8_t* buffer,
count_t bufferLength) {
this->buffer = buffer;
this->constBuffer = buffer;
this->bufferLength = bufferLength;
} }
@ -91,4 +125,5 @@ ReturnValue_t SerialBufferAdapter<T>::deSerialize(const uint8_t** buffer,
template class SerialBufferAdapter<uint8_t>; template class SerialBufferAdapter<uint8_t>;
template class SerialBufferAdapter<uint16_t>; template class SerialBufferAdapter<uint16_t>;
template class SerialBufferAdapter<uint32_t>; template class SerialBufferAdapter<uint32_t>;
template class SerialBufferAdapter<uint64_t>;

@ -1,35 +1,78 @@
#ifndef SERIALBUFFERADAPTER_H_ #ifndef SERIALBUFFERADAPTER_H_
#define SERIALBUFFERADAPTER_H_ #define SERIALBUFFERADAPTER_H_
#include "SerializeIF.h" #include "../serialize/SerializeIF.h"
#include "SerializeAdapter.h" #include "../serialize/SerializeAdapter.h"
/** /**
* This adapter provides an interface for SerializeIF to serialize or deserialize
* buffers with no length header but a known size.
*
* Additionally, the buffer length can be serialized too and will be put in
* front of the serialized buffer.
*
* Can be used with SerialLinkedListAdapter by declaring a SerializeElement with
* SerialElement<SerialBufferAdapter<bufferLengthType(will be uint8_t mostly)>>.
* Right now, the SerialBufferAdapter must always
* be initialized with the buffer and size !
*
* \ingroup serialize * \ingroup serialize
*/ */
template<typename T> template<typename count_t>
class SerialBufferAdapter: public SerializeIF { class SerialBufferAdapter: public SerializeIF {
public: public:
SerialBufferAdapter(const uint8_t * buffer, T bufferLength, bool serializeLenght = false);
SerialBufferAdapter(uint8_t* buffer, T bufferLength,
bool serializeLenght = false);
virtual ~SerialBufferAdapter(); /**
* Constructor for constant uint8_t buffer. Length field can be serialized optionally.
* Type of length can be supplied as template type.
* @param buffer
* @param bufferLength
* @param serializeLength
*/
SerialBufferAdapter(const uint8_t* buffer, count_t bufferLength,
bool serializeLength = false);
virtual ReturnValue_t serialize(uint8_t** buffer, size_t* size, /**
size_t maxSize, Endianness streamEndianness) const override; * Constructor for non-constant uint8_t buffer.
* Length field can be serialized optionally.
* Type of length can be supplied as template type.
* @param buffer
* @param bufferLength
* @param serializeLength Length field will be serialized with size count_t
*/
SerialBufferAdapter(uint8_t* buffer, count_t bufferLength,
bool serializeLength = false);
virtual size_t getSerializedSize() const override; virtual ~SerialBufferAdapter();
virtual ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size, virtual ReturnValue_t serialize(uint8_t** buffer, size_t* size,
Endianness streamEndianness) override; size_t maxSize, Endianness streamEndianness) const override;
virtual size_t getSerializedSize() const override;
/**
* @brief This function deserializes a buffer into the member buffer.
* @details
* If a length field is present, it is ignored, as the size should have
* been set in the constructor. If the size is not known beforehand,
* consider using SerialFixedArrayListAdapter instead.
* @param buffer [out] Resulting buffer
* @param size remaining size to deserialize, should be larger than buffer
* + size field size
* @param bigEndian
* @return
*/
virtual ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size,
Endianness streamEndianness) override;
uint8_t * getBuffer();
const uint8_t * getConstBuffer();
void setBuffer(uint8_t* buffer, count_t bufferLength);
private: private:
bool serializeLength; bool serializeLength = false;
const uint8_t *constBuffer; const uint8_t *constBuffer = nullptr;
uint8_t *buffer; uint8_t *buffer = nullptr;
T bufferLength; count_t bufferLength = 0;
}; };
#endif /* SERIALBUFFERADAPTER_H_ */ #endif /* SERIALBUFFERADAPTER_H_ */

@ -1,17 +1,17 @@
#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 <stddef.h>
/** /**
* \defgroup serialize Serialization * @defgroup serialize Serialization
* Contains serialisation services. * Contains serialization services.
*/ */
/** /**
* Translation of objects into data streams. * Translation of objects into data streams and from data streams.
* \ingroup serialize * @ingroup serialize
*/ */
class SerializeIF { class SerializeIF {
public: public:
@ -20,21 +20,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
* - @¢ 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_ */

@ -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;

@ -7,7 +7,7 @@
class ModeSequenceMessage { class ModeSequenceMessage {
public: public:
static const uint8_t MESSAGE_ID = MESSAGE_TYPE::MODE_SEQUENCE; static const uint8_t MESSAGE_ID = messagetypes::MODE_SEQUENCE;
static const Command_t ADD_SEQUENCE = MAKE_COMMAND_ID(0x01); static const Command_t ADD_SEQUENCE = MAKE_COMMAND_ID(0x01);
static const Command_t ADD_TABLE = MAKE_COMMAND_ID(0x02); static const Command_t ADD_TABLE = MAKE_COMMAND_ID(0x02);

50
tasks/SemaphoreFactory.h Normal file

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

68
tasks/SemaphoreIF.h Normal file

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

@ -1,7 +1,6 @@
#ifndef FRAMEWORK_TASKS_TYPEDEF_H_ #ifndef FRAMEWORK_TASKS_TYPEDEF_H_
#define FRAMEWORK_TASKS_TYPEDEF_H_ #define FRAMEWORK_TASKS_TYPEDEF_H_
//TODO more generic?
typedef const char* TaskName; typedef const char* TaskName;
typedef uint8_t TaskPriority; typedef uint8_t TaskPriority;
typedef size_t TaskStackSize; typedef size_t TaskStackSize;

@ -119,7 +119,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;

@ -41,7 +41,7 @@ public:
static store_address_t getStoreId(const CommandMessage* cmd); static store_address_t getStoreId(const CommandMessage* cmd);
virtual ~TmStoreMessage(); virtual ~TmStoreMessage();
static const uint8_t MESSAGE_ID = MESSAGE_TYPE::TM_STORE; static const uint8_t MESSAGE_ID = messagetypes::TM_STORE;
static const Command_t ENABLE_STORING = MAKE_COMMAND_ID(1); static const Command_t ENABLE_STORING = MAKE_COMMAND_ID(1);
static const Command_t DELETE_STORE_CONTENT = MAKE_COMMAND_ID(2); static const Command_t DELETE_STORE_CONTENT = MAKE_COMMAND_ID(2);
static const Command_t DOWNLINK_STORE_CONTENT = MAKE_COMMAND_ID(3); static const Command_t DOWNLINK_STORE_CONTENT = MAKE_COMMAND_ID(3);

@ -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"
@ -345,4 +345,4 @@ private:
void checkTimeout(); void checkTimeout();
}; };
#endif /* COMMANDINGSERVICEBASE_H_ */ #endif /* FSFW_TMTCSERVICES_COMMANDINGSERVICEBASE_H_ */

@ -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
result = handleStoredTm(); (packetSentCounter < sentPacketsPerCycle)) {
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());
packetSentCounter++;
} }
tmStore->deleteData(message.getStorageId());
} }
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;
}

@ -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;
}; };