Merge branch 'development' of https://egit.irs.uni-stuttgart.de/eive/fsfw into development

This commit is contained in:
Jakob Meier 2021-03-19 15:38:06 +01:00
commit fa108f0a3b
54 changed files with 2130 additions and 1532 deletions

View File

@ -22,7 +22,9 @@ a C file without issues
### Local Pool ### Local Pool
- Interface of LocalPools has changed. LocalPool is not a template anymore. Instead the size and bucket number of the pools per page and the number of pages are passed to the ctor instead of two ctor arguments and a template parameter - Interface of LocalPools has changed. LocalPool is not a template anymore. Instead the size and
bucket number of the pools per page and the number of pages are passed to the ctor instead of
two ctor arguments and a template parameter
### Parameter Service ### Parameter Service
@ -40,7 +42,8 @@ important use-case)
### File System Interface ### File System Interface
- A new interfaces specifies the functions for a software object which exposes the file system of a given hardware to use message based file handling (e.g. PUS commanding) - A new interfaces specifies the functions for a software object which exposes the file system of
a given hardware to use message based file handling (e.g. PUS commanding)
### Internal Error Reporter ### Internal Error Reporter
@ -52,7 +55,8 @@ ID for now.
### Device Handler Base ### Device Handler Base
- There is an additional `PERFORM_OPERATION` step for the device handler base. It is important - There is an additional `PERFORM_OPERATION` step for the device handler base. It is important
that DHB users adapt their polling sequence tables to perform this step. This steps allows for aclear distinction between operation and communication steps that DHB users adapt their polling sequence tables to perform this step. This steps allows for
a clear distinction between operation and communication steps
- setNormalDatapoolEntriesInvalid is not an abstract method and a default implementation was provided - setNormalDatapoolEntriesInvalid is not an abstract method and a default implementation was provided
- getTransitionDelayMs is now an abstract method - getTransitionDelayMs is now an abstract method
@ -69,7 +73,8 @@ now
### Commanding Service Base ### Commanding Service Base
- CSB uses the new fsfwconfig::FSFW_CSB_FIFO_DEPTH variable to determine the FIFO depth for each CSB instance. This variable has to be set in the FSFWConfig.h file - CSB uses the new fsfwconfig::FSFW_CSB_FIFO_DEPTH variable to determine the FIFO depth for each
CSB instance. This variable has to be set in the FSFWConfig.h file
### Service Interface ### Service Interface
@ -82,6 +87,12 @@ now
For mission code, developers need to replace sif:: calls by the printf counterparts, but only if the CPP stream are excluded. For mission code, developers need to replace sif:: calls by the printf counterparts, but only if the CPP stream are excluded.
If this is not the case, everything should work as usual. If this is not the case, everything should work as usual.
### ActionHelper and ActionMessage
- ActionHelper finish function and ActionMessage::setCompletionReply now expects explicit
information whether to report a success or failure message instead of deriving it implicitely
from returnvalue
### PUS Parameter Service 20 ### PUS Parameter Service 20
Added PUS parameter service 20 (only custom subservices available). Added PUS parameter service 20 (only custom subservices available).

View File

@ -43,10 +43,10 @@ void ActionHelper::step(uint8_t step, MessageQueueId_t reportTo,
queueToUse->sendMessage(reportTo, &reply); queueToUse->sendMessage(reportTo, &reply);
} }
void ActionHelper::finish(MessageQueueId_t reportTo, ActionId_t commandId, void ActionHelper::finish(bool success, MessageQueueId_t reportTo, ActionId_t commandId,
ReturnValue_t result) { ReturnValue_t result) {
CommandMessage reply; CommandMessage reply;
ActionMessage::setCompletionReply(&reply, commandId, result); ActionMessage::setCompletionReply(&reply, commandId, success, result);
queueToUse->sendMessage(reportTo, &reply); queueToUse->sendMessage(reportTo, &reply);
} }
@ -69,7 +69,7 @@ void ActionHelper::prepareExecution(MessageQueueId_t commandedBy,
ipcStore->deleteData(dataAddress); ipcStore->deleteData(dataAddress);
if(result == HasActionsIF::EXECUTION_FINISHED) { if(result == HasActionsIF::EXECUTION_FINISHED) {
CommandMessage reply; CommandMessage reply;
ActionMessage::setCompletionReply(&reply, actionId, result); ActionMessage::setCompletionReply(&reply, actionId, true, result);
queueToUse->sendMessage(commandedBy, &reply); queueToUse->sendMessage(commandedBy, &reply);
} }
if (result != HasReturnvaluesIF::RETURN_OK) { if (result != HasReturnvaluesIF::RETURN_OK) {

View File

@ -62,12 +62,12 @@ public:
ReturnValue_t result = HasReturnvaluesIF::RETURN_OK); ReturnValue_t result = HasReturnvaluesIF::RETURN_OK);
/** /**
* Function to be called by the owner to send a action completion message * Function to be called by the owner to send a action completion message
* * @param success Specify whether action was completed successfully or not.
* @param reportTo MessageQueueId_t to report the action completion message to * @param reportTo MessageQueueId_t to report the action completion message to
* @param commandId ID of the executed command * @param commandId ID of the executed command
* @param result Result of the execution * @param result Result of the execution
*/ */
void finish(MessageQueueId_t reportTo, ActionId_t commandId, void finish(bool success, MessageQueueId_t reportTo, ActionId_t commandId,
ReturnValue_t result = HasReturnvaluesIF::RETURN_OK); ReturnValue_t result = HasReturnvaluesIF::RETURN_OK);
/** /**
* Function to be called by the owner if an action does report data. * Function to be called by the owner if an action does report data.

View File

@ -54,10 +54,11 @@ void ActionMessage::setDataReply(CommandMessage* message, ActionId_t actionId,
} }
void ActionMessage::setCompletionReply(CommandMessage* message, void ActionMessage::setCompletionReply(CommandMessage* message,
ActionId_t fid, ReturnValue_t result) { ActionId_t fid, bool success, ReturnValue_t result) {
if (result == HasReturnvaluesIF::RETURN_OK or result == HasActionsIF::EXECUTION_FINISHED) { if (success) {
message->setCommand(COMPLETION_SUCCESS); message->setCommand(COMPLETION_SUCCESS);
} else { }
else {
message->setCommand(COMPLETION_FAILED); message->setCommand(COMPLETION_FAILED);
} }
message->setParameter(fid); message->setParameter(fid);

View File

@ -24,11 +24,14 @@ public:
static const Command_t DATA_REPLY = MAKE_COMMAND_ID(4); static const Command_t DATA_REPLY = MAKE_COMMAND_ID(4);
static const Command_t COMPLETION_SUCCESS = MAKE_COMMAND_ID(5); static const Command_t COMPLETION_SUCCESS = MAKE_COMMAND_ID(5);
static const Command_t COMPLETION_FAILED = MAKE_COMMAND_ID(6); static const Command_t COMPLETION_FAILED = MAKE_COMMAND_ID(6);
virtual ~ActionMessage(); virtual ~ActionMessage();
static void setCommand(CommandMessage* message, ActionId_t fid, static void setCommand(CommandMessage* message, ActionId_t fid,
store_address_t parameters); store_address_t parameters);
static ActionId_t getActionId(const CommandMessage* message ); static ActionId_t getActionId(const CommandMessage* message );
static store_address_t getStoreId(const CommandMessage* message ); static store_address_t getStoreId(const CommandMessage* message);
static void setStepReply(CommandMessage* message, ActionId_t fid, static void setStepReply(CommandMessage* message, ActionId_t fid,
uint8_t step, ReturnValue_t result = HasReturnvaluesIF::RETURN_OK); uint8_t step, ReturnValue_t result = HasReturnvaluesIF::RETURN_OK);
static uint8_t getStep(const CommandMessage* message ); static uint8_t getStep(const CommandMessage* message );
@ -36,7 +39,8 @@ public:
static void setDataReply(CommandMessage* message, ActionId_t actionId, static void setDataReply(CommandMessage* message, ActionId_t actionId,
store_address_t data); store_address_t data);
static void setCompletionReply(CommandMessage* message, ActionId_t fid, static void setCompletionReply(CommandMessage* message, ActionId_t fid,
ReturnValue_t result = HasReturnvaluesIF::RETURN_OK); bool success, ReturnValue_t result = HasReturnvaluesIF::RETURN_OK);
static void clear(CommandMessage* message); static void clear(CommandMessage* message);
}; };

View File

@ -63,7 +63,7 @@ void SimpleActionHelper::prepareExecution(MessageQueueId_t commandedBy,
break; break;
case HasActionsIF::EXECUTION_FINISHED: case HasActionsIF::EXECUTION_FINISHED:
ActionMessage::setCompletionReply(&reply, actionId, ActionMessage::setCompletionReply(&reply, actionId,
HasReturnvaluesIF::RETURN_OK); true, HasReturnvaluesIF::RETURN_OK);
queueToUse->sendMessage(commandedBy, &reply); queueToUse->sendMessage(commandedBy, &reply);
break; break;
default: default:

View File

@ -13,7 +13,7 @@ ExtendedControllerBase::~ExtendedControllerBase() {
ReturnValue_t ExtendedControllerBase::executeAction(ActionId_t actionId, ReturnValue_t ExtendedControllerBase::executeAction(ActionId_t actionId,
MessageQueueId_t commandedBy, const uint8_t *data, size_t size) { MessageQueueId_t commandedBy, const uint8_t *data, size_t size) {
// needs to be overriden and implemented by child class. /* Needs to be overriden and implemented by child class. */
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
} }
@ -21,7 +21,7 @@ ReturnValue_t ExtendedControllerBase::executeAction(ActionId_t actionId,
ReturnValue_t ExtendedControllerBase::initializeLocalDataPool( ReturnValue_t ExtendedControllerBase::initializeLocalDataPool(
localpool::DataPool &localDataPoolMap, LocalDataPoolManager &poolManager) { localpool::DataPool &localDataPoolMap, LocalDataPoolManager &poolManager) {
// needs to be overriden and implemented by child class. /* Needs to be overriden and implemented by child class. */
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
} }
@ -96,8 +96,10 @@ ReturnValue_t ExtendedControllerBase::initializeAfterTaskCreation() {
ReturnValue_t ExtendedControllerBase::performOperation(uint8_t opCode) { ReturnValue_t ExtendedControllerBase::performOperation(uint8_t opCode) {
handleQueue(); handleQueue();
poolManager.performHkOperation();
performControlOperation(); performControlOperation();
/* We do this after performing control operation because variables will be set changed
in this function. */
poolManager.performHkOperation();
return RETURN_OK; return RETURN_OK;
} }

View File

@ -18,15 +18,13 @@ class PoolVariableIF;
class DataSetIF { class DataSetIF {
public: public:
static constexpr uint8_t INTERFACE_ID = CLASS_ID::DATA_SET_CLASS; static constexpr uint8_t INTERFACE_ID = CLASS_ID::DATA_SET_CLASS;
static constexpr ReturnValue_t INVALID_PARAMETER_DEFINITION = static constexpr ReturnValue_t INVALID_PARAMETER_DEFINITION = MAKE_RETURN_CODE(1);
MAKE_RETURN_CODE( 0x01 ); static constexpr ReturnValue_t SET_WAS_ALREADY_READ = MAKE_RETURN_CODE(2);
static constexpr ReturnValue_t SET_WAS_ALREADY_READ = MAKE_RETURN_CODE( 0x02 ); static constexpr ReturnValue_t COMMITING_WITHOUT_READING = MAKE_RETURN_CODE(3);
static constexpr ReturnValue_t COMMITING_WITHOUT_READING =
MAKE_RETURN_CODE(0x03);
static constexpr ReturnValue_t DATA_SET_UNINITIALISED = MAKE_RETURN_CODE( 0x04 ); static constexpr ReturnValue_t DATA_SET_UNINITIALISED = MAKE_RETURN_CODE(4);
static constexpr ReturnValue_t DATA_SET_FULL = MAKE_RETURN_CODE( 0x05 ); static constexpr ReturnValue_t DATA_SET_FULL = MAKE_RETURN_CODE(5);
static constexpr ReturnValue_t POOL_VAR_NULL = MAKE_RETURN_CODE( 0x06 ); static constexpr ReturnValue_t POOL_VAR_NULL = MAKE_RETURN_CODE(6);
/** /**
* @brief This is an empty virtual destructor, * @brief This is an empty virtual destructor,

View File

@ -1,5 +1,8 @@
#include "PoolDataSetBase.h" #include "PoolDataSetBase.h"
#include "../serviceinterface/ServiceInterfaceStream.h" #include "ReadCommitIFAttorney.h"
#include "../serviceinterface/ServiceInterface.h"
#include <cstring> #include <cstring>
PoolDataSetBase::PoolDataSetBase(PoolVariableIF** registeredVariablesArray, PoolDataSetBase::PoolDataSetBase(PoolVariableIF** registeredVariablesArray,
@ -11,62 +14,66 @@ PoolDataSetBase::PoolDataSetBase(PoolVariableIF** registeredVariablesArray,
PoolDataSetBase::~PoolDataSetBase() {} PoolDataSetBase::~PoolDataSetBase() {}
ReturnValue_t PoolDataSetBase::registerVariable( ReturnValue_t PoolDataSetBase::registerVariable(PoolVariableIF *variable) {
PoolVariableIF *variable) { if (state != States::STATE_SET_UNINITIALISED) {
if (state != States::STATE_SET_UNINITIALISED) {
#if FSFW_CPP_OSTREAM_ENABLED == 1 #if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "DataSet::registerVariable: " sif::error << "DataSet::registerVariable: Call made in wrong position." << std::endl;
"Call made in wrong position." << std::endl; #else
sif::printError("DataSet::registerVariable: Call made in wrong position.");
#endif #endif
return DataSetIF::DATA_SET_UNINITIALISED; return DataSetIF::DATA_SET_UNINITIALISED;
} }
if (variable == nullptr) { if (variable == nullptr) {
#if FSFW_CPP_OSTREAM_ENABLED == 1 #if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "DataSet::registerVariable: " sif::error << "DataSet::registerVariable: Pool variable is nullptr." << std::endl;
"Pool variable is nullptr." << std::endl; #else
sif::printError("DataSet::registerVariable: Pool variable is nullptr.\n");
#endif #endif
return DataSetIF::POOL_VAR_NULL; return DataSetIF::POOL_VAR_NULL;
} }
if (fillCount >= maxFillCount) { if (fillCount >= maxFillCount) {
#if FSFW_CPP_OSTREAM_ENABLED == 1 #if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "DataSet::registerVariable: " sif::error << "DataSet::registerVariable: DataSet is full." << std::endl;
"DataSet is full." << std::endl; #else
sif::printError("DataSet::registerVariable: DataSet is full.\n");
#endif #endif
return DataSetIF::DATA_SET_FULL; return DataSetIF::DATA_SET_FULL;
} }
registeredVariables[fillCount] = variable; registeredVariables[fillCount] = variable;
fillCount++; fillCount++;
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
} }
ReturnValue_t PoolDataSetBase::read(MutexIF::TimeoutType timeoutType, ReturnValue_t PoolDataSetBase::read(MutexIF::TimeoutType timeoutType,
uint32_t lockTimeout) { uint32_t lockTimeout) {
ReturnValue_t result = HasReturnvaluesIF::RETURN_OK; ReturnValue_t result = HasReturnvaluesIF::RETURN_OK;
ReturnValue_t error = result; ReturnValue_t error = result;
if (state == States::STATE_SET_UNINITIALISED) { if (state == States::STATE_SET_UNINITIALISED) {
lockDataPool(timeoutType, lockTimeout); lockDataPool(timeoutType, lockTimeout);
for (uint16_t count = 0; count < fillCount; count++) { for (uint16_t count = 0; count < fillCount; count++) {
result = readVariable(count); result = readVariable(count);
if(result != RETURN_OK) { if(result != RETURN_OK) {
error = result; error = result;
} }
} }
state = States::STATE_SET_WAS_READ; state = States::STATE_SET_WAS_READ;
unlockDataPool(); unlockDataPool();
} }
else { else {
#if FSFW_CPP_OSTREAM_ENABLED == 1 #if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "DataSet::read(): " sif::error << "DataSet::read(): Call made in wrong position. Don't forget to commit"
"Call made in wrong position. Don't forget to commit" " member datasets!" << std::endl;
" member datasets!" << std::endl; #else
#endif sif::printError("DataSet::read(): Call made in wrong position. Don't forget to commit"
result = SET_WAS_ALREADY_READ; " member datasets!\n");
} #endif /* FSFW_CPP_OSTREAM_ENABLED == 1 */
result = SET_WAS_ALREADY_READ;
}
if(error != HasReturnvaluesIF::RETURN_OK) { if(error != HasReturnvaluesIF::RETURN_OK) {
result = error; result = error;
} }
return result; return result;
} }
uint16_t PoolDataSetBase::getFillCount() const { uint16_t PoolDataSetBase::getFillCount() const {
@ -74,144 +81,136 @@ uint16_t PoolDataSetBase::getFillCount() const {
} }
ReturnValue_t PoolDataSetBase::readVariable(uint16_t count) { ReturnValue_t PoolDataSetBase::readVariable(uint16_t count) {
ReturnValue_t result = HasReturnvaluesIF::RETURN_OK; ReturnValue_t result = HasReturnvaluesIF::RETURN_OK;
if(registeredVariables[count] == nullptr) { if(registeredVariables[count] == nullptr) {
// configuration error. /* Configuration error. */
return HasReturnvaluesIF::RETURN_FAILED; return HasReturnvaluesIF::RETURN_FAILED;
} }
// These checks are often performed by the respective /* These checks are often performed by the respective variable implementation too, but I guess
// variable implementation too, but I guess a double check does not hurt. a double check does not hurt. */
if (registeredVariables[count]->getReadWriteMode() != if (registeredVariables[count]->getReadWriteMode() != PoolVariableIF::VAR_WRITE and
PoolVariableIF::VAR_WRITE and registeredVariables[count]->getDataPoolId() != PoolVariableIF::NO_PARAMETER) {
registeredVariables[count]->getDataPoolId() if(protectEveryReadCommitCall) {
!= PoolVariableIF::NO_PARAMETER) result = registeredVariables[count]->read(timeoutTypeForSingleVars,
{ mutexTimeoutForSingleVars);
if(protectEveryReadCommitCall) { }
result = registeredVariables[count]->read( else {
timeoutTypeForSingleVars, /* The readWithoutLock function is protected, so we use the attorney here */
mutexTimeoutForSingleVars); result = ReadCommitIFAttorney::readWithoutLock(registeredVariables[count]);
} }
else {
result = registeredVariables[count]->readWithoutLock();
}
if(result != HasReturnvaluesIF::RETURN_OK) { if(result != HasReturnvaluesIF::RETURN_OK) {
result = INVALID_PARAMETER_DEFINITION; result = INVALID_PARAMETER_DEFINITION;
} }
} }
return result; return result;
} }
ReturnValue_t PoolDataSetBase::commit(MutexIF::TimeoutType timeoutType, ReturnValue_t PoolDataSetBase::commit(MutexIF::TimeoutType timeoutType,
uint32_t lockTimeout) { uint32_t lockTimeout) {
if (state == States::STATE_SET_WAS_READ) { if (state == States::STATE_SET_WAS_READ) {
handleAlreadyReadDatasetCommit(timeoutType, lockTimeout); handleAlreadyReadDatasetCommit(timeoutType, lockTimeout);
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
} }
else { else {
return handleUnreadDatasetCommit(timeoutType, lockTimeout); return handleUnreadDatasetCommit(timeoutType, lockTimeout);
} }
} }
void PoolDataSetBase::handleAlreadyReadDatasetCommit( void PoolDataSetBase::handleAlreadyReadDatasetCommit(
MutexIF::TimeoutType timeoutType, uint32_t lockTimeout) { MutexIF::TimeoutType timeoutType, uint32_t lockTimeout) {
lockDataPool(timeoutType, lockTimeout); lockDataPool(timeoutType, lockTimeout);
for (uint16_t count = 0; count < fillCount; count++) { for (uint16_t count = 0; count < fillCount; count++) {
if (registeredVariables[count]->getReadWriteMode() if ((registeredVariables[count]->getReadWriteMode() != PoolVariableIF::VAR_READ) and
!= PoolVariableIF::VAR_READ (registeredVariables[count]->getDataPoolId() != PoolVariableIF::NO_PARAMETER)) {
&& registeredVariables[count]->getDataPoolId() if(protectEveryReadCommitCall) {
!= PoolVariableIF::NO_PARAMETER) { registeredVariables[count]->commit(timeoutTypeForSingleVars,
if(protectEveryReadCommitCall) { mutexTimeoutForSingleVars);
registeredVariables[count]->commit( }
timeoutTypeForSingleVars, else {
mutexTimeoutForSingleVars); /* The commitWithoutLock function is protected, so we use the attorney here */
} ReadCommitIFAttorney::commitWithoutLock(registeredVariables[count]);
else { }
registeredVariables[count]->commitWithoutLock(); }
} }
} state = States::STATE_SET_UNINITIALISED;
} unlockDataPool();
state = States::STATE_SET_UNINITIALISED;
unlockDataPool();
} }
ReturnValue_t PoolDataSetBase::handleUnreadDatasetCommit( ReturnValue_t PoolDataSetBase::handleUnreadDatasetCommit(
MutexIF::TimeoutType timeoutType, uint32_t lockTimeout) { MutexIF::TimeoutType timeoutType, uint32_t lockTimeout) {
ReturnValue_t result = HasReturnvaluesIF::RETURN_OK; ReturnValue_t result = HasReturnvaluesIF::RETURN_OK;
lockDataPool(timeoutType, lockTimeout); lockDataPool(timeoutType, lockTimeout);
for (uint16_t count = 0; count < fillCount; count++) { for (uint16_t count = 0; count < fillCount; count++) {
if (registeredVariables[count]->getReadWriteMode() if ((registeredVariables[count]->getReadWriteMode() == PoolVariableIF::VAR_WRITE) and
== PoolVariableIF::VAR_WRITE (registeredVariables[count]->getDataPoolId() != PoolVariableIF::NO_PARAMETER)) {
&& registeredVariables[count]->getDataPoolId() if(protectEveryReadCommitCall) {
!= PoolVariableIF::NO_PARAMETER) { result = registeredVariables[count]->commit(timeoutTypeForSingleVars,
if(protectEveryReadCommitCall) { mutexTimeoutForSingleVars);
result = registeredVariables[count]->commit( }
timeoutTypeForSingleVars, else {
mutexTimeoutForSingleVars); /* The commitWithoutLock function is protected, so we use the attorney here */
} ReadCommitIFAttorney::commitWithoutLock(registeredVariables[count]);
else { }
result = registeredVariables[count]->commitWithoutLock();
}
} else if (registeredVariables[count]->getDataPoolId() } else if (registeredVariables[count]->getDataPoolId()
!= PoolVariableIF::NO_PARAMETER) { != PoolVariableIF::NO_PARAMETER) {
if (result != COMMITING_WITHOUT_READING) { if (result != COMMITING_WITHOUT_READING) {
#if FSFW_CPP_OSTREAM_ENABLED == 1 #if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "DataSet::commit(): commit-without-read call made " sif::error << "DataSet::commit(): commit-without-read call made "
"with non write-only variable." << std::endl; "with non write-only variable." << std::endl;
#endif #endif
result = COMMITING_WITHOUT_READING; result = COMMITING_WITHOUT_READING;
} }
} }
} }
state = States::STATE_SET_UNINITIALISED; state = States::STATE_SET_UNINITIALISED;
unlockDataPool(); unlockDataPool();
return result; return result;
} }
ReturnValue_t PoolDataSetBase::lockDataPool(MutexIF::TimeoutType timeoutType, ReturnValue_t PoolDataSetBase::lockDataPool(MutexIF::TimeoutType timeoutType,
uint32_t lockTimeout) { uint32_t lockTimeout) {
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
} }
ReturnValue_t PoolDataSetBase::unlockDataPool() { ReturnValue_t PoolDataSetBase::unlockDataPool() {
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
} }
ReturnValue_t PoolDataSetBase::serialize(uint8_t** buffer, size_t* size, ReturnValue_t PoolDataSetBase::serialize(uint8_t** buffer, size_t* size,
const size_t maxSize, SerializeIF::Endianness streamEndianness) const { const size_t maxSize, SerializeIF::Endianness streamEndianness) const {
ReturnValue_t result = HasReturnvaluesIF::RETURN_FAILED; ReturnValue_t result = HasReturnvaluesIF::RETURN_FAILED;
for (uint16_t count = 0; count < fillCount; count++) { for (uint16_t count = 0; count < fillCount; count++) {
result = registeredVariables[count]->serialize(buffer, size, maxSize, result = registeredVariables[count]->serialize(buffer, size, maxSize, streamEndianness);
streamEndianness); if (result != HasReturnvaluesIF::RETURN_OK) {
if (result != HasReturnvaluesIF::RETURN_OK) { return result;
return result; }
} }
} return result;
return result;
} }
ReturnValue_t PoolDataSetBase::deSerialize(const uint8_t** buffer, size_t* size, ReturnValue_t PoolDataSetBase::deSerialize(const uint8_t** buffer, size_t* size,
SerializeIF::Endianness streamEndianness) { SerializeIF::Endianness streamEndianness) {
ReturnValue_t result = HasReturnvaluesIF::RETURN_FAILED; ReturnValue_t result = HasReturnvaluesIF::RETURN_FAILED;
for (uint16_t count = 0; count < fillCount; count++) { for (uint16_t count = 0; count < fillCount; count++) {
result = registeredVariables[count]->deSerialize(buffer, size, result = registeredVariables[count]->deSerialize(buffer, size,
streamEndianness); streamEndianness);
if (result != HasReturnvaluesIF::RETURN_OK) { if (result != HasReturnvaluesIF::RETURN_OK) {
return result; return result;
} }
} }
return result; return result;
} }
size_t PoolDataSetBase::getSerializedSize() const { size_t PoolDataSetBase::getSerializedSize() const {
uint32_t size = 0; uint32_t size = 0;
for (uint16_t count = 0; count < fillCount; count++) { for (uint16_t count = 0; count < fillCount; count++) {
size += registeredVariables[count]->getSerializedSize(); size += registeredVariables[count]->getSerializedSize();
} }
return size; return size;
} }
void PoolDataSetBase::setContainer(PoolVariableIF **variablesContainer) { void PoolDataSetBase::setContainer(PoolVariableIF **variablesContainer) {
@ -219,13 +218,13 @@ void PoolDataSetBase::setContainer(PoolVariableIF **variablesContainer) {
} }
PoolVariableIF** PoolDataSetBase::getContainer() const { PoolVariableIF** PoolDataSetBase::getContainer() const {
return registeredVariables; return registeredVariables;
} }
void PoolDataSetBase::setReadCommitProtectionBehaviour( void PoolDataSetBase::setReadCommitProtectionBehaviour(
bool protectEveryReadCommit, MutexIF::TimeoutType timeoutType, bool protectEveryReadCommit, MutexIF::TimeoutType timeoutType,
uint32_t mutexTimeout) { uint32_t mutexTimeout) {
this->protectEveryReadCommitCall = protectEveryReadCommit; this->protectEveryReadCommitCall = protectEveryReadCommit;
this->timeoutTypeForSingleVars = timeoutType; this->timeoutTypeForSingleVars = timeoutType;
this->mutexTimeoutForSingleVars = mutexTimeout; this->mutexTimeoutForSingleVars = mutexTimeout;
} }

View File

@ -29,98 +29,99 @@
* @author Bastian Baetz * @author Bastian Baetz
* @ingroup data_pool * @ingroup data_pool
*/ */
class PoolDataSetBase: public PoolDataSetIF, class PoolDataSetBase:
public SerializeIF, public PoolDataSetIF,
public HasReturnvaluesIF { public SerializeIF,
public HasReturnvaluesIF {
public: public:
/** /**
* @brief Creates an empty dataset. Use registerVariable or * @brief Creates an empty dataset. Use registerVariable or
* supply a pointer to this dataset to PoolVariable * supply a pointer to this dataset to PoolVariable
* initializations to register pool variables. * initializations to register pool variables.
*/ */
PoolDataSetBase(PoolVariableIF** registeredVariablesArray, const size_t maxFillCount); PoolDataSetBase(PoolVariableIF** registeredVariablesArray, const size_t maxFillCount);
/* Forbidden for now */ /* Forbidden for now */
PoolDataSetBase(const PoolDataSetBase& otherSet) = delete; PoolDataSetBase(const PoolDataSetBase& otherSet) = delete;
const PoolDataSetBase& operator=(const PoolDataSetBase& otherSet) = delete; const PoolDataSetBase& operator=(const PoolDataSetBase& otherSet) = delete;
virtual~ PoolDataSetBase(); virtual~ PoolDataSetBase();
/** /**
* @brief The read call initializes reading out all registered variables. * @brief The read call initializes reading out all registered variables.
* It is mandatory to call commit after every read call! * It is mandatory to call commit after every read call!
* @details * @details
* It iterates through the list of registered variables and calls all read() * It iterates through the list of registered variables and calls all read()
* functions of the registered pool variables (which read out their values * functions of the registered pool variables (which read out their values
* from the data pool) which are not write-only. * from the data pool) which are not write-only.
* In case of an error (e.g. a wrong data type, or an invalid data pool id), * In case of an error (e.g. a wrong data type, or an invalid data pool id),
* the operation is aborted and @c INVALID_PARAMETER_DEFINITION returned. * the operation is aborted and @c INVALID_PARAMETER_DEFINITION returned.
* *
* The data pool is locked during the whole read operation and * The data pool is locked during the whole read operation and
* freed afterwards. It is mandatory to call commit after a read call, * freed afterwards. It is mandatory to call commit after a read call,
* even if the read operation is not successful! * even if the read operation is not successful!
* @return * @return
* - @c RETURN_OK if all variables were read successfully. * - @c RETURN_OK if all variables were read successfully.
* - @c INVALID_PARAMETER_DEFINITION if a pool entry does not exist or there * - @c INVALID_PARAMETER_DEFINITION if a pool entry does not exist or there
* is a type conflict. * is a type conflict.
* - @c SET_WAS_ALREADY_READ if read() is called twice without calling * - @c SET_WAS_ALREADY_READ if read() is called twice without calling
* commit() in between * commit() in between
*/ */
virtual ReturnValue_t read(MutexIF::TimeoutType timeoutType = MutexIF::TimeoutType::WAITING, virtual ReturnValue_t read(MutexIF::TimeoutType timeoutType = MutexIF::TimeoutType::WAITING,
uint32_t lockTimeout = 20) override; uint32_t lockTimeout = 20) override;
/** /**
* @brief The commit call initializes writing back the registered variables. * @brief The commit call initializes writing back the registered variables.
* @details * @details
* It iterates through the list of registered variables and calls the * It iterates through the list of registered variables and calls the
* commit() method of the remaining registered variables (which write back * commit() method of the remaining registered variables (which write back
* their values to the pool). * their values to the pool).
* *
* The data pool is locked during the whole commit operation and * The data pool is locked during the whole commit operation and
* freed afterwards. The state changes to "was committed" after this operation. * freed afterwards. The state changes to "was committed" after this operation.
* *
* If the set does contain at least one variable which is not write-only * If the set does contain at least one variable which is not write-only
* commit() can only be called after read(). If the set only contains * commit() can only be called after read(). If the set only contains
* variables which are write only, commit() can be called without a * variables which are write only, commit() can be called without a
* preceding read() call. Every read call must be followed by a commit call! * preceding read() call. Every read call must be followed by a commit call!
* @return - @c RETURN_OK if all variables were read successfully. * @return - @c RETURN_OK if all variables were read successfully.
* - @c COMMITING_WITHOUT_READING if set was not read yet and * - @c COMMITING_WITHOUT_READING if set was not read yet and
* contains non write-only variables * contains non write-only variables
*/ */
virtual ReturnValue_t commit(MutexIF::TimeoutType timeoutType = MutexIF::TimeoutType::WAITING, virtual ReturnValue_t commit(MutexIF::TimeoutType timeoutType = MutexIF::TimeoutType::WAITING,
uint32_t lockTimeout = 20) override; uint32_t lockTimeout = 20) override;
/** /**
* Register the passed pool variable instance into the data set. * Register the passed pool variable instance into the data set.
* @param variable * @param variable
* @return * @return
*/ */
virtual ReturnValue_t registerVariable( PoolVariableIF* variable) override; virtual ReturnValue_t registerVariable( PoolVariableIF* variable) override;
/** /**
* Provides the means to lock the underlying data structure to ensure * Provides the means to lock the underlying data structure to ensure
* thread-safety. Default implementation is empty * thread-safety. Default implementation is empty
* @return Always returns -@c RETURN_OK * @return Always returns -@c RETURN_OK
*/ */
virtual ReturnValue_t lockDataPool( virtual ReturnValue_t lockDataPool(
MutexIF::TimeoutType timeoutType = MutexIF::TimeoutType::WAITING, MutexIF::TimeoutType timeoutType = MutexIF::TimeoutType::WAITING,
uint32_t timeoutMs = 20) override; uint32_t timeoutMs = 20) override;
/** /**
* Provides the means to unlock the underlying data structure to ensure * Provides the means to unlock the underlying data structure to ensure
* thread-safety. Default implementation is empty * thread-safety. Default implementation is empty
* @return Always returns -@c RETURN_OK * @return Always returns -@c RETURN_OK
*/ */
virtual ReturnValue_t unlockDataPool() override; virtual ReturnValue_t unlockDataPool() override;
virtual uint16_t getFillCount() const; virtual uint16_t getFillCount() const;
/* SerializeIF implementations */ /* SerializeIF implementations */
virtual ReturnValue_t serialize(uint8_t** buffer, size_t* size, virtual ReturnValue_t serialize(uint8_t** buffer, size_t* size,
const size_t maxSize, const size_t maxSize,
SerializeIF::Endianness streamEndianness) const override; SerializeIF::Endianness streamEndianness) const override;
virtual size_t getSerializedSize() const override; virtual size_t getSerializedSize() const override;
virtual ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size, virtual ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size,
SerializeIF::Endianness streamEndianness) override; SerializeIF::Endianness streamEndianness) override;
/** /**
* Can be used to individually protect every read and commit call. * Can be used to individually protect every read and commit call.
@ -132,48 +133,48 @@ public:
uint32_t mutexTimeout = 20); uint32_t mutexTimeout = 20);
protected: protected:
/** /**
* @brief The fill_count attribute ensures that the variables * @brief The fill_count attribute ensures that the variables
* register in the correct array position and that the maximum * register in the correct array position and that the maximum
* number of variables is not exceeded. * number of variables is not exceeded.
*/ */
uint16_t fillCount = 0; uint16_t fillCount = 0;
/** /**
* States of the seet. * States of the seet.
*/ */
enum class States { enum class States {
STATE_SET_UNINITIALISED, //!< DATA_SET_UNINITIALISED STATE_SET_UNINITIALISED, //!< DATA_SET_UNINITIALISED
STATE_SET_WAS_READ //!< DATA_SET_WAS_READ STATE_SET_WAS_READ //!< DATA_SET_WAS_READ
}; };
/** /**
* @brief state manages the internal state of the data set, * @brief state manages the internal state of the data set,
* which is important e.g. for the behavior on destruction. * which is important e.g. for the behavior on destruction.
*/ */
States state = States::STATE_SET_UNINITIALISED; States state = States::STATE_SET_UNINITIALISED;
/** /**
* @brief This array represents all pool variables registered in this set. * @brief This array represents all pool variables registered in this set.
* Child classes can use a static or dynamic container to create * Child classes can use a static or dynamic container to create
* an array of registered variables and assign the first entry here. * an array of registered variables and assign the first entry here.
*/ */
PoolVariableIF** registeredVariables = nullptr; PoolVariableIF** registeredVariables = nullptr;
const size_t maxFillCount = 0; const size_t maxFillCount = 0;
void setContainer(PoolVariableIF** variablesContainer); void setContainer(PoolVariableIF** variablesContainer);
PoolVariableIF** getContainer() const; PoolVariableIF** getContainer() const;
private: private:
bool protectEveryReadCommitCall = false; bool protectEveryReadCommitCall = false;
MutexIF::TimeoutType timeoutTypeForSingleVars = MutexIF::TimeoutType::WAITING; MutexIF::TimeoutType timeoutTypeForSingleVars = MutexIF::TimeoutType::WAITING;
uint32_t mutexTimeoutForSingleVars = 20; uint32_t mutexTimeoutForSingleVars = 20;
ReturnValue_t readVariable(uint16_t count); ReturnValue_t readVariable(uint16_t count);
void handleAlreadyReadDatasetCommit( void handleAlreadyReadDatasetCommit(
MutexIF::TimeoutType timeoutType = MutexIF::TimeoutType::WAITING, MutexIF::TimeoutType timeoutType = MutexIF::TimeoutType::WAITING,
uint32_t timeoutMs = 20); uint32_t timeoutMs = 20);
ReturnValue_t handleUnreadDatasetCommit( ReturnValue_t handleUnreadDatasetCommit(
MutexIF::TimeoutType timeoutType = MutexIF::TimeoutType::WAITING, MutexIF::TimeoutType timeoutType = MutexIF::TimeoutType::WAITING,
uint32_t timeoutMs = 20); uint32_t timeoutMs = 20);
}; };
#endif /* FSFW_DATAPOOL_POOLDATASETBASE_H_ */ #endif /* FSFW_DATAPOOL_POOLDATASETBASE_H_ */

View File

@ -8,7 +8,9 @@
* @brief Extendes the DataSetIF by adding abstract functions to lock * @brief Extendes the DataSetIF by adding abstract functions to lock
* and unlock a data pool and read/commit semantics. * and unlock a data pool and read/commit semantics.
*/ */
class PoolDataSetIF: public DataSetIF, public ReadCommitIF { class PoolDataSetIF:
public DataSetIF,
public ReadCommitIF {
public: public:
virtual~ PoolDataSetIF() {}; virtual~ PoolDataSetIF() {};

View File

@ -8,9 +8,9 @@
/** /**
* @brief Helper class to read data sets or pool variables * @brief Helper class to read data sets or pool variables
*/ */
class PoolReadHelper { class PoolReadGuard {
public: public:
PoolReadHelper(ReadCommitIF* readObject, PoolReadGuard(ReadCommitIF* readObject,
MutexIF::TimeoutType timeoutType = MutexIF::TimeoutType::WAITING, MutexIF::TimeoutType timeoutType = MutexIF::TimeoutType::WAITING,
uint32_t mutexTimeout = 20): uint32_t mutexTimeout = 20):
readObject(readObject), mutexTimeout(mutexTimeout) { readObject(readObject), mutexTimeout(mutexTimeout) {
@ -32,8 +32,18 @@ public:
return readResult; return readResult;
} }
~PoolReadHelper() { /**
if(readObject != nullptr) { * @brief Can be used to suppress commit on destruction.
*/
void setNoCommitMode(bool commit) {
this->noCommit = commit;
}
/**
* @brief Default destructor which will take care of commiting changed values.
*/
~PoolReadGuard() {
if(readObject != nullptr and not noCommit) {
readObject->commit(timeoutType, mutexTimeout); readObject->commit(timeoutType, mutexTimeout);
} }
@ -42,6 +52,7 @@ public:
private: private:
ReadCommitIF* readObject = nullptr; ReadCommitIF* readObject = nullptr;
ReturnValue_t readResult = HasReturnvaluesIF::RETURN_OK; ReturnValue_t readResult = HasReturnvaluesIF::RETURN_OK;
bool noCommit = false;
MutexIF::TimeoutType timeoutType = MutexIF::TimeoutType::WAITING; MutexIF::TimeoutType timeoutType = MutexIF::TimeoutType::WAITING;
uint32_t mutexTimeout = 20; uint32_t mutexTimeout = 20;
}; };

View File

@ -1,9 +1,10 @@
#ifndef FSFW_DATAPOOL_POOLVARIABLEIF_H_ #ifndef FSFW_DATAPOOL_POOLVARIABLEIF_H_
#define FSFW_DATAPOOL_POOLVARIABLEIF_H_ #define FSFW_DATAPOOL_POOLVARIABLEIF_H_
#include "ReadCommitIF.h"
#include "../returnvalues/HasReturnvaluesIF.h" #include "../returnvalues/HasReturnvaluesIF.h"
#include "../serialize/SerializeIF.h" #include "../serialize/SerializeIF.h"
#include "ReadCommitIF.h"
/** /**
* @brief This interface is used to control data pool * @brief This interface is used to control data pool
@ -18,47 +19,48 @@
* @author Bastian Baetz * @author Bastian Baetz
* @ingroup data_pool * @ingroup data_pool
*/ */
class PoolVariableIF : public SerializeIF, class PoolVariableIF :
public ReadCommitIF { public SerializeIF,
friend class PoolDataSetBase; public ReadCommitIF {
friend class LocalPoolDataSetBase;
public: public:
static constexpr uint8_t INTERFACE_ID = CLASS_ID::POOL_VARIABLE_IF; static constexpr uint8_t INTERFACE_ID = CLASS_ID::POOL_VARIABLE_IF;
static constexpr ReturnValue_t INVALID_READ_WRITE_MODE = MAKE_RETURN_CODE(0xA0); static constexpr ReturnValue_t INVALID_READ_WRITE_MODE = MAKE_RETURN_CODE(0xA0);
static constexpr ReturnValue_t INVALID_POOL_ENTRY = MAKE_RETURN_CODE(0xA1); static constexpr ReturnValue_t INVALID_POOL_ENTRY = MAKE_RETURN_CODE(0xA1);
static constexpr bool VALID = 1; static constexpr bool VALID = 1;
static constexpr bool INVALID = 0; static constexpr bool INVALID = 0;
static constexpr uint32_t NO_PARAMETER = 0xffffffff; static constexpr uint32_t NO_PARAMETER = 0xffffffff;
enum ReadWriteMode_t { enum ReadWriteMode_t {
VAR_READ, VAR_WRITE, VAR_READ_WRITE VAR_READ, VAR_WRITE, VAR_READ_WRITE
}; };
/** /**
* @brief This is an empty virtual destructor, * @brief This is an empty virtual destructor,
* as it is proposed for C++ interfaces. * as it is proposed for C++ interfaces.
*/ */
virtual ~PoolVariableIF() {} virtual ~PoolVariableIF() {}
/** /**
* @brief This method returns if the variable is write-only, * @brief This method returns if the variable is write-only,
* read-write or read-only. * read-write or read-only.
*/ */
virtual ReadWriteMode_t getReadWriteMode() const = 0; virtual ReadWriteMode_t getReadWriteMode() const = 0;
/** virtual void setReadWriteMode(ReadWriteMode_t newMode) = 0;
* @brief This operation shall return the data pool id of the variable.
*/
virtual uint32_t getDataPoolId() const = 0;
/**
* @brief With this call, the valid information of the
* variable is returned.
*/
virtual bool isValid() const = 0;
/**
* @brief With this call, the valid information of the variable is set.
*/
virtual void setValid(bool validity) = 0;
/**
* @brief This operation shall return the data pool id of the variable.
*/
virtual uint32_t getDataPoolId() const = 0;
/**
* @brief With this call, the valid information of the
* variable is returned.
*/
virtual bool isValid() const = 0;
/**
* @brief With this call, the valid information of the variable is set.
*/
virtual void setValid(bool validity) = 0;
}; };
using pool_rwm_t = PoolVariableIF::ReadWriteMode_t; using pool_rwm_t = PoolVariableIF::ReadWriteMode_t;

View File

@ -9,6 +9,7 @@
* semantics. * semantics.
*/ */
class ReadCommitIF { class ReadCommitIF {
friend class ReadCommitIFAttorney;
public: public:
virtual ~ReadCommitIF() {} virtual ~ReadCommitIF() {}
virtual ReturnValue_t read(MutexIF::TimeoutType timeoutType, virtual ReturnValue_t read(MutexIF::TimeoutType timeoutType,
@ -18,9 +19,8 @@ public:
protected: protected:
//! Optional and protected because this is interesting for classes grouping /* Optional and protected because this is interesting for classes grouping members with commit
//! members with commit and read semantics where the lock is only necessary and read semantics where the lock is only necessary once. */
//! once.
virtual ReturnValue_t readWithoutLock() { virtual ReturnValue_t readWithoutLock() {
return read(MutexIF::TimeoutType::WAITING, 20); return read(MutexIF::TimeoutType::WAITING, 20);
} }

View File

@ -0,0 +1,32 @@
#ifndef FSFW_DATAPOOL_READCOMMITIFATTORNEY_H_
#define FSFW_DATAPOOL_READCOMMITIFATTORNEY_H_
#include <fsfw/datapool/ReadCommitIF.h>
#include <fsfw/returnvalues/HasReturnvaluesIF.h>
/**
* @brief This class determines which members are allowed to access protected members
* of the ReadCommitIF.
*/
class ReadCommitIFAttorney {
private:
static ReturnValue_t readWithoutLock(ReadCommitIF* readCommitIF) {
if(readCommitIF == nullptr) {
return HasReturnvaluesIF::RETURN_FAILED;
}
return readCommitIF->readWithoutLock();
}
static ReturnValue_t commitWithoutLock(ReadCommitIF* readCommitIF) {
if(readCommitIF == nullptr) {
return HasReturnvaluesIF::RETURN_FAILED;
}
return readCommitIF->commitWithoutLock();
}
friend class PoolDataSetBase;
};
#endif /* FSFW_DATAPOOL_READCOMMITIFATTORNEY_H_ */

View File

@ -23,11 +23,21 @@ class LocalPoolObjectBase;
* @details * @details
* Any class implementing this interface shall also have a LocalDataPoolManager member class which * Any class implementing this interface shall also have a LocalDataPoolManager member class which
* contains the actual pool data structure and exposes the public interface for it. * contains the actual pool data structure and exposes the public interface for it.
*
* The local data pool can be accessed using helper classes by using the * The local data pool can be accessed using helper classes by using the
* LocalPoolVariable, LocalPoolVector or LocalDataSet classes. Every local pool variable can * LocalPoolVariable, LocalPoolVector or LocalDataSet classes. Every local pool variable can
* be uniquely identified by a global pool ID (gp_id_t) and every dataset tied * be uniquely identified by a global pool ID (gp_id_t) and every dataset tied
* to a pool manager can be uniqely identified by a global structure ID (sid_t). * to a pool manager can be uniqely identified by a global structure ID (sid_t).
* *
* All software objects which want to use the local pool of another object shall also use this
* interface, for example to get a handle to the subscription interface. The interface
* can be retrieved using the object manager, provided the target object is a SystemObject.
* For example, the following line of code can be used to retrieve the interface
*
* HasLocalDataPoolIF* poolIF = objectManager->get<HasLocalDataPoolIF>(objects::SOME_OBJECT);
* if(poolIF != nullptr) {
* doSomething()
* }
*/ */
class HasLocalDataPoolIF { class HasLocalDataPoolIF {
friend class HasLocalDpIFManagerAttorney; friend class HasLocalDpIFManagerAttorney;
@ -152,8 +162,8 @@ protected:
*/ */
virtual LocalPoolObjectBase* getPoolObjectHandle(lp_id_t localPoolId) { virtual LocalPoolObjectBase* getPoolObjectHandle(lp_id_t localPoolId) {
#if FSFW_CPP_OSTREAM_ENABLED == 1 #if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning << "HasLocalDataPoolIF::getPoolObjectHandle: Not overriden" sif::warning << "HasLocalDataPoolIF::getPoolObjectHandle: Not overriden. "
<< ". Returning nullptr!" << std::endl; "Returning nullptr!" << std::endl;
#else #else
sif::printWarning("HasLocalDataPoolIF::getPoolObjectHandle: " sif::printWarning("HasLocalDataPoolIF::getPoolObjectHandle: "
"Not overriden. Returning nullptr!\n"); "Not overriden. Returning nullptr!\n");

View File

@ -42,15 +42,15 @@ LocalDataPoolManager::~LocalDataPoolManager() {}
ReturnValue_t LocalDataPoolManager::initialize(MessageQueueIF* queueToUse) { ReturnValue_t LocalDataPoolManager::initialize(MessageQueueIF* queueToUse) {
if(queueToUse == nullptr) { if(queueToUse == nullptr) {
// error, all destinations invalid /* Error, all destinations invalid */
printWarningOrError(sif::OutputTypes::OUT_ERROR, printWarningOrError(sif::OutputTypes::OUT_ERROR, "initialize",
"initialize", QUEUE_OR_DESTINATION_INVALID); QUEUE_OR_DESTINATION_INVALID);
} }
hkQueue = queueToUse; hkQueue = queueToUse;
ipcStore = objectManager->get<StorageManagerIF>(objects::IPC_STORE); ipcStore = objectManager->get<StorageManagerIF>(objects::IPC_STORE);
if(ipcStore == nullptr) { if(ipcStore == nullptr) {
// error, all destinations invalid /* Error, all destinations invalid */
printWarningOrError(sif::OutputTypes::OUT_ERROR, printWarningOrError(sif::OutputTypes::OUT_ERROR,
"initialize", HasReturnvaluesIF::RETURN_FAILED, "initialize", HasReturnvaluesIF::RETURN_FAILED,
"Could not set IPC store."); "Could not set IPC store.");
@ -98,7 +98,7 @@ ReturnValue_t LocalDataPoolManager::initializeHousekeepingPoolEntriesOnce() {
ReturnValue_t LocalDataPoolManager::performHkOperation() { ReturnValue_t LocalDataPoolManager::performHkOperation() {
ReturnValue_t status = HasReturnvaluesIF::RETURN_OK; ReturnValue_t status = HasReturnvaluesIF::RETURN_OK;
for(auto& receiver: hkReceiversMap) { for(auto& receiver: hkReceivers) {
switch(receiver.reportingType) { switch(receiver.reportingType) {
case(ReportingType::PERIODIC): { case(ReportingType::PERIODIC): {
if(receiver.dataType == DataType::LOCAL_POOL_VARIABLE) { if(receiver.dataType == DataType::LOCAL_POOL_VARIABLE) {
@ -375,12 +375,12 @@ ReturnValue_t LocalDataPoolManager::subscribeForPeriodicPacket(sid_t sid,
owner->getPeriodicOperationFrequency(), isDiagnostics); owner->getPeriodicOperationFrequency(), isDiagnostics);
} }
hkReceiversMap.push_back(hkReceiver); hkReceivers.push_back(hkReceiver);
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
} }
ReturnValue_t LocalDataPoolManager::subscribeForUpdatePackets(sid_t sid, ReturnValue_t LocalDataPoolManager::subscribeForUpdatePacket(sid_t sid,
bool isDiagnostics, bool reportingEnabled, bool isDiagnostics, bool reportingEnabled,
object_id_t packetDestination) { object_id_t packetDestination) {
AcceptsHkPacketsIF* hkReceiverObject = AcceptsHkPacketsIF* hkReceiverObject =
@ -404,13 +404,13 @@ ReturnValue_t LocalDataPoolManager::subscribeForUpdatePackets(sid_t sid,
LocalPoolDataSetAttorney::setDiagnostic(*dataSet, isDiagnostics); LocalPoolDataSetAttorney::setDiagnostic(*dataSet, isDiagnostics);
} }
hkReceiversMap.push_back(hkReceiver); hkReceivers.push_back(hkReceiver);
handleHkUpdateResetListInsertion(hkReceiver.dataType, hkReceiver.dataId); handleHkUpdateResetListInsertion(hkReceiver.dataType, hkReceiver.dataId);
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
} }
ReturnValue_t LocalDataPoolManager::subscribeForSetUpdateMessages( ReturnValue_t LocalDataPoolManager::subscribeForSetUpdateMessage(
const uint32_t setId, object_id_t destinationObject, const uint32_t setId, object_id_t destinationObject,
MessageQueueId_t targetQueueId, bool generateSnapshot) { MessageQueueId_t targetQueueId, bool generateSnapshot) {
struct HkReceiver hkReceiver; struct HkReceiver hkReceiver;
@ -425,13 +425,13 @@ ReturnValue_t LocalDataPoolManager::subscribeForSetUpdateMessages(
hkReceiver.reportingType = ReportingType::UPDATE_NOTIFICATION; hkReceiver.reportingType = ReportingType::UPDATE_NOTIFICATION;
} }
hkReceiversMap.push_back(hkReceiver); hkReceivers.push_back(hkReceiver);
handleHkUpdateResetListInsertion(hkReceiver.dataType, hkReceiver.dataId); handleHkUpdateResetListInsertion(hkReceiver.dataType, hkReceiver.dataId);
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
} }
ReturnValue_t LocalDataPoolManager::subscribeForVariableUpdateMessages( ReturnValue_t LocalDataPoolManager::subscribeForVariableUpdateMessage(
const lp_id_t localPoolId, object_id_t destinationObject, const lp_id_t localPoolId, object_id_t destinationObject,
MessageQueueId_t targetQueueId, bool generateSnapshot) { MessageQueueId_t targetQueueId, bool generateSnapshot) {
struct HkReceiver hkReceiver; struct HkReceiver hkReceiver;
@ -446,7 +446,7 @@ ReturnValue_t LocalDataPoolManager::subscribeForVariableUpdateMessages(
hkReceiver.reportingType = ReportingType::UPDATE_NOTIFICATION; hkReceiver.reportingType = ReportingType::UPDATE_NOTIFICATION;
} }
hkReceiversMap.push_back(hkReceiver); hkReceivers.push_back(hkReceiver);
handleHkUpdateResetListInsertion(hkReceiver.dataType, hkReceiver.dataId); handleHkUpdateResetListInsertion(hkReceiver.dataType, hkReceiver.dataId);
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
@ -829,8 +829,8 @@ ReturnValue_t LocalDataPoolManager::generateSetStructurePacket(sid_t sid,
} }
void LocalDataPoolManager::clearReceiversList() { void LocalDataPoolManager::clearReceiversList() {
// clear the vector completely and releases allocated memory. /* Clear the vector completely and releases allocated memory. */
HkReceivers().swap(hkReceiversMap); HkReceivers().swap(hkReceivers);
} }
MutexIF* LocalDataPoolManager::getLocalPoolMutex() { MutexIF* LocalDataPoolManager::getLocalPoolMutex() {

View File

@ -137,7 +137,7 @@ public:
* @param packetDestination * @param packetDestination
* @return * @return
*/ */
ReturnValue_t subscribeForUpdatePackets(sid_t sid, bool reportingEnabled, ReturnValue_t subscribeForUpdatePacket(sid_t sid, bool reportingEnabled,
bool isDiagnostics, bool isDiagnostics,
object_id_t packetDestination = defaultHkDestination) override; object_id_t packetDestination = defaultHkDestination) override;
@ -155,7 +155,7 @@ public:
* Otherwise, only an notification message is sent. * Otherwise, only an notification message is sent.
* @return * @return
*/ */
ReturnValue_t subscribeForSetUpdateMessages(const uint32_t setId, ReturnValue_t subscribeForSetUpdateMessage(const uint32_t setId,
object_id_t destinationObject, object_id_t destinationObject,
MessageQueueId_t targetQueueId, MessageQueueId_t targetQueueId,
bool generateSnapshot) override; bool generateSnapshot) override;
@ -174,7 +174,7 @@ public:
* Otherwise, only an notification message is sent. * Otherwise, only an notification message is sent.
* @return * @return
*/ */
ReturnValue_t subscribeForVariableUpdateMessages(const lp_id_t localPoolId, ReturnValue_t subscribeForVariableUpdateMessage(const lp_id_t localPoolId,
object_id_t destinationObject, object_id_t destinationObject,
MessageQueueId_t targetQueueId, MessageQueueId_t targetQueueId,
bool generateSnapshot) override; bool generateSnapshot) override;
@ -271,7 +271,10 @@ public:
MutexIF* getMutexHandle(); MutexIF* getMutexHandle();
virtual LocalDataPoolManager* getPoolManagerHandle() override; virtual LocalDataPoolManager* getPoolManagerHandle() override;
private:
protected:
/** Core data structure for the actual pool data */
localpool::DataPool localPoolMap; localpool::DataPool localPoolMap;
/** Every housekeeping data manager has a mutex to protect access /** Every housekeeping data manager has a mutex to protect access
to it's data pool. */ to it's data pool. */
@ -307,7 +310,7 @@ private:
/** This vector will contain the list of HK receivers. */ /** This vector will contain the list of HK receivers. */
using HkReceivers = std::vector<struct HkReceiver>; using HkReceivers = std::vector<struct HkReceiver>;
HkReceivers hkReceiversMap; HkReceivers hkReceivers;
struct HkUpdateResetHelper { struct HkUpdateResetHelper {
DataType dataType = DataType::DATA_SET; DataType dataType = DataType::DATA_SET;
@ -317,7 +320,8 @@ private:
}; };
using HkUpdateResetList = std::vector<struct HkUpdateResetHelper>; using HkUpdateResetList = std::vector<struct HkUpdateResetHelper>;
// Will only be created when needed. /** This list is used to manage creating multiple update packets and only resetting
the update flag if all of them were created. Will only be created when needed. */
HkUpdateResetList* hkUpdateResetList = nullptr; HkUpdateResetList* hkUpdateResetList = nullptr;
/** This is the map holding the actual data. Should only be initialized /** This is the map holding the actual data. Should only be initialized
@ -341,16 +345,14 @@ private:
* Read a variable by supplying its local pool ID and assign the pool * Read a variable by supplying its local pool ID and assign the pool
* entry to the supplied PoolEntry pointer. The type of the pool entry * entry to the supplied PoolEntry pointer. The type of the pool entry
* is deduced automatically. This call is not thread-safe! * is deduced automatically. This call is not thread-safe!
* For now, only friend classes like LocalPoolVar may access this * For now, only classes designated by the LocalDpManagerAttorney may use this function.
* function.
* @tparam T Type of the pool entry * @tparam T Type of the pool entry
* @param localPoolId Pool ID of the variable to read * @param localPoolId Pool ID of the variable to read
* @param poolVar [out] Corresponding pool entry will be assigned to the * @param poolVar [out] Corresponding pool entry will be assigned to the
* supplied pointer. * supplied pointer.
* @return * @return
*/ */
template <class T> ReturnValue_t fetchPoolEntry(lp_id_t localPoolId, template <class T> ReturnValue_t fetchPoolEntry(lp_id_t localPoolId, PoolEntry<T> **poolEntry);
PoolEntry<T> **poolEntry);
/** /**
* This function is used to fill the local data pool map with pool * This function is used to fill the local data pool map with pool
@ -362,15 +364,13 @@ private:
MutexIF* getLocalPoolMutex() override; MutexIF* getLocalPoolMutex() override;
ReturnValue_t serializeHkPacketIntoStore( ReturnValue_t serializeHkPacketIntoStore(HousekeepingPacketDownlink& hkPacket,
HousekeepingPacketDownlink& hkPacket,
store_address_t& storeId, bool forDownlink, size_t* serializedSize); store_address_t& storeId, bool forDownlink, size_t* serializedSize);
void performPeriodicHkGeneration(HkReceiver& hkReceiver); void performPeriodicHkGeneration(HkReceiver& hkReceiver);
ReturnValue_t togglePeriodicGeneration(sid_t sid, bool enable, ReturnValue_t togglePeriodicGeneration(sid_t sid, bool enable, bool isDiagnostics);
ReturnValue_t changeCollectionInterval(sid_t sid, float newCollectionInterval,
bool isDiagnostics); bool isDiagnostics);
ReturnValue_t changeCollectionInterval(sid_t sid,
float newCollectionInterval, bool isDiagnostics);
ReturnValue_t generateSetStructurePacket(sid_t sid, bool isDiagnostics); ReturnValue_t generateSetStructurePacket(sid_t sid, bool isDiagnostics);
void handleHkUpdateResetListInsertion(DataType dataType, DataId dataId); void handleHkUpdateResetListInsertion(DataType dataType, DataId dataId);
@ -378,25 +378,19 @@ private:
DataId dataId, MarkChangedIF* toReset); DataId dataId, MarkChangedIF* toReset);
void resetHkUpdateResetHelper(); void resetHkUpdateResetHelper();
ReturnValue_t handleHkUpdate(HkReceiver& hkReceiver, ReturnValue_t handleHkUpdate(HkReceiver& hkReceiver, ReturnValue_t& status);
ReturnValue_t& status); ReturnValue_t handleNotificationUpdate(HkReceiver& hkReceiver, ReturnValue_t& status);
ReturnValue_t handleNotificationUpdate(HkReceiver& hkReceiver, ReturnValue_t handleNotificationSnapshot(HkReceiver& hkReceiver, ReturnValue_t& status);
ReturnValue_t& status); ReturnValue_t addUpdateToStore(HousekeepingSnapshot& updatePacket, store_address_t& storeId);
ReturnValue_t handleNotificationSnapshot(HkReceiver& hkReceiver,
ReturnValue_t& status);
ReturnValue_t addUpdateToStore(HousekeepingSnapshot& updatePacket,
store_address_t& storeId);
void printWarningOrError(sif::OutputTypes outputType, void printWarningOrError(sif::OutputTypes outputType, const char* functionName,
const char* functionName,
ReturnValue_t errorCode = HasReturnvaluesIF::RETURN_FAILED, ReturnValue_t errorCode = HasReturnvaluesIF::RETURN_FAILED,
const char* errorPrint = nullptr); const char* errorPrint = nullptr);
}; };
template<class T> inline template<class T> inline
ReturnValue_t LocalDataPoolManager::fetchPoolEntry(lp_id_t localPoolId, ReturnValue_t LocalDataPoolManager::fetchPoolEntry(lp_id_t localPoolId, PoolEntry<T> **poolEntry) {
PoolEntry<T> **poolEntry) {
auto poolIter = localPoolMap.find(localPoolId); auto poolIter = localPoolMap.find(localPoolId);
if (poolIter == localPoolMap.end()) { if (poolIter == localPoolMap.end()) {
printWarningOrError(sif::OutputTypes::OUT_WARNING, "fetchPoolEntry", printWarningOrError(sif::OutputTypes::OUT_WARNING, "fetchPoolEntry",

View File

@ -3,6 +3,7 @@
#include "internal/HasLocalDpIFUserAttorney.h" #include "internal/HasLocalDpIFUserAttorney.h"
#include "../serviceinterface/ServiceInterface.h" #include "../serviceinterface/ServiceInterface.h"
#include "../globalfunctions/bitutility.h"
#include "../datapoollocal/LocalDataPoolManager.h" #include "../datapoollocal/LocalDataPoolManager.h"
#include "../housekeeping/PeriodicHousekeepingHelper.h" #include "../housekeeping/PeriodicHousekeepingHelper.h"
#include "../serialize/SerializeAdapter.h" #include "../serialize/SerializeAdapter.h"
@ -35,14 +36,13 @@ LocalPoolDataSetBase::LocalPoolDataSetBase(HasLocalDataPoolIF *hkOwner,
this->sid.objectId = hkOwner->getObjectId(); this->sid.objectId = hkOwner->getObjectId();
this->sid.ownerSetId = setId; this->sid.ownerSetId = setId;
// Data creators get a periodic helper for periodic HK data generation. /* Data creators get a periodic helper for periodic HK data generation. */
if(periodicHandling) { if(periodicHandling) {
periodicHelper = new PeriodicHousekeepingHelper(this); periodicHelper = new PeriodicHousekeepingHelper(this);
} }
} }
LocalPoolDataSetBase::LocalPoolDataSetBase(sid_t sid, LocalPoolDataSetBase::LocalPoolDataSetBase(sid_t sid, PoolVariableIF** registeredVariablesArray,
PoolVariableIF** registeredVariablesArray,
const size_t maxNumberOfVariables): const size_t maxNumberOfVariables):
PoolDataSetBase(registeredVariablesArray, maxNumberOfVariables) { PoolDataSetBase(registeredVariablesArray, maxNumberOfVariables) {
HasLocalDataPoolIF* hkOwner = objectManager->get<HasLocalDataPoolIF>( HasLocalDataPoolIF* hkOwner = objectManager->get<HasLocalDataPoolIF>(
@ -96,22 +96,22 @@ ReturnValue_t LocalPoolDataSetBase::serializeWithValidityBuffer(uint8_t **buffer
SerializeIF::Endianness streamEndianness) const { SerializeIF::Endianness streamEndianness) const {
ReturnValue_t result = HasReturnvaluesIF::RETURN_OK; ReturnValue_t result = HasReturnvaluesIF::RETURN_OK;
uint8_t validityMaskSize = std::ceil(static_cast<float>(fillCount)/8.0); uint8_t validityMaskSize = std::ceil(static_cast<float>(fillCount)/8.0);
uint8_t validityMask[validityMaskSize]; uint8_t validityMask[validityMaskSize] = {};
uint8_t validBufferIndex = 0; uint8_t validBufferIndex = 0;
uint8_t validBufferIndexBit = 0; uint8_t validBufferIndexBit = 0;
for (uint16_t count = 0; count < fillCount; count++) { for (uint16_t count = 0; count < fillCount; count++) {
if(registeredVariables[count]->isValid()) { if(registeredVariables[count]->isValid()) {
// set validity buffer here. /* Set bit at correct position */
this->bitSetter(validityMask + validBufferIndex, bitutil::bitSet(validityMask + validBufferIndex, validBufferIndexBit);
validBufferIndexBit);
if(validBufferIndexBit == 7) {
validBufferIndex ++;
validBufferIndexBit = 0;
}
else {
validBufferIndexBit ++;
}
} }
if(validBufferIndexBit == 7) {
validBufferIndex ++;
validBufferIndexBit = 0;
}
else {
validBufferIndexBit ++;
}
result = registeredVariables[count]->serialize(buffer, size, maxSize, result = registeredVariables[count]->serialize(buffer, size, maxSize,
streamEndianness); streamEndianness);
if (result != HasReturnvaluesIF::RETURN_OK) { if (result != HasReturnvaluesIF::RETURN_OK) {
@ -148,7 +148,7 @@ ReturnValue_t LocalPoolDataSetBase::deSerializeWithValidityBuffer(
uint8_t validBufferIndexBit = 0; uint8_t validBufferIndexBit = 0;
for (uint16_t count = 0; count < fillCount; count++) { for (uint16_t count = 0; count < fillCount; count++) {
// set validity buffer here. // set validity buffer here.
bool nextVarValid = this->bitGetter(*buffer + bool nextVarValid = bitutil::bitGet(*buffer +
validBufferIndex, validBufferIndexBit); validBufferIndex, validBufferIndexBit);
registeredVariables[count]->setValid(nextVarValid); registeredVariables[count]->setValid(nextVarValid);
@ -173,7 +173,7 @@ ReturnValue_t LocalPoolDataSetBase::unlockDataPool() {
ReturnValue_t LocalPoolDataSetBase::serializeLocalPoolIds(uint8_t** buffer, ReturnValue_t LocalPoolDataSetBase::serializeLocalPoolIds(uint8_t** buffer,
size_t* size, size_t maxSize,SerializeIF::Endianness streamEndianness, size_t* size, size_t maxSize,SerializeIF::Endianness streamEndianness,
bool serializeFillCount) const { bool serializeFillCount) const {
// Serialize as uint8_t /* Serialize fill count as uint8_t */
uint8_t fillCount = this->fillCount; uint8_t fillCount = this->fillCount;
if(serializeFillCount) { if(serializeFillCount) {
SerializeAdapter::serialize(&fillCount, buffer, size, maxSize, SerializeAdapter::serialize(&fillCount, buffer, size, maxSize,
@ -246,21 +246,6 @@ ReturnValue_t LocalPoolDataSetBase::serialize(uint8_t **buffer, size_t *size,
} }
} }
void LocalPoolDataSetBase::bitSetter(uint8_t* byte, uint8_t position) const {
if(position > 7) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning << "LocalPoolDataSetBase::bitSetter: Invalid position!"
<< std::endl;
#else
sif::printWarning("LocalPoolDataSetBase::bitSetter: "
"Invalid position!\n\r");
#endif
return;
}
uint8_t shiftNumber = position + (7 - 2 * position);
*byte |= 1 << shiftNumber;
}
void LocalPoolDataSetBase::setDiagnostic(bool isDiagnostics) { void LocalPoolDataSetBase::setDiagnostic(bool isDiagnostics) {
this->diagnostic = isDiagnostics; this->diagnostic = isDiagnostics;
} }
@ -296,19 +281,6 @@ sid_t LocalPoolDataSetBase::getSid() const {
return sid; return sid;
} }
bool LocalPoolDataSetBase::bitGetter(const uint8_t* byte,
uint8_t position) const {
if(position > 7) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::debug << "Pool Raw Access: Bit setting invalid position"
<< std::endl;
#endif
return false;
}
uint8_t shiftNumber = position + (7 - 2 * position);
return *byte & (1 << shiftNumber);
}
bool LocalPoolDataSetBase::isValid() const { bool LocalPoolDataSetBase::isValid() const {
return this->valid; return this->valid;
} }
@ -316,7 +288,7 @@ bool LocalPoolDataSetBase::isValid() const {
void LocalPoolDataSetBase::setValidity(bool valid, bool setEntriesRecursively) { void LocalPoolDataSetBase::setValidity(bool valid, bool setEntriesRecursively) {
if(setEntriesRecursively) { if(setEntriesRecursively) {
for(size_t idx = 0; idx < this->getFillCount(); idx++) { for(size_t idx = 0; idx < this->getFillCount(); idx++) {
registeredVariables[idx] -> setValid(valid); registeredVariables[idx]->setValid(valid);
} }
} }
this->valid = valid; this->valid = valid;
@ -328,3 +300,9 @@ object_id_t LocalPoolDataSetBase::getCreatorObjectId() {
} }
return objects::NO_OBJECT; return objects::NO_OBJECT;
} }
void LocalPoolDataSetBase::setAllVariablesReadOnly() {
for(size_t idx = 0; idx < this->getFillCount(); idx++) {
registeredVariables[idx]->setReadWriteMode(pool_rwm_t::VAR_READ);
}
}

View File

@ -59,7 +59,7 @@ public:
/** /**
* @brief Constructor for users of the local pool data, which need * @brief Constructor for users of the local pool data, which need
* to access data created by one (!) HK manager. * to access data created by one HK manager.
* @details * @details
* Unlike the first constructor, no component for periodic handling * Unlike the first constructor, no component for periodic handling
* will be initiated. * will be initiated.
@ -109,6 +109,12 @@ public:
LocalPoolDataSetBase(const LocalPoolDataSetBase& otherSet) = delete; LocalPoolDataSetBase(const LocalPoolDataSetBase& otherSet) = delete;
const LocalPoolDataSetBase& operator=(const LocalPoolDataSetBase& otherSet) = delete; const LocalPoolDataSetBase& operator=(const LocalPoolDataSetBase& otherSet) = delete;
/**
* Helper functions used to set all currently contained variables to read-only.
* It is recommended to call this in set constructors intended to be used
* by data consumers to prevent accidentally changing pool data.
*/
void setAllVariablesReadOnly();
void setValidityBufferGeneration(bool withValidityBuffer); void setValidityBufferGeneration(bool withValidityBuffer);
sid_t getSid() const; sid_t getSid() const;
@ -218,13 +224,6 @@ protected:
*/ */
ReturnValue_t unlockDataPool() override; ReturnValue_t unlockDataPool() override;
/**
* Set n-th bit of a byte, with n being the position from 0
* (most significant bit) to 7 (least significant bit)
*/
void bitSetter(uint8_t* byte, uint8_t position) const;
bool bitGetter(const uint8_t* byte, uint8_t position) const;
PeriodicHousekeepingHelper* periodicHelper = nullptr; PeriodicHousekeepingHelper* periodicHelper = nullptr;
LocalDataPoolManager* poolManager = nullptr; LocalDataPoolManager* poolManager = nullptr;

View File

@ -1,10 +1,12 @@
#include "LocalPoolObjectBase.h" #include "LocalPoolObjectBase.h"
#include "LocalDataPoolManager.h" #include "LocalDataPoolManager.h"
#include "internal/HasLocalDpIFUserAttorney.h" #include "AccessLocalPoolF.h"
#include "HasLocalDataPoolIF.h" #include "HasLocalDataPoolIF.h"
#include "internal/HasLocalDpIFUserAttorney.h"
#include "../objectmanager/ObjectManagerIF.h" #include "../objectmanager/ObjectManagerIF.h"
LocalPoolObjectBase::LocalPoolObjectBase(lp_id_t poolId, HasLocalDataPoolIF* hkOwner, LocalPoolObjectBase::LocalPoolObjectBase(lp_id_t poolId, HasLocalDataPoolIF* hkOwner,
DataSetIF* dataSet, pool_rwm_t setReadWriteMode): DataSetIF* dataSet, pool_rwm_t setReadWriteMode):
localPoolId(poolId), readWriteMode(setReadWriteMode) { localPoolId(poolId), readWriteMode(setReadWriteMode) {
@ -35,15 +37,20 @@ LocalPoolObjectBase::LocalPoolObjectBase(object_id_t poolOwner, lp_id_t poolId,
if(poolId == PoolVariableIF::NO_PARAMETER) { if(poolId == PoolVariableIF::NO_PARAMETER) {
#if FSFW_CPP_OSTREAM_ENABLED == 1 #if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning << "LocalPoolVar<T>::LocalPoolVar: 0 passed as pool ID, " sif::warning << "LocalPoolVar<T>::LocalPoolVar: 0 passed as pool ID, "
<< "which is the NO_PARAMETER value!" << std::endl; "which is the NO_PARAMETER value!" << std::endl;
#else
sif::printWarning("LocalPoolVar<T>::LocalPoolVar: 0 passed as pool ID, "
"which is the NO_PARAMETER value!\n");
#endif #endif
} }
HasLocalDataPoolIF* hkOwner = objectManager->get<HasLocalDataPoolIF>(poolOwner); HasLocalDataPoolIF* hkOwner = objectManager->get<HasLocalDataPoolIF>(poolOwner);
if(hkOwner == nullptr) { if(hkOwner == nullptr) {
#if FSFW_CPP_OSTREAM_ENABLED == 1 #if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "LocalPoolVariable: The supplied pool owner did not " sif::error << "LocalPoolVariable: The supplied pool owner did not implement the correct "
<< "implement the correct interface" "interface HasLocalDataPoolIF!" << std::endl;
<< " HasLocalDataPoolIF!" << std::endl; #else
sif::printError( "LocalPoolVariable: The supplied pool owner did not implement the correct "
"interface HasLocalDataPoolIF!\n");
#endif #endif
return; return;
} }
@ -93,6 +100,10 @@ void LocalPoolObjectBase::setReadWriteMode(pool_rwm_t newReadWriteMode) {
void LocalPoolObjectBase::reportReadCommitError(const char* variableType, void LocalPoolObjectBase::reportReadCommitError(const char* variableType,
ReturnValue_t error, bool read, object_id_t objectId, lp_id_t lpId) { ReturnValue_t error, bool read, object_id_t objectId, lp_id_t lpId) {
#if FSFW_DISABLE_PRINTOUT == 0 #if FSFW_DISABLE_PRINTOUT == 0
const char* variablePrintout = variableType;
if(variablePrintout == nullptr) {
variablePrintout = "Unknown Type";
}
const char* type = nullptr; const char* type = nullptr;
if(read) { if(read) {
type = "read"; type = "read";
@ -119,12 +130,12 @@ void LocalPoolObjectBase::reportReadCommitError(const char* variableType,
} }
#if FSFW_CPP_OSTREAM_ENABLED == 1 #if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning << variableType << ": " << type << " call | " << errMsg << " | Owner: 0x" sif::warning << variablePrintout << ": " << type << " call | " << errMsg << " | Owner: 0x"
<< std::hex << std::setw(8) << std::setfill('0') << objectId << std::dec << std::hex << std::setw(8) << std::setfill('0') << objectId << std::dec
<< " LPID: " << lpId << std::endl; << " LPID: " << lpId << std::endl;
#else #else
sif::printWarning("%s: %s call | %s | Owner: 0x%08x LPID: %lu\n", sif::printWarning("%s: %s call | %s | Owner: 0x%08x LPID: %lu\n",
variableType, type, errMsg, objectId, lpId); variablePrintout, type, errMsg, objectId, lpId);
#endif /* FSFW_CPP_OSTREAM_ENABLED == 1 */ #endif /* FSFW_CPP_OSTREAM_ENABLED == 1 */
#endif /* FSFW_DISABLE_PRINTOUT == 0 */ #endif /* FSFW_DISABLE_PRINTOUT == 0 */
} }

View File

@ -26,8 +26,17 @@ inline LocalPoolVariable<T>::LocalPoolVariable(gp_id_t globalPoolId,
template<typename T> template<typename T>
inline ReturnValue_t LocalPoolVariable<T>::read( inline ReturnValue_t LocalPoolVariable<T>::read(
MutexIF::TimeoutType timeoutType, uint32_t timeoutMs) { MutexIF::TimeoutType timeoutType, uint32_t timeoutMs) {
MutexHelper(LocalDpManagerAttorney::getMutexHandle(*hkManager), timeoutType, timeoutMs); if(hkManager == nullptr) {
return readWithoutLock(); return readWithoutLock();
}
MutexIF* mutex = LocalDpManagerAttorney::getMutexHandle(*hkManager);
ReturnValue_t result = mutex->lockMutex(timeoutType, timeoutMs);
if(result != HasReturnvaluesIF::RETURN_OK) {
return result;
}
result = readWithoutLock();
mutex->unlockMutex();
return result;
} }
template<typename T> template<typename T>
@ -43,7 +52,6 @@ inline ReturnValue_t LocalPoolVariable<T>::readWithoutLock() {
PoolEntry<T>* poolEntry = nullptr; PoolEntry<T>* poolEntry = nullptr;
ReturnValue_t result = LocalDpManagerAttorney::fetchPoolEntry(*hkManager, localPoolId, ReturnValue_t result = LocalDpManagerAttorney::fetchPoolEntry(*hkManager, localPoolId,
&poolEntry); &poolEntry);
//ReturnValue_t result = hkManager->fetchPoolEntry(localPoolId, &poolEntry);
if(result != RETURN_OK) { if(result != RETURN_OK) {
object_id_t ownerObjectId = hkManager->getCreatorObjectId(); object_id_t ownerObjectId = hkManager->getCreatorObjectId();
reportReadCommitError("LocalPoolVariable", result, reportReadCommitError("LocalPoolVariable", result,
@ -51,15 +59,6 @@ inline ReturnValue_t LocalPoolVariable<T>::readWithoutLock() {
return result; return result;
} }
// Actually this should never happen..
// if(poolEntry->address == nullptr) {
// result = PoolVariableIF::INVALID_POOL_ENTRY;
// object_id_t ownerObjectId = hkManager->getOwner()->getObjectId();
// reportReadCommitError("LocalPoolVariable", result,
// false, ownerObjectId, localPoolId);
// return result;
// }
this->value = *(poolEntry->getDataPtr()); this->value = *(poolEntry->getDataPtr());
this->valid = poolEntry->getValid(); this->valid = poolEntry->getValid();
return RETURN_OK; return RETURN_OK;
@ -75,8 +74,17 @@ inline ReturnValue_t LocalPoolVariable<T>::commit(bool setValid,
template<typename T> template<typename T>
inline ReturnValue_t LocalPoolVariable<T>::commit( inline ReturnValue_t LocalPoolVariable<T>::commit(
MutexIF::TimeoutType timeoutType, uint32_t timeoutMs) { MutexIF::TimeoutType timeoutType, uint32_t timeoutMs) {
MutexHelper(LocalDpManagerAttorney::getMutexHandle(*hkManager), timeoutType, timeoutMs); if(hkManager == nullptr) {
return commitWithoutLock(); return commitWithoutLock();
}
MutexIF* mutex = LocalDpManagerAttorney::getMutexHandle(*hkManager);
ReturnValue_t result = mutex->lockMutex(timeoutType, timeoutMs);
if(result != HasReturnvaluesIF::RETURN_OK) {
return result;
}
result = commitWithoutLock();
mutex->unlockMutex();
return result;
} }
template<typename T> template<typename T>
@ -90,7 +98,6 @@ inline ReturnValue_t LocalPoolVariable<T>::commitWithoutLock() {
} }
PoolEntry<T>* poolEntry = nullptr; PoolEntry<T>* poolEntry = nullptr;
//ReturnValue_t result = hkManager->fetchPoolEntry(localPoolId, &poolEntry);
ReturnValue_t result = LocalDpManagerAttorney::fetchPoolEntry(*hkManager, localPoolId, ReturnValue_t result = LocalDpManagerAttorney::fetchPoolEntry(*hkManager, localPoolId,
&poolEntry); &poolEntry);
if(result != RETURN_OK) { if(result != RETURN_OK) {

View File

@ -17,12 +17,8 @@ public:
* to generate housekeeping packets which are downlinked directly. * to generate housekeeping packets which are downlinked directly.
* @return * @return
*/ */
virtual ReturnValue_t subscribeForPeriodicPacket(sid_t sid, virtual ReturnValue_t subscribeForPeriodicPacket(sid_t sid, bool enableReporting,
bool enableReporting, float collectionInterval, bool isDiagnostics, object_id_t packetDestination) = 0;
float collectionInterval, bool isDiagnostics,
object_id_t packetDestination) = 0;
/** /**
* @brief Subscribe for the generation of packets if the dataset * @brief Subscribe for the generation of packets if the dataset
* is marked as changed. * is marked as changed.
@ -33,11 +29,8 @@ public:
* @param packetDestination * @param packetDestination
* @return * @return
*/ */
virtual ReturnValue_t subscribeForUpdatePackets(sid_t sid, virtual ReturnValue_t subscribeForUpdatePacket(sid_t sid, bool reportingEnabled,
bool reportingEnabled, bool isDiagnostics, object_id_t packetDestination) = 0;
bool isDiagnostics,
object_id_t packetDestination) = 0;
/** /**
* @brief Subscribe for a notification message which will be sent * @brief Subscribe for a notification message which will be sent
* if a dataset has changed. * if a dataset has changed.
@ -52,10 +45,9 @@ public:
* Otherwise, only an notification message is sent. * Otherwise, only an notification message is sent.
* @return * @return
*/ */
virtual ReturnValue_t subscribeForSetUpdateMessages(const uint32_t setId, virtual ReturnValue_t subscribeForSetUpdateMessage(const uint32_t setId,
object_id_t destinationObject, MessageQueueId_t targetQueueId, object_id_t destinationObject, MessageQueueId_t targetQueueId,
bool generateSnapshot) = 0; bool generateSnapshot) = 0;
/** /**
* @brief Subscribe for an notification message which will be sent if a * @brief Subscribe for an notification message which will be sent if a
* pool variable has changed. * pool variable has changed.
@ -70,12 +62,9 @@ public:
* only an notification message is sent. * only an notification message is sent.
* @return * @return
*/ */
virtual ReturnValue_t subscribeForVariableUpdateMessages( virtual ReturnValue_t subscribeForVariableUpdateMessage(const lp_id_t localPoolId,
const lp_id_t localPoolId, object_id_t destinationObject, MessageQueueId_t targetQueueId,
object_id_t destinationObject,
MessageQueueId_t targetQueueId,
bool generateSnapshot) = 0; bool generateSnapshot) = 0;
}; };
#endif /* FSFW_DATAPOOLLOCAL_PROVIDESDATAPOOLSUBSCRIPTION_H_ */ #endif /* FSFW_DATAPOOLLOCAL_PROVIDESDATAPOOLSUBSCRIPTION_H_ */

View File

@ -24,7 +24,6 @@ private:
return manager.getMutexHandle(); return manager.getMutexHandle();
} }
template<typename T> friend class LocalPoolVariable; template<typename T> friend class LocalPoolVariable;
template<typename T, uint16_t vecSize> friend class LocalPoolVector; template<typename T, uint16_t vecSize> friend class LocalPoolVector;
}; };

View File

@ -21,8 +21,8 @@ static constexpr uint8_t INTERFACE_ID = CLASS_ID::LOCAL_POOL_OWNER_IF;
static constexpr ReturnValue_t POOL_ENTRY_NOT_FOUND = MAKE_RETURN_CODE(0x00); static constexpr ReturnValue_t POOL_ENTRY_NOT_FOUND = MAKE_RETURN_CODE(0x00);
static constexpr ReturnValue_t POOL_ENTRY_TYPE_CONFLICT = MAKE_RETURN_CODE(0x01); static constexpr ReturnValue_t POOL_ENTRY_TYPE_CONFLICT = MAKE_RETURN_CODE(0x01);
//! This is the core data structure of the local data pools. Users should insert all desired /** This is the core data structure of the local data pools. Users should insert all desired
//! pool variables, using the std::map interface. pool variables, using the std::map interface. */
using DataPool = std::map<lp_id_t, PoolEntryIF*>; using DataPool = std::map<lp_id_t, PoolEntryIF*>;
using DataPoolMapIter = DataPool::iterator; using DataPoolMapIter = DataPool::iterator;

View File

@ -558,7 +558,7 @@ void DeviceHandlerBase::replyToCommand(ReturnValue_t status,
if (cookieInfo.pendingCommand->second.sendReplyTo != NO_COMMANDER) { if (cookieInfo.pendingCommand->second.sendReplyTo != NO_COMMANDER) {
MessageQueueId_t queueId = cookieInfo.pendingCommand->second.sendReplyTo; MessageQueueId_t queueId = cookieInfo.pendingCommand->second.sendReplyTo;
if (status == NO_REPLY_EXPECTED) { if (status == NO_REPLY_EXPECTED) {
actionHelper.finish(queueId, cookieInfo.pendingCommand->first, actionHelper.finish(true, queueId, cookieInfo.pendingCommand->first,
RETURN_OK); RETURN_OK);
} else { } else {
actionHelper.step(1, queueId, cookieInfo.pendingCommand->first, actionHelper.step(1, queueId, cookieInfo.pendingCommand->first,
@ -581,7 +581,11 @@ void DeviceHandlerBase::replyToReply(DeviceReplyMap::iterator iter,
// Check if it was transition or internal command. // Check if it was transition or internal command.
// Don't send any replies in that case. // Don't send any replies in that case.
if (info->sendReplyTo != NO_COMMANDER) { if (info->sendReplyTo != NO_COMMANDER) {
actionHelper.finish(info->sendReplyTo, iter->first, status); bool success = false;
if(status == HasReturnvaluesIF::RETURN_OK) {
success = true;
}
actionHelper.finish(success, info->sendReplyTo, iter->first, status);
} }
info->isExecuting = false; info->isExecuting = false;
} }
@ -1494,10 +1498,9 @@ void DeviceHandlerBase::printWarningOrError(sif::OutputTypes errorType,
if(errorType == sif::OutputTypes::OUT_WARNING) { if(errorType == sif::OutputTypes::OUT_WARNING) {
#if FSFW_CPP_OSTREAM_ENABLED == 1 #if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning << "DeviceHandlerBase::" << functionName << ": Object ID " sif::warning << "DeviceHandlerBase::" << functionName << ": Object ID 0x" << std::hex <<
<< std::hex << std::setw(8) << std::setfill('0') std::setw(8) << std::setfill('0') << this->getObjectId() << " | " << errorPrint <<
<< this->getObjectId() << " | " << errorPrint << std::dec std::dec << std::setfill(' ') << std::endl;
<< std::setfill(' ') << std::endl;
#else #else
sif::printWarning("DeviceHandlerBase::%s: Object ID 0x%08x | %s\n", sif::printWarning("DeviceHandlerBase::%s: Object ID 0x%08x | %s\n",
this->getObjectId(), errorPrint); this->getObjectId(), errorPrint);

View File

@ -1,3 +1,172 @@
## Local Data Pools ## Local Data Pools Developer Information
The following text is targeted towards mission software developers which would like
to use the local data pools provided by the FSFW to store data like sensor values so they can be
used by other software objects like controllers as well. If a custom class should have a local
pool which can be used by other software objects as well, following steps have to be performed:
1. Create a `LocalDataPoolManager` member object in the custom class
2. Implement the `HasLocalDataPoolIF` with specifies the interface between the local pool manager
and the class owning the local pool.
The local data pool manager is also able to process housekeeping service requests in form
of messages, generate periodic housekeeping packet, generate notification and snapshots of changed
variables and datasets and process notifications and snapshots coming from other objects.
The two former tasks are related to the external interface using telemetry and telecommands (TMTC)
while the later two are related to data consumers like controllers only acting on data change
detected by the data creator instead of checking the data manually each cycle. Two important
framework classes `DeviceHandlerBase` and `ExtendedControllerBase` already perform the two steps
shown above so the steps required are altered slightly.
### Storing and Accessing pool data
The pool manager is responsible for thread-safe access of the pool data, but the actual
access to the pool data from the point of view of a mission software developer happens via proxy
classes like pool variable classes. These classes store a copy
of the pool variable with the matching datatype and copy the actual data from the local pool
on a `read` call. Changed variables can then be written to the local pool with a `commit` call.
The `read` and `commit` calls are thread-safe and can be called concurrently from data creators
and data consumers. Generally, a user will create a dataset class which in turn groups all
cohesive pool variables. These sets simply iterator over the list of variables and call the
`read` and `commit` functions of each variable. The following diagram shows the
high-level architecture of the local data pools.
<img align="center" src="./images/PoolArchitecture.png" width="50%"> <br>
An example is shown for using the local data pools with a Gyroscope.
For example, the following code shows an implementation to access data from a Gyroscope taken
from the SOURCE CubeSat project:
```cpp
class GyroPrimaryDataset: public StaticLocalDataSet<3 * sizeof(float)> {
public:
/**
* Constructor for data users
* @param gyroId
*/
GyroPrimaryDataset(object_id_t gyroId):
StaticLocalDataSet(sid_t(gyroId, gyrodefs::GYRO_DATA_SET_ID)) {
setAllVariablesReadOnly();
}
lp_var_t<float> angVelocityX = lp_var_t<float>(sid.objectId,
gyrodefs::ANGULAR_VELOCITY_X, this);
lp_var_t<float> angVelocityY = lp_var_t<float>(sid.objectId,
gyrodefs::ANGULAR_VELOCITY_Y, this);
lp_var_t<float> angVelocityZ = lp_var_t<float>(sid.objectId,
gyrodefs::ANGULAR_VELOCITY_Z, this);
private:
friend class GyroHandler;
/**
* Constructor for data creator
* @param hkOwner
*/
GyroPrimaryDataset(HasLocalDataPoolIF* hkOwner):
StaticLocalDataSet(hkOwner, gyrodefs::GYRO_DATA_SET_ID) {}
};
```
There is a public constructor for users which sets all variables to read-only and there is a
constructor for the GyroHandler data creator by marking it private and declaring the `GyroHandler`
as a friend class. Both the atittude controller and the `GyroHandler` can now
use the same class definition to access the pool variables with `read` and `commit` semantics
in a thread-safe way. Generally, each class requiring access will have the set class as a member
class. The data creator will also be generally a `DeviceHandlerBase` subclass and some additional
steps are necessary to expose the set for housekeeping purposes.
### Using the local data pools in a `DeviceHandlerBase` subclass
It is very common to store data generated by devices like a sensor into a pool which can
then be used by other objects. Therefore, the `DeviceHandlerBase` already has a
local pool. Using the aforementioned example, our `GyroHandler` will now have the set class
as a member:
```cpp
class GyroHandler: ... {
public:
...
private:
...
GyroPrimaryDataset gyroData;
...
};
```
The constructor used for the creators expects the owner class as a parameter, so we initialize
the object in the `GyroHandler` constructor like this:
```cpp
GyroHandler::GyroHandler(object_id_t objectId, object_id_t comIF,
CookieIF *comCookie, uint8_t switchId):
DeviceHandlerBase(objectId, comIF, comCookie), switchId(switchId),
gyroData(this) {}
```
We need to assign the set to a reply ID used in the `DeviceHandlerBase`.
The combination of the `GyroHandler` object ID and the reply ID will be the 64-bit structure ID
`sid_t` and is used to globally identify the set, for example when requesting housekeeping data or
generating update messages. We need to assign our custom set class in some way so that the local
pool manager can access the custom data sets as well.
By default, the `getDataSetHandle` will take care of this tasks. The default implementation for a
`DeviceHandlerBase` subclass will use the internal command map to retrieve
a handle to a dataset from a given reply ID. Therefore,
we assign the set in the `fillCommandAndReplyMap` function:
```cpp
void GyroHandler::fillCommandAndReplyMap() {
...
this->insertInCommandAndReplyMap(gyrodefs::GYRO_DATA, 3, &gyroData);
...
}
```
Now, we need to create the actual pool entries as well, using the `initializeLocalDataPool`
function. Here, we also immediately subscribe for periodic housekeeping packets
with an interval of 4 seconds. They are still disabled in this example and can be enabled
with a housekeeping service command.
```cpp
ReturnValue_t GyroHandler::initializeLocalDataPool(localpool::DataPool &localDataPoolMap,
LocalDataPoolManager &poolManager) {
localDataPoolMap.emplace(gyrodefs::ANGULAR_VELOCITY_X,
new PoolEntry<float>({0.0}));
localDataPoolMap.emplace(gyrodefs::ANGULAR_VELOCITY_Y,
new PoolEntry<float>({0.0}));
localDataPoolMap.emplace(gyrodefs::ANGULAR_VELOCITY_Z,
new PoolEntry<float>({0.0}));
localDataPoolMap.emplace(gyrodefs::GENERAL_CONFIG_REG42,
new PoolEntry<uint8_t>({0}));
localDataPoolMap.emplace(gyrodefs::RANGE_CONFIG_REG43,
new PoolEntry<uint8_t>({0}));
poolManager.subscribeForPeriodicPacket(gyroData.getSid(), false, 4.0, false);
return HasReturnvaluesIF::RETURN_OK;
}
```
Now, if we receive some sensor data and converted them into the right format,
we can write it into the pool like this, using a guard class to ensure the set is commited back
in any case:
```cpp
PoolReadGuard readHelper(&gyroData);
if(readHelper.getReadResult() == HasReturnvaluesIF::RETURN_OK) {
if(not gyroData.isValid()) {
gyroData.setValidity(true, true);
}
gyroData.angVelocityX = angularVelocityX;
gyroData.angVelocityY = angularVelocityY;
gyroData.angVelocityZ = angularVelocityZ;
}
```
The guard class will commit the changed data on destruction automatically.
### Using the local data pools in a `ExtendedControllerBase` subclass
Coming soon

Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB

View File

@ -7,6 +7,7 @@ target_sources(${LIB_FSFW_NAME}
PeriodicOperationDivider.cpp PeriodicOperationDivider.cpp
timevalOperations.cpp timevalOperations.cpp
Type.cpp Type.cpp
bitutility.cpp
) )
add_subdirectory(math) add_subdirectory(math)

View File

@ -5,6 +5,15 @@
void arrayprinter::print(const uint8_t *data, size_t size, OutputType type, void arrayprinter::print(const uint8_t *data, size_t size, OutputType type,
bool printInfo, size_t maxCharPerLine) { bool printInfo, size_t maxCharPerLine) {
if(size == 0) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::info << "Size is zero, nothing to print" << std::endl;
#else
sif::printInfo("Size is zero, nothing to print\n");
#endif
return;
}
#if FSFW_CPP_OSTREAM_ENABLED == 1 #if FSFW_CPP_OSTREAM_ENABLED == 1
if(printInfo) { if(printInfo) {
sif::info << "Printing data with size " << size << ": " << std::endl; sif::info << "Printing data with size " << size << ": " << std::endl;

View File

@ -0,0 +1,33 @@
#include "bitutility.h"
void bitutil::bitSet(uint8_t *byte, uint8_t position) {
if(position > 7) {
return;
}
uint8_t shiftNumber = position + (7 - 2 * position);
*byte |= 1 << shiftNumber;
}
void bitutil::bitToggle(uint8_t *byte, uint8_t position) {
if(position > 7) {
return;
}
uint8_t shiftNumber = position + (7 - 2 * position);
*byte ^= 1 << shiftNumber;
}
void bitutil::bitClear(uint8_t *byte, uint8_t position) {
if(position > 7) {
return;
}
uint8_t shiftNumber = position + (7 - 2 * position);
*byte &= ~(1 << shiftNumber);
}
bool bitutil::bitGet(const uint8_t *byte, uint8_t position) {
if(position > 7) {
return false;
}
uint8_t shiftNumber = position + (7 - 2 * position);
return *byte & (1 << shiftNumber);
}

View File

@ -0,0 +1,18 @@
#ifndef FSFW_GLOBALFUNCTIONS_BITUTIL_H_
#define FSFW_GLOBALFUNCTIONS_BITUTIL_H_
#include <cstdint>
namespace bitutil {
/* Helper functions for manipulating the individual bits of a byte.
Position refers to n-th bit of a byte, going from 0 (most significant bit) to
7 (least significant bit) */
void bitSet(uint8_t* byte, uint8_t position);
void bitToggle(uint8_t* byte, uint8_t position);
void bitClear(uint8_t* byte, uint8_t position);
bool bitGet(const uint8_t* byte, uint8_t position);
}
#endif /* FSFW_GLOBALFUNCTIONS_BITUTIL_H_ */

View File

@ -10,7 +10,11 @@
* which are destined to be downlinked into the store. * which are destined to be downlinked into the store.
* @details * @details
* The housekeeping packets are stored into the IPC store and forwarded * The housekeeping packets are stored into the IPC store and forwarded
* to the designated housekeeping handler. * to the designated housekeeping handler. The packet will consist of the following fields
* - SID (8 byte): Structure ID, with the first 4 bytes being the object ID and the last four
* bytes being the set ID
* - Housekeeping Data: The rest of the packet will be the serialized housekeeping data. A validity
* buffer might be appended at the end, depending on the set configuration.
*/ */
class HousekeepingPacketDownlink: public SerialLinkedListAdapter<SerializeIF> { class HousekeepingPacketDownlink: public SerialLinkedListAdapter<SerializeIF> {
public: public:

View File

@ -13,60 +13,62 @@ public:
/** /**
* Header consists of sender ID and command ID. * Header consists of sender ID and command ID.
*/ */
static constexpr size_t HEADER_SIZE = MessageQueueMessageIF::HEADER_SIZE + static constexpr size_t HEADER_SIZE = MessageQueueMessageIF::HEADER_SIZE + sizeof(Command_t);
sizeof(Command_t); /**
/** * This minimum size is derived from the interface requirement to be able
* This minimum size is derived from the interface requirement to be able
* to set a rejected reply, which contains a returnvalue and the initial * to set a rejected reply, which contains a returnvalue and the initial
* command. * command.
*/ */
static constexpr size_t MINIMUM_COMMAND_MESSAGE_SIZE = static constexpr size_t MINIMUM_COMMAND_MESSAGE_SIZE = CommandMessageIF::HEADER_SIZE +
CommandMessageIF::HEADER_SIZE + sizeof(ReturnValue_t) + sizeof(ReturnValue_t) + sizeof(Command_t);
sizeof(Command_t);
static const uint8_t INTERFACE_ID = CLASS_ID::COMMAND_MESSAGE; static constexpr Command_t makeCommandId(uint8_t messageId, uint8_t uniqueId) {
static const ReturnValue_t UNKNOWN_COMMAND = MAKE_RETURN_CODE(0x01); return ((messageId << 8) | uniqueId);
}
static const uint8_t MESSAGE_ID = messagetypes::COMMAND; static const uint8_t INTERFACE_ID = CLASS_ID::COMMAND_MESSAGE;
//! Used internally, shall be ignored static const ReturnValue_t UNKNOWN_COMMAND = MAKE_RETURN_CODE(1);
static const Command_t CMD_NONE = MAKE_COMMAND_ID( 0 );
static const Command_t REPLY_COMMAND_OK = MAKE_COMMAND_ID( 1 );
//! Reply indicating that the current command was rejected,
//! par1 should contain the error code
static const Command_t REPLY_REJECTED = MAKE_COMMAND_ID( 2 );
virtual ~CommandMessageIF() {}; static const uint8_t MESSAGE_ID = messagetypes::COMMAND;
//! Used internally, shall be ignored
static const Command_t CMD_NONE = MAKE_COMMAND_ID( 0 );
static const Command_t REPLY_COMMAND_OK = MAKE_COMMAND_ID( 1 );
//! Reply indicating that the current command was rejected,
//! par1 should contain the error code
static const Command_t REPLY_REJECTED = MAKE_COMMAND_ID( 2 );
/** virtual ~CommandMessageIF() {};
* A command message shall have a uint16_t command ID field.
* @return
*/
virtual Command_t getCommand() const = 0;
/**
* A command message shall have a uint8_t message type ID field.
* @return
*/
virtual uint8_t getMessageType() const = 0;
/** /**
* A command message can be rejected and needs to offer a function * A command message shall have a uint16_t command ID field.
* to set a rejected reply * @return
* @param reason */
* @param initialCommand virtual Command_t getCommand() const = 0;
*/ /**
virtual void setReplyRejected(ReturnValue_t reason, * A command message shall have a uint8_t message type ID field.
Command_t initialCommand) = 0; * @return
/** */
* Corrensonding getter function. virtual uint8_t getMessageType() const = 0;
* @param initialCommand
* @return
*/
virtual ReturnValue_t getReplyRejectedReason(
Command_t* initialCommand = nullptr) const = 0;
virtual void setToUnknownCommand() = 0; /**
* A command message can be rejected and needs to offer a function
* to set a rejected reply
* @param reason
* @param initialCommand
*/
virtual void setReplyRejected(ReturnValue_t reason,
Command_t initialCommand) = 0;
/**
* Corrensonding getter function.
* @param initialCommand
* @return
*/
virtual ReturnValue_t getReplyRejectedReason(
Command_t* initialCommand = nullptr) const = 0;
virtual void clear() = 0; virtual void setToUnknownCommand() = 0;
virtual void clear() = 0;
}; };

View File

@ -2,33 +2,56 @@
#define FRAMEWORK_IPC_MUTEXHELPER_H_ #define FRAMEWORK_IPC_MUTEXHELPER_H_
#include "MutexFactory.h" #include "MutexFactory.h"
#include "../serviceinterface/ServiceInterfaceStream.h" #include "../serviceinterface/ServiceInterface.h"
class MutexHelper { class MutexHelper {
public: public:
MutexHelper(MutexIF* mutex, MutexIF::TimeoutType timeoutType = MutexHelper(MutexIF* mutex, MutexIF::TimeoutType timeoutType =
MutexIF::TimeoutType::BLOCKING, uint32_t timeoutMs = 0) : MutexIF::TimeoutType::BLOCKING, uint32_t timeoutMs = 0):
internalMutex(mutex) { internalMutex(mutex) {
ReturnValue_t status = mutex->lockMutex(timeoutType, if(mutex == nullptr) {
timeoutMs); #if FSFW_VERBOSE_LEVEL >= 1
if(status == MutexIF::MUTEX_TIMEOUT) {
#if FSFW_CPP_OSTREAM_ENABLED == 1 #if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "MutexHelper: Lock of mutex failed with timeout of " sif::error << "MutexHelper: Passed mutex is invalid!" << std::endl;
<< timeoutMs << " milliseconds!" << std::endl; #else
#endif sif::printError("MutexHelper: Passed mutex is invalid!\n");
} #endif /* FSFW_CPP_OSTREAM_ENABLED == 1 */
else if(status != HasReturnvaluesIF::RETURN_OK){ #endif /* FSFW_VERBOSE_LEVEL >= 1 */
return;
}
ReturnValue_t status = mutex->lockMutex(timeoutType,
timeoutMs);
#if FSFW_VERBOSE_LEVEL >= 1
if(status == MutexIF::MUTEX_TIMEOUT) {
#if FSFW_CPP_OSTREAM_ENABLED == 1 #if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "MutexHelper: Lock of Mutex failed with code " sif::error << "MutexHelper: Lock of mutex failed with timeout of "
<< status << std::endl; << timeoutMs << " milliseconds!" << std::endl;
#endif #else
} sif::printError("MutexHelper: Lock of mutex failed with timeout of %lu milliseconds\n",
} timeoutMs);
#endif /* FSFW_CPP_OSTREAM_ENABLED == 1 */
~MutexHelper() { }
internalMutex->unlockMutex(); else if(status != HasReturnvaluesIF::RETURN_OK) {
} #if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "MutexHelper: Lock of Mutex failed with code " << status << std::endl;
#else
sif::printError("MutexHelper: Lock of Mutex failed with code %d\n", status);
#endif /* FSFW_CPP_OSTREAM_ENABLED == 1 */
}
#else
/* To avoid unused variable warning */
static_cast<void>(status);
#endif /* FSFW_VERBOSE_LEVEL >= 1 */
}
~MutexHelper() {
if(internalMutex != nullptr) {
internalMutex->unlockMutex();
}
}
private: private:
MutexIF* internalMutex; MutexIF* internalMutex;
}; };
#endif /* FRAMEWORK_IPC_MUTEXHELPER_H_ */ #endif /* FRAMEWORK_IPC_MUTEXHELPER_H_ */

View File

@ -16,17 +16,27 @@ class HasFileSystemIF {
public: public:
static constexpr uint8_t INTERFACE_ID = CLASS_ID::FILE_SYSTEM; static constexpr uint8_t INTERFACE_ID = CLASS_ID::FILE_SYSTEM;
static constexpr ReturnValue_t FILE_DOES_NOT_EXIST = MAKE_RETURN_CODE(0x00); //! [EXPORT] : P1: Can be file system specific error code
static constexpr ReturnValue_t FILE_ALREADY_EXISTS = MAKE_RETURN_CODE(0x01); static constexpr ReturnValue_t GENERIC_FILE_ERROR = MAKE_RETURN_CODE(0);
static constexpr ReturnValue_t FILE_LOCKED = MAKE_RETURN_CODE(0x02); //! [EXPORT] : File system is currently busy
static constexpr ReturnValue_t IS_BUSY = MAKE_RETURN_CODE(1);
//! [EXPORT] : Invalid parameters like file name or repository path
static constexpr ReturnValue_t INVALID_PARAMETERS = MAKE_RETURN_CODE(2);
static constexpr ReturnValue_t DIRECTORY_DOES_NOT_EXIST = MAKE_RETURN_CODE(0x03); static constexpr ReturnValue_t FILE_DOES_NOT_EXIST = MAKE_RETURN_CODE(5);
static constexpr ReturnValue_t DIRECTORY_ALREADY_EXISTS = MAKE_RETURN_CODE(0x04); static constexpr ReturnValue_t FILE_ALREADY_EXISTS = MAKE_RETURN_CODE(6);
static constexpr ReturnValue_t DIRECTORY_NOT_EMPTY = MAKE_RETURN_CODE(0x05); static constexpr ReturnValue_t FILE_LOCKED = MAKE_RETURN_CODE(7);
static constexpr ReturnValue_t DIRECTORY_DOES_NOT_EXIST = MAKE_RETURN_CODE(10);
static constexpr ReturnValue_t DIRECTORY_ALREADY_EXISTS = MAKE_RETURN_CODE(11);
static constexpr ReturnValue_t DIRECTORY_NOT_EMPTY = MAKE_RETURN_CODE(12);
//! [EXPORT] : P1: Sequence number missing
static constexpr ReturnValue_t SEQUENCE_PACKET_MISSING_WRITE = MAKE_RETURN_CODE(15);
//! [EXPORT] : P1: Sequence number missing
static constexpr ReturnValue_t SEQUENCE_PACKET_MISSING_READ = MAKE_RETURN_CODE(16);
static constexpr ReturnValue_t SEQUENCE_PACKET_MISSING_WRITE = MAKE_RETURN_CODE(0x06); //! P1: Sequence number missing
static constexpr ReturnValue_t SEQUENCE_PACKET_MISSING_READ = MAKE_RETURN_CODE(0x07); //! P1: Sequence number missing
virtual ~HasFileSystemIF() {} virtual ~HasFileSystemIF() {}
/** /**

View File

@ -16,56 +16,56 @@ uint16_t Clock::leapSeconds = 0;
MutexIF* Clock::timeMutex = nullptr; MutexIF* Clock::timeMutex = nullptr;
uint32_t Clock::getTicksPerSecond(void) { uint32_t Clock::getTicksPerSecond(void) {
return 1000; return 1000;
} }
ReturnValue_t Clock::setClock(const TimeOfDay_t* time) { ReturnValue_t Clock::setClock(const TimeOfDay_t* time) {
timeval time_timeval; timeval time_timeval;
ReturnValue_t result = convertTimeOfDayToTimeval(time, &time_timeval); ReturnValue_t result = convertTimeOfDayToTimeval(time, &time_timeval);
if (result != HasReturnvaluesIF::RETURN_OK){ if (result != HasReturnvaluesIF::RETURN_OK){
return result; return result;
} }
return setClock(&time_timeval); return setClock(&time_timeval);
} }
ReturnValue_t Clock::setClock(const timeval* time) { ReturnValue_t Clock::setClock(const timeval* time) {
timeval uptime = getUptime(); timeval uptime = getUptime();
timeval offset = *time - uptime; timeval offset = *time - uptime;
Timekeeper::instance()->setOffset(offset); Timekeeper::instance()->setOffset(offset);
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
} }
ReturnValue_t Clock::getClock_timeval(timeval* time) { ReturnValue_t Clock::getClock_timeval(timeval* time) {
timeval uptime = getUptime(); timeval uptime = getUptime();
timeval offset = Timekeeper::instance()->getOffset(); timeval offset = Timekeeper::instance()->getOffset();
*time = offset + uptime; *time = offset + uptime;
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
} }
ReturnValue_t Clock::getUptime(timeval* uptime) { ReturnValue_t Clock::getUptime(timeval* uptime) {
*uptime = getUptime(); *uptime = getUptime();
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
} }
timeval Clock::getUptime() { timeval Clock::getUptime() {
TickType_t ticksSinceStart = xTaskGetTickCount(); TickType_t ticksSinceStart = xTaskGetTickCount();
return Timekeeper::ticksToTimeval(ticksSinceStart); return Timekeeper::ticksToTimeval(ticksSinceStart);
} }
ReturnValue_t Clock::getUptime(uint32_t* uptimeMs) { ReturnValue_t Clock::getUptime(uint32_t* uptimeMs) {
timeval uptime = getUptime(); timeval uptime = getUptime();
*uptimeMs = uptime.tv_sec * 1000 + uptime.tv_usec / 1000; *uptimeMs = uptime.tv_sec * 1000 + uptime.tv_usec / 1000;
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
} }
@ -76,129 +76,129 @@ ReturnValue_t Clock::getUptime(uint32_t* uptimeMs) {
ReturnValue_t Clock::getClock_usecs(uint64_t* time) { ReturnValue_t Clock::getClock_usecs(uint64_t* time) {
timeval time_timeval; timeval time_timeval;
ReturnValue_t result = getClock_timeval(&time_timeval); ReturnValue_t result = getClock_timeval(&time_timeval);
if (result != HasReturnvaluesIF::RETURN_OK) { if (result != HasReturnvaluesIF::RETURN_OK) {
return result; return result;
} }
*time = time_timeval.tv_sec * 1000000 + time_timeval.tv_usec; *time = time_timeval.tv_sec * 1000000 + time_timeval.tv_usec;
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
} }
ReturnValue_t Clock::getDateAndTime(TimeOfDay_t* time) { ReturnValue_t Clock::getDateAndTime(TimeOfDay_t* time) {
timeval time_timeval; timeval time_timeval;
ReturnValue_t result = getClock_timeval(&time_timeval); ReturnValue_t result = getClock_timeval(&time_timeval);
if (result != HasReturnvaluesIF::RETURN_OK) { if (result != HasReturnvaluesIF::RETURN_OK) {
return result; return result;
} }
struct tm time_tm; struct tm time_tm;
gmtime_r(&time_timeval.tv_sec,&time_tm); gmtime_r(&time_timeval.tv_sec,&time_tm);
time->year = time_tm.tm_year + 1900; time->year = time_tm.tm_year + 1900;
time->month = time_tm.tm_mon + 1; time->month = time_tm.tm_mon + 1;
time->day = time_tm.tm_mday; time->day = time_tm.tm_mday;
time->hour = time_tm.tm_hour; time->hour = time_tm.tm_hour;
time->minute = time_tm.tm_min; time->minute = time_tm.tm_min;
time->second = time_tm.tm_sec; time->second = time_tm.tm_sec;
time->usecond = time_timeval.tv_usec; time->usecond = time_timeval.tv_usec;
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
} }
ReturnValue_t Clock::convertTimeOfDayToTimeval(const TimeOfDay_t* from, ReturnValue_t Clock::convertTimeOfDayToTimeval(const TimeOfDay_t* from,
timeval* to) { timeval* to) {
struct tm time_tm; struct tm time_tm;
time_tm.tm_year = from->year - 1900; time_tm.tm_year = from->year - 1900;
time_tm.tm_mon = from->month - 1; time_tm.tm_mon = from->month - 1;
time_tm.tm_mday = from->day; time_tm.tm_mday = from->day;
time_tm.tm_hour = from->hour; time_tm.tm_hour = from->hour;
time_tm.tm_min = from->minute; time_tm.tm_min = from->minute;
time_tm.tm_sec = from->second; time_tm.tm_sec = from->second;
time_t seconds = mktime(&time_tm); time_t seconds = mktime(&time_tm);
to->tv_sec = seconds; to->tv_sec = seconds;
to->tv_usec = from->usecond; to->tv_usec = from->usecond;
//Fails in 2038.. //Fails in 2038..
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
} }
ReturnValue_t Clock::convertTimevalToJD2000(timeval time, double* JD2000) { ReturnValue_t Clock::convertTimevalToJD2000(timeval time, double* JD2000) {
*JD2000 = (time.tv_sec - 946728000. + time.tv_usec / 1000000.) / 24. *JD2000 = (time.tv_sec - 946728000. + time.tv_usec / 1000000.) / 24.
/ 3600.; / 3600.;
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
} }
ReturnValue_t Clock::convertUTCToTT(timeval utc, timeval* tt) { ReturnValue_t Clock::convertUTCToTT(timeval utc, timeval* tt) {
//SHOULDDO: works not for dates in the past (might have less leap seconds) //SHOULDDO: works not for dates in the past (might have less leap seconds)
if (timeMutex == nullptr) { if (timeMutex == nullptr) {
return HasReturnvaluesIF::RETURN_FAILED; return HasReturnvaluesIF::RETURN_FAILED;
} }
uint16_t leapSeconds; uint16_t leapSeconds;
ReturnValue_t result = getLeapSeconds(&leapSeconds); ReturnValue_t result = getLeapSeconds(&leapSeconds);
if (result != HasReturnvaluesIF::RETURN_OK) { if (result != HasReturnvaluesIF::RETURN_OK) {
return result; return result;
} }
timeval leapSeconds_timeval = { 0, 0 }; timeval leapSeconds_timeval = { 0, 0 };
leapSeconds_timeval.tv_sec = leapSeconds; leapSeconds_timeval.tv_sec = leapSeconds;
//initial offset between UTC and TAI //initial offset between UTC and TAI
timeval UTCtoTAI1972 = { 10, 0 }; timeval UTCtoTAI1972 = { 10, 0 };
timeval TAItoTT = { 32, 184000 }; timeval TAItoTT = { 32, 184000 };
*tt = utc + leapSeconds_timeval + UTCtoTAI1972 + TAItoTT; *tt = utc + leapSeconds_timeval + UTCtoTAI1972 + TAItoTT;
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
} }
ReturnValue_t Clock::setLeapSeconds(const uint16_t leapSeconds_) { ReturnValue_t Clock::setLeapSeconds(const uint16_t leapSeconds_) {
if (checkOrCreateClockMutex() != HasReturnvaluesIF::RETURN_OK) { if (checkOrCreateClockMutex() != HasReturnvaluesIF::RETURN_OK) {
return HasReturnvaluesIF::RETURN_FAILED; return HasReturnvaluesIF::RETURN_FAILED;
} }
ReturnValue_t result = timeMutex->lockMutex(MutexIF::TimeoutType::BLOCKING); ReturnValue_t result = timeMutex->lockMutex(MutexIF::TimeoutType::BLOCKING);
if (result != HasReturnvaluesIF::RETURN_OK) { if (result != HasReturnvaluesIF::RETURN_OK) {
return result; return result;
} }
leapSeconds = leapSeconds_; leapSeconds = leapSeconds_;
result = timeMutex->unlockMutex(); result = timeMutex->unlockMutex();
return result; return result;
} }
ReturnValue_t Clock::getLeapSeconds(uint16_t* leapSeconds_) { ReturnValue_t Clock::getLeapSeconds(uint16_t* leapSeconds_) {
if (timeMutex == NULL) { if (timeMutex == NULL) {
return HasReturnvaluesIF::RETURN_FAILED; return HasReturnvaluesIF::RETURN_FAILED;
} }
ReturnValue_t result = timeMutex->lockMutex(MutexIF::TimeoutType::BLOCKING); ReturnValue_t result = timeMutex->lockMutex(MutexIF::TimeoutType::BLOCKING);
if (result != HasReturnvaluesIF::RETURN_OK) { if (result != HasReturnvaluesIF::RETURN_OK) {
return result; return result;
} }
*leapSeconds_ = leapSeconds; *leapSeconds_ = leapSeconds;
result = timeMutex->unlockMutex(); result = timeMutex->unlockMutex();
return result; return result;
} }
ReturnValue_t Clock::checkOrCreateClockMutex() { ReturnValue_t Clock::checkOrCreateClockMutex() {
if (timeMutex == NULL) { if (timeMutex == NULL) {
MutexFactory* mutexFactory = MutexFactory::instance(); MutexFactory* mutexFactory = MutexFactory::instance();
if (mutexFactory == NULL) { if (mutexFactory == NULL) {
return HasReturnvaluesIF::RETURN_FAILED; return HasReturnvaluesIF::RETURN_FAILED;
} }
timeMutex = mutexFactory->createMutex(); timeMutex = mutexFactory->createMutex();
if (timeMutex == NULL) { if (timeMutex == NULL) {
return HasReturnvaluesIF::RETURN_FAILED; return HasReturnvaluesIF::RETURN_FAILED;
} }
} }
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
} }

View File

@ -49,5 +49,11 @@ ReturnValue_t TaskFactory::delayTask(uint32_t delayMs) {
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
} }
void TaskFactory::printMissedDeadline() {
/* TODO: Implement */
return;
}
TaskFactory::TaskFactory() { TaskFactory::TaskFactory() {
} }

View File

@ -1,4 +1,4 @@
#include "../../serviceinterface/ServiceInterfaceStream.h" #include "../../serviceinterface/ServiceInterface.h"
#include "../../timemanager/Clock.h" #include "../../timemanager/Clock.h"
#include <chrono> #include <chrono>

View File

@ -1,5 +1,6 @@
#include "QueueMapManager.h" #include "QueueMapManager.h"
#include "../../serviceinterface/ServiceInterface.h"
#include "../../ipc/MutexFactory.h" #include "../../ipc/MutexFactory.h"
#include "../../ipc/MutexHelper.h" #include "../../ipc/MutexHelper.h"

View File

@ -48,4 +48,9 @@ ReturnValue_t TaskFactory::delayTask(uint32_t delayMs){
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
} }
void TaskFactory::printMissedDeadline() {
/* TODO: Implement */
return;
}

View File

@ -68,20 +68,6 @@ void PeriodicPosixTask::taskFunctionality(void) {
} }
if(not PosixThread::delayUntil(&lastWakeTime, periodMs)){ if(not PosixThread::delayUntil(&lastWakeTime, periodMs)){
char name[20] = {0};
int status = pthread_getname_np(pthread_self(), name, sizeof(name));
if(status == 0) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "PeriodicPosixTask " << name << ": Deadline "
"missed." << std::endl;
#endif
}
else {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "PeriodicPosixTask X: Deadline missed. " <<
status << std::endl;
#endif
}
if (this->deadlineMissedFunc != nullptr) { if (this->deadlineMissedFunc != nullptr) {
this->deadlineMissedFunc(); this->deadlineMissedFunc();
} }

View File

@ -39,5 +39,26 @@ ReturnValue_t TaskFactory::delayTask(uint32_t delayMs){
return PosixThread::sleep(delayMs*1000000ull); return PosixThread::sleep(delayMs*1000000ull);
} }
void TaskFactory::printMissedDeadline() {
char name[20] = {0};
int status = pthread_getname_np(pthread_self(), name, sizeof(name));
#if FSFW_CPP_OSTREAM_ENABLED == 1
if(status == 0) {
sif::warning << "task::printMissedDeadline: " << name << "" << std::endl;
}
else {
sif::warning << "task::printMissedDeadline: Unknown task name" << status <<
std::endl;
}
#else
if(status == 0) {
sif::printWarning("task::printMissedDeadline: %s\n", name);
}
else {
sif::printWarning("task::printMissedDeadline: Unknown task name\n", name);
}
#endif /* FSFW_CPP_OSTREAM_ENABLED == 1 */
}
TaskFactory::TaskFactory() { TaskFactory::TaskFactory() {
} }

View File

@ -10,201 +10,209 @@ uint16_t Clock::leapSeconds = 0;
MutexIF* Clock::timeMutex = nullptr; MutexIF* Clock::timeMutex = nullptr;
uint32_t Clock::getTicksPerSecond(void){ uint32_t Clock::getTicksPerSecond(void){
rtems_interval ticks_per_second = rtems_clock_get_ticks_per_second(); rtems_interval ticks_per_second = rtems_clock_get_ticks_per_second();
return static_cast<uint32_t>(ticks_per_second); return static_cast<uint32_t>(ticks_per_second);
} }
ReturnValue_t Clock::setClock(const TimeOfDay_t* time) { ReturnValue_t Clock::setClock(const TimeOfDay_t* time) {
rtems_time_of_day timeRtems; rtems_time_of_day timeRtems;
timeRtems.year = time->year; timeRtems.year = time->year;
timeRtems.month = time->month; timeRtems.month = time->month;
timeRtems.day = time->day; timeRtems.day = time->day;
timeRtems.hour = time->hour; timeRtems.hour = time->hour;
timeRtems.minute = time->minute; timeRtems.minute = time->minute;
timeRtems.second = time->second; timeRtems.second = time->second;
timeRtems.ticks = time->usecond * getTicksPerSecond() / 1e6; timeRtems.ticks = time->usecond * getTicksPerSecond() / 1e6;
rtems_status_code status = rtems_clock_set(&timeRtems); rtems_status_code status = rtems_clock_set(&timeRtems);
switch(status){ switch(status){
case RTEMS_SUCCESSFUL: case RTEMS_SUCCESSFUL:
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
case RTEMS_INVALID_ADDRESS: case RTEMS_INVALID_ADDRESS:
return HasReturnvaluesIF::RETURN_FAILED; return HasReturnvaluesIF::RETURN_FAILED;
case RTEMS_INVALID_CLOCK: case RTEMS_INVALID_CLOCK:
return HasReturnvaluesIF::RETURN_FAILED; return HasReturnvaluesIF::RETURN_FAILED;
default: default:
return HasReturnvaluesIF::RETURN_FAILED; return HasReturnvaluesIF::RETURN_FAILED;
} }
} }
ReturnValue_t Clock::setClock(const timeval* time) { ReturnValue_t Clock::setClock(const timeval* time) {
timespec newTime; timespec newTime;
newTime.tv_sec = time->tv_sec; newTime.tv_sec = time->tv_sec;
if(time->tv_usec < 0) { if(time->tv_usec < 0) {
// better returnvalue. // better returnvalue.
return HasReturnvaluesIF::RETURN_FAILED; return HasReturnvaluesIF::RETURN_FAILED;
} }
newTime.tv_nsec = time->tv_usec * TOD_NANOSECONDS_PER_MICROSECOND; newTime.tv_nsec = time->tv_usec * TOD_NANOSECONDS_PER_MICROSECOND;
ISR_lock_Context context; ISR_lock_Context context;
_TOD_Lock(); _TOD_Lock();
_TOD_Acquire(&context); _TOD_Acquire(&context);
Status_Control status = _TOD_Set(&newTime, &context); Status_Control status = _TOD_Set(&newTime, &context);
_TOD_Unlock(); _TOD_Unlock();
if(status == STATUS_SUCCESSFUL) { if(status == STATUS_SUCCESSFUL) {
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
} }
// better returnvalue // better returnvalue
return HasReturnvaluesIF::RETURN_FAILED; return HasReturnvaluesIF::RETURN_FAILED;
} }
ReturnValue_t Clock::getClock_timeval(timeval* time) { ReturnValue_t Clock::getClock_timeval(timeval* time) {
//Callable from ISR //Callable from ISR
rtems_status_code status = rtems_clock_get_tod_timeval(time); rtems_status_code status = rtems_clock_get_tod_timeval(time);
switch(status){ switch(status){
case RTEMS_SUCCESSFUL: case RTEMS_SUCCESSFUL:
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
case RTEMS_NOT_DEFINED: case RTEMS_NOT_DEFINED:
return HasReturnvaluesIF::RETURN_FAILED; return HasReturnvaluesIF::RETURN_FAILED;
default: default:
return HasReturnvaluesIF::RETURN_FAILED; return HasReturnvaluesIF::RETURN_FAILED;
} }
} }
ReturnValue_t Clock::getUptime(timeval* uptime) { ReturnValue_t Clock::getUptime(timeval* uptime) {
//According to docs.rtems.org for rtems 5 this method is more accurate than rtems_clock_get_ticks_since_boot //According to docs.rtems.org for rtems 5 this method is more accurate than rtems_clock_get_ticks_since_boot
timespec time; timespec time;
rtems_status_code status = rtems_clock_get_uptime(&time); rtems_status_code status = rtems_clock_get_uptime(&time);
uptime->tv_sec = time.tv_sec; uptime->tv_sec = time.tv_sec;
time.tv_nsec = time.tv_nsec / 1000; time.tv_nsec = time.tv_nsec / 1000;
uptime->tv_usec = time.tv_nsec; uptime->tv_usec = time.tv_nsec;
switch(status){ switch(status){
case RTEMS_SUCCESSFUL: case RTEMS_SUCCESSFUL:
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
default: default:
return HasReturnvaluesIF::RETURN_FAILED; return HasReturnvaluesIF::RETURN_FAILED;
} }
} }
ReturnValue_t Clock::getUptime(uint32_t* uptimeMs) { ReturnValue_t Clock::getUptime(uint32_t* uptimeMs) {
//This counter overflows after 50 days //This counter overflows after 50 days
*uptimeMs = rtems_clock_get_ticks_since_boot(); *uptimeMs = rtems_clock_get_ticks_since_boot();
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
} }
ReturnValue_t Clock::getClock_usecs(uint64_t* time) { ReturnValue_t Clock::getClock_usecs(uint64_t* time) {
timeval temp_time; timeval temp_time;
rtems_status_code returnValue = rtems_clock_get_tod_timeval(&temp_time); rtems_status_code returnValue = rtems_clock_get_tod_timeval(&temp_time);
*time = ((uint64_t) temp_time.tv_sec * 1000000) + temp_time.tv_usec; *time = ((uint64_t) temp_time.tv_sec * 1000000) + temp_time.tv_usec;
switch(returnValue){ switch(returnValue){
case RTEMS_SUCCESSFUL: case RTEMS_SUCCESSFUL:
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
default: default:
return HasReturnvaluesIF::RETURN_FAILED; return HasReturnvaluesIF::RETURN_FAILED;
} }
} }
ReturnValue_t Clock::getDateAndTime(TimeOfDay_t* time) { ReturnValue_t Clock::getDateAndTime(TimeOfDay_t* time) {
/* For all but the last field, the struct will be filled with the correct values */ /* For all but the last field, the struct will be filled with the correct values */
rtems_time_of_day* timeRtems = reinterpret_cast<rtems_time_of_day*>(time); rtems_time_of_day timeRtems;
rtems_status_code status = rtems_clock_get_tod(timeRtems); rtems_status_code status = rtems_clock_get_tod(&timeRtems);
/* The last field now contains the RTEMS ticks of the seconds from 0 switch (status) {
to rtems_clock_get_ticks_per_second() minus one. We calculate the microseconds accordingly */ case RTEMS_SUCCESSFUL: {
timeRtems->ticks = static_cast<float>(timeRtems->ticks) / /* The last field now contains the RTEMS ticks of the seconds from 0
rtems_clock_get_ticks_per_second() * 1e6; to rtems_clock_get_ticks_per_second() minus one.
switch (status) { We calculate the microseconds accordingly */
case RTEMS_SUCCESSFUL: time->day = timeRtems.day;
return HasReturnvaluesIF::RETURN_OK; time->hour = timeRtems.hour;
case RTEMS_NOT_DEFINED: time->minute = timeRtems.minute;
//system date and time is not set time->month = timeRtems.month;
return HasReturnvaluesIF::RETURN_FAILED; time->second = timeRtems.second;
case RTEMS_INVALID_ADDRESS: time->usecond = static_cast<float>(timeRtems.ticks) /
//time_buffer is NULL rtems_clock_get_ticks_per_second() * 1e6;
return HasReturnvaluesIF::RETURN_FAILED; time->year = timeRtems.year;
default: return HasReturnvaluesIF::RETURN_OK;
return HasReturnvaluesIF::RETURN_FAILED; }
} case RTEMS_NOT_DEFINED:
/* System date and time is not set */
return HasReturnvaluesIF::RETURN_FAILED;
case RTEMS_INVALID_ADDRESS:
/* time_buffer is NULL */
return HasReturnvaluesIF::RETURN_FAILED;
default:
return HasReturnvaluesIF::RETURN_FAILED;
}
} }
ReturnValue_t Clock::convertTimeOfDayToTimeval(const TimeOfDay_t* from, ReturnValue_t Clock::convertTimeOfDayToTimeval(const TimeOfDay_t* from,
timeval* to) { timeval* to) {
//Fails in 2038.. //Fails in 2038..
rtems_time_of_day timeRtems; rtems_time_of_day timeRtems;
timeRtems.year = from->year; timeRtems.year = from->year;
timeRtems.month = from->month; timeRtems.month = from->month;
timeRtems.day = from->day; timeRtems.day = from->day;
timeRtems.hour = from->hour; timeRtems.hour = from->hour;
timeRtems.minute = from->minute; timeRtems.minute = from->minute;
timeRtems.second = from->second; timeRtems.second = from->second;
timeRtems.ticks = from->usecond * getTicksPerSecond() / 1e6; timeRtems.ticks = from->usecond * getTicksPerSecond() / 1e6;
to->tv_sec = _TOD_To_seconds(&timeRtems); to->tv_sec = _TOD_To_seconds(&timeRtems);
to->tv_usec = from->usecond; to->tv_usec = from->usecond;
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
} }
ReturnValue_t Clock::convertTimevalToJD2000(timeval time, double* JD2000) { ReturnValue_t Clock::convertTimevalToJD2000(timeval time, double* JD2000) {
*JD2000 = (time.tv_sec - 946728000. + time.tv_usec / 1000000.) / 24. *JD2000 = (time.tv_sec - 946728000. + time.tv_usec / 1000000.) / 24.
/ 3600.; / 3600.;
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
} }
ReturnValue_t Clock::convertUTCToTT(timeval utc, timeval* tt) { ReturnValue_t Clock::convertUTCToTT(timeval utc, timeval* tt) {
//SHOULDDO: works not for dates in the past (might have less leap seconds) //SHOULDDO: works not for dates in the past (might have less leap seconds)
if (timeMutex == nullptr) { if (timeMutex == nullptr) {
return HasReturnvaluesIF::RETURN_FAILED; return HasReturnvaluesIF::RETURN_FAILED;
} }
uint16_t leapSeconds; uint16_t leapSeconds;
ReturnValue_t result = getLeapSeconds(&leapSeconds); ReturnValue_t result = getLeapSeconds(&leapSeconds);
if (result != HasReturnvaluesIF::RETURN_OK) { if (result != HasReturnvaluesIF::RETURN_OK) {
return result; return result;
} }
timeval leapSeconds_timeval = { 0, 0 }; timeval leapSeconds_timeval = { 0, 0 };
leapSeconds_timeval.tv_sec = leapSeconds; leapSeconds_timeval.tv_sec = leapSeconds;
//initial offset between UTC and TAI //initial offset between UTC and TAI
timeval UTCtoTAI1972 = { 10, 0 }; timeval UTCtoTAI1972 = { 10, 0 };
timeval TAItoTT = { 32, 184000 }; timeval TAItoTT = { 32, 184000 };
*tt = utc + leapSeconds_timeval + UTCtoTAI1972 + TAItoTT; *tt = utc + leapSeconds_timeval + UTCtoTAI1972 + TAItoTT;
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
} }
ReturnValue_t Clock::setLeapSeconds(const uint16_t leapSeconds_) { ReturnValue_t Clock::setLeapSeconds(const uint16_t leapSeconds_) {
if(checkOrCreateClockMutex()!=HasReturnvaluesIF::RETURN_OK){ if(checkOrCreateClockMutex()!=HasReturnvaluesIF::RETURN_OK){
return HasReturnvaluesIF::RETURN_FAILED; return HasReturnvaluesIF::RETURN_FAILED;
} }
MutexHelper helper(timeMutex); MutexHelper helper(timeMutex);
leapSeconds = leapSeconds_; leapSeconds = leapSeconds_;
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
} }
ReturnValue_t Clock::getLeapSeconds(uint16_t* leapSeconds_) { ReturnValue_t Clock::getLeapSeconds(uint16_t* leapSeconds_) {
if(timeMutex==nullptr){ if(timeMutex==nullptr){
return HasReturnvaluesIF::RETURN_FAILED; return HasReturnvaluesIF::RETURN_FAILED;
} }
MutexHelper helper(timeMutex); MutexHelper helper(timeMutex);
*leapSeconds_ = leapSeconds; *leapSeconds_ = leapSeconds;
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
} }
ReturnValue_t Clock::checkOrCreateClockMutex(){ ReturnValue_t Clock::checkOrCreateClockMutex(){
if(timeMutex==nullptr){ if(timeMutex==nullptr){
MutexFactory* mutexFactory = MutexFactory::instance(); MutexFactory* mutexFactory = MutexFactory::instance();
if (mutexFactory == nullptr) { if (mutexFactory == nullptr) {
return HasReturnvaluesIF::RETURN_FAILED; return HasReturnvaluesIF::RETURN_FAILED;
} }
timeMutex = mutexFactory->createMutex(); timeMutex = mutexFactory->createMutex();
if (timeMutex == nullptr) { if (timeMutex == nullptr) {
return HasReturnvaluesIF::RETURN_FAILED; return HasReturnvaluesIF::RETURN_FAILED;
} }
} }
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
} }

View File

@ -44,5 +44,10 @@ ReturnValue_t TaskFactory::delayTask(uint32_t delayMs){
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
} }
void TaskFactory::printMissedDeadline() {
/* TODO: Implement */
return;
}
TaskFactory::TaskFactory() { TaskFactory::TaskFactory() {
} }

View File

@ -65,6 +65,7 @@ enum {
HOUSEKEEPING_MANAGER, //HKM 60 HOUSEKEEPING_MANAGER, //HKM 60
DLE_ENCODER, //DLEE 61 DLE_ENCODER, //DLEE 61
PUS_SERVICE_9, //PUS9 62 PUS_SERVICE_9, //PUS9 62
FILE_SYSTEM, //FILS 63
FW_CLASS_ID_COUNT //is actually count + 1 ! FW_CLASS_ID_COUNT //is actually count + 1 !
}; };

View File

@ -62,6 +62,12 @@ public:
*/ */
static ReturnValue_t delayTask(uint32_t delayMs); static ReturnValue_t delayTask(uint32_t delayMs);
/**
* OS specific implementation to print deadline. In most cases, there is a OS specific
* way to retrieve the task name and print it out as well.
*/
static void printMissedDeadline();
private: private:
/** /**
* External instantiation is not allowed. * External instantiation is not allowed.

File diff suppressed because it is too large Load Diff

View File

@ -21,215 +21,215 @@ bool operator==(const timeval& lhs, const timeval& rhs);
*/ */
class CCSDSTime: public HasReturnvaluesIF { class CCSDSTime: public HasReturnvaluesIF {
public: public:
/** /**
* The Time code identifications, bits 4-6 in the P-Field * The Time code identifications, bits 4-6 in the P-Field
*/ */
enum TimeCodeIdentification { enum TimeCodeIdentification {
CCS = 0b101, CCS = 0b101,
CUC_LEVEL1 = 0b001, CUC_LEVEL1 = 0b001,
CUC_LEVEL2 = 0b010, CUC_LEVEL2 = 0b010,
CDS = 0b100, CDS = 0b100,
AGENCY_DEFINED = 0b110 AGENCY_DEFINED = 0b110
}; };
static const uint8_t P_FIELD_CUC_6B_CCSDS = (CUC_LEVEL1 << 4) + (3 << 2) static const uint8_t P_FIELD_CUC_6B_CCSDS = (CUC_LEVEL1 << 4) + (3 << 2)
+ 2; + 2;
static const uint8_t P_FIELD_CUC_6B_AGENCY = (CUC_LEVEL2 << 4) + (3 << 2) static const uint8_t P_FIELD_CUC_6B_AGENCY = (CUC_LEVEL2 << 4) + (3 << 2)
+ 2; + 2;
static const uint8_t P_FIELD_CDS_SHORT = (CDS << 4); static const uint8_t P_FIELD_CDS_SHORT = (CDS << 4);
/** /**
* Struct for CDS day-segmented format. * Struct for CDS day-segmented format.
*/ */
struct CDS_short { struct CDS_short {
uint8_t pField; uint8_t pField;
uint8_t dayMSB; uint8_t dayMSB;
uint8_t dayLSB; uint8_t dayLSB;
uint8_t msDay_hh; uint8_t msDay_hh;
uint8_t msDay_h; uint8_t msDay_h;
uint8_t msDay_l; uint8_t msDay_l;
uint8_t msDay_ll; uint8_t msDay_ll;
}; };
/** /**
* Struct for the CCS fromat in day of month variation with max resolution * Struct for the CCS fromat in day of month variation with max resolution
*/ */
struct Ccs_seconds { struct Ccs_seconds {
uint8_t pField; uint8_t pField;
uint8_t yearMSB; uint8_t yearMSB;
uint8_t yearLSB; uint8_t yearLSB;
uint8_t month; uint8_t month;
uint8_t day; uint8_t day;
uint8_t hour; uint8_t hour;
uint8_t minute; uint8_t minute;
uint8_t second; uint8_t second;
}; };
/** /**
* Struct for the CCS fromat in day of month variation with 10E-4 seconds resolution * Struct for the CCS fromat in day of month variation with 10E-4 seconds resolution
*/ */
struct Ccs_mseconds { struct Ccs_mseconds {
uint8_t pField; uint8_t pField;
uint8_t yearMSB; uint8_t yearMSB;
uint8_t yearLSB; uint8_t yearLSB;
uint8_t month; uint8_t month;
uint8_t day; uint8_t day;
uint8_t hour; uint8_t hour;
uint8_t minute; uint8_t minute;
uint8_t second; uint8_t second;
uint8_t secondEminus2; uint8_t secondEminus2;
uint8_t secondEminus4; uint8_t secondEminus4;
}; };
struct OBT_FLP { struct OBT_FLP {
uint8_t pFiled; uint8_t pFiled;
uint8_t seconds_hh; uint8_t seconds_hh;
uint8_t seconds_h; uint8_t seconds_h;
uint8_t seconds_l; uint8_t seconds_l;
uint8_t seconds_ll; uint8_t seconds_ll;
uint8_t subsecondsMSB; uint8_t subsecondsMSB;
uint8_t subsecondsLSB; uint8_t subsecondsLSB;
}; };
struct TimevalLess { struct TimevalLess {
bool operator()(const timeval& lhs, const timeval& rhs) const { bool operator()(const timeval& lhs, const timeval& rhs) const {
return (lhs < rhs); return (lhs < rhs);
} }
}; };
static const uint8_t INTERFACE_ID = CLASS_ID::CCSDS_TIME_HELPER_CLASS; static const uint8_t INTERFACE_ID = CLASS_ID::CCSDS_TIME_HELPER_CLASS;
static const ReturnValue_t UNSUPPORTED_TIME_FORMAT = MAKE_RETURN_CODE(0); static const ReturnValue_t UNSUPPORTED_TIME_FORMAT = MAKE_RETURN_CODE(0);
static const ReturnValue_t NOT_ENOUGH_INFORMATION_FOR_TARGET_FORMAT = static const ReturnValue_t NOT_ENOUGH_INFORMATION_FOR_TARGET_FORMAT =
MAKE_RETURN_CODE(1); MAKE_RETURN_CODE(1);
static const ReturnValue_t LENGTH_MISMATCH = MAKE_RETURN_CODE(2); static const ReturnValue_t LENGTH_MISMATCH = MAKE_RETURN_CODE(2);
static const ReturnValue_t INVALID_TIME_FORMAT = MAKE_RETURN_CODE(3); static const ReturnValue_t INVALID_TIME_FORMAT = MAKE_RETURN_CODE(3);
static const ReturnValue_t INVALID_DAY_OF_YEAR = MAKE_RETURN_CODE(4); static const ReturnValue_t INVALID_DAY_OF_YEAR = MAKE_RETURN_CODE(4);
static const ReturnValue_t TIME_DOES_NOT_FIT_FORMAT = MAKE_RETURN_CODE(5); static const ReturnValue_t TIME_DOES_NOT_FIT_FORMAT = MAKE_RETURN_CODE(5);
/** /**
* convert a TimeofDay struct to ccs with seconds resolution * convert a TimeofDay struct to ccs with seconds resolution
* *
* @param to pointer to a CCS struct * @param to pointer to a CCS struct
* @param from pointer to a TimeOfDay Struct * @param from pointer to a TimeOfDay Struct
* @return * @return
* - @c RETURN_OK if OK * - @c RETURN_OK if OK
* - @c INVALID_TIMECODE if not OK * - @c INVALID_TIMECODE if not OK
*/ */
static ReturnValue_t convertToCcsds(Ccs_seconds *to, static ReturnValue_t convertToCcsds(Ccs_seconds *to,
Clock::TimeOfDay_t const *from); Clock::TimeOfDay_t const *from);
/** /**
* Converts to CDS format from timeval. * Converts to CDS format from timeval.
* @param to pointer to the CDS struct to generate * @param to pointer to the CDS struct to generate
* @param from pointer to a timeval struct which comprises a time of day since UNIX epoch. * @param from pointer to a timeval struct which comprises a time of day since UNIX epoch.
* @return * @return
* - @c RETURN_OK as it assumes a valid timeval. * - @c RETURN_OK as it assumes a valid timeval.
*/ */
static ReturnValue_t convertToCcsds(CDS_short* to, timeval const *from); static ReturnValue_t convertToCcsds(CDS_short* to, timeval const *from);
static ReturnValue_t convertToCcsds(OBT_FLP* to, timeval const *from); static ReturnValue_t convertToCcsds(OBT_FLP* to, timeval const *from);
/** /**
* convert a TimeofDay struct to ccs with 10E-3 seconds resolution * convert a TimeofDay struct to ccs with 10E-3 seconds resolution
* *
* The 10E-4 seconds in the CCS Struct are 0 as the TimeOfDay only has ms resolution * The 10E-4 seconds in the CCS Struct are 0 as the TimeOfDay only has ms resolution
* *
* @param to pointer to a CCS struct * @param to pointer to a CCS struct
* @param from pointer to a TimeOfDay Struct * @param from pointer to a TimeOfDay Struct
* @return * @return
* - @c RETURN_OK if OK * - @c RETURN_OK if OK
* - @c INVALID_TIMECODE if not OK * - @c INVALID_TIMECODE if not OK
*/ */
static ReturnValue_t convertToCcsds(Ccs_mseconds *to, static ReturnValue_t convertToCcsds(Ccs_mseconds *to,
Clock::TimeOfDay_t const *from); Clock::TimeOfDay_t const *from);
/** /**
* SHOULDDO: can this be modified to recognize padding? * SHOULDDO: can this be modified to recognize padding?
* Tries to interpret a Level 1 CCSDS time code * Tries to interpret a Level 1 CCSDS time code
* *
* It assumes binary formats contain a valid P Field and recognizes the ASCII format * It assumes binary formats contain a valid P Field and recognizes the ASCII format
* by the lack of one. * by the lack of one.
* *
* @param to an empty TimeOfDay struct * @param to an empty TimeOfDay struct
* @param from pointer to an CCSDS Time code * @param from pointer to an CCSDS Time code
* @param length length of the Time code * @param length length of the Time code
* @return * @return
* - @c RETURN_OK if successful * - @c RETURN_OK if successful
* - @c UNSUPPORTED_TIME_FORMAT if a (possibly valid) time code is not supported * - @c UNSUPPORTED_TIME_FORMAT if a (possibly valid) time code is not supported
* - @c LENGTH_MISMATCH if the length does not match the P Field * - @c LENGTH_MISMATCH if the length does not match the P Field
* - @c INVALID_TIME_FORMAT if the format or a value is invalid * - @c INVALID_TIME_FORMAT if the format or a value is invalid
*/ */
static ReturnValue_t convertFromCcsds(Clock::TimeOfDay_t *to, static ReturnValue_t convertFromCcsds(Clock::TimeOfDay_t *to,
uint8_t const *from, size_t length); uint8_t const *from, size_t length);
/** /**
* not implemented yet * not implemented yet
* *
* @param to * @param to
* @param from * @param from
* @return * @return
*/ */
static ReturnValue_t convertFromCcsds(timeval *to, uint8_t const *from, static ReturnValue_t convertFromCcsds(timeval *to, uint8_t const *from,
size_t* foundLength, size_t maxLength); size_t* foundLength, size_t maxLength);
static ReturnValue_t convertFromCUC(Clock::TimeOfDay_t *to, static ReturnValue_t convertFromCUC(Clock::TimeOfDay_t *to,
uint8_t const *from, uint8_t length); uint8_t const *from, uint8_t length);
static ReturnValue_t convertFromCUC(timeval *to, uint8_t const *from, static ReturnValue_t convertFromCUC(timeval *to, uint8_t const *from,
size_t* foundLength, size_t maxLength); size_t* foundLength, size_t maxLength);
static ReturnValue_t convertFromCUC(timeval *to, uint8_t pField, static ReturnValue_t convertFromCUC(timeval *to, uint8_t pField,
uint8_t const *from, size_t* foundLength, size_t maxLength); uint8_t const *from, size_t* foundLength, size_t maxLength);
static ReturnValue_t convertFromCCS(timeval *to, uint8_t const *from, static ReturnValue_t convertFromCCS(timeval *to, uint8_t const *from,
size_t* foundLength, size_t maxLength); size_t* foundLength, size_t maxLength);
static ReturnValue_t convertFromCCS(timeval *to, uint8_t pField, static ReturnValue_t convertFromCCS(timeval *to, uint8_t pField,
uint8_t const *from, size_t* foundLength, size_t maxLength); uint8_t const *from, size_t* foundLength, size_t maxLength);
static ReturnValue_t convertFromCDS(Clock::TimeOfDay_t *to, static ReturnValue_t convertFromCDS(Clock::TimeOfDay_t *to,
uint8_t const *from, uint8_t length); uint8_t const *from, uint8_t length);
static ReturnValue_t convertFromCDS(timeval *to, uint8_t const *from, static ReturnValue_t convertFromCDS(timeval *to, uint8_t const *from,
size_t* foundLength, size_t maxLength); size_t* foundLength, size_t maxLength);
static ReturnValue_t convertFromCCS(Clock::TimeOfDay_t *to, static ReturnValue_t convertFromCCS(Clock::TimeOfDay_t *to,
uint8_t const *from, size_t* foundLength, size_t maxLength); uint8_t const *from, size_t* foundLength, size_t maxLength);
static ReturnValue_t convertFromASCII(Clock::TimeOfDay_t *to, static ReturnValue_t convertFromASCII(Clock::TimeOfDay_t *to,
uint8_t const *from, uint8_t length); uint8_t const *from, uint8_t length);
static uint32_t subsecondsToMicroseconds(uint16_t subseconds); static uint32_t subsecondsToMicroseconds(uint16_t subseconds);
private: private:
CCSDSTime(); CCSDSTime();
virtual ~CCSDSTime(); virtual ~CCSDSTime();
/** /**
* checks a ccs time stream for validity * checks a ccs time stream for validity
* *
* Stream may be longer than the actual timecode * Stream may be longer than the actual timecode
* *
* @param time pointer to an Ccs stream * @param time pointer to an Ccs stream
* @param length length of stream * @param length length of stream
* @return * @return
*/ */
static ReturnValue_t checkCcs(const uint8_t* time, uint8_t length); static ReturnValue_t checkCcs(const uint8_t* time, uint8_t length);
static ReturnValue_t checkTimeOfDay(const Clock::TimeOfDay_t *time); static ReturnValue_t checkTimeOfDay(const Clock::TimeOfDay_t *time);
static const uint32_t SECONDS_PER_DAY = 24 * 60 * 60; static const uint32_t SECONDS_PER_DAY = 24 * 60 * 60;
static const uint32_t SECONDS_PER_NON_LEAP_YEAR = SECONDS_PER_DAY * 365; static const uint32_t SECONDS_PER_NON_LEAP_YEAR = SECONDS_PER_DAY * 365;
static const uint32_t DAYS_CCSDS_TO_UNIX_EPOCH = 4383; //!< Time difference between CCSDS and POSIX epoch. This is exact, because leap-seconds where not introduced before 1972. static const uint32_t DAYS_CCSDS_TO_UNIX_EPOCH = 4383; //!< Time difference between CCSDS and POSIX epoch. This is exact, because leap-seconds where not introduced before 1972.
static const uint32_t SECONDS_CCSDS_TO_UNIX_EPOCH = DAYS_CCSDS_TO_UNIX_EPOCH static const uint32_t SECONDS_CCSDS_TO_UNIX_EPOCH = DAYS_CCSDS_TO_UNIX_EPOCH
* SECONDS_PER_DAY; * SECONDS_PER_DAY;
/** /**
* @param dayofYear * @param dayofYear
* @param year * @param year
* @param month * @param month
* @param day * @param day
*/ */
static ReturnValue_t convertDaysOfYear(uint16_t dayofYear, uint16_t year, static ReturnValue_t convertDaysOfYear(uint16_t dayofYear, uint16_t year,
uint8_t *month, uint8_t *day); uint8_t *month, uint8_t *day);
static bool isLeapYear(uint32_t year); static bool isLeapYear(uint32_t year);
static ReturnValue_t convertTimevalToTimeOfDay(Clock::TimeOfDay_t* to, static ReturnValue_t convertTimevalToTimeOfDay(Clock::TimeOfDay_t* to,
timeval* from); timeval* from);
}; };
#endif /* FSFW_TIMEMANAGER_CCSDSTIME_H_ */ #endif /* FSFW_TIMEMANAGER_CCSDSTIME_H_ */

View File

@ -70,7 +70,7 @@ TEST_CASE( "Action Helper" , "[ActionHelper]") {
SECTION("Handle finish"){ SECTION("Handle finish"){
CHECK(not testMqMock.wasMessageSent()); CHECK(not testMqMock.wasMessageSent());
ReturnValue_t status = 0x9876; ReturnValue_t status = 0x9876;
actionHelper.finish(testMqMock.getId(), testActionId, status); actionHelper.finish(true, testMqMock.getId(), testActionId, status);
CHECK(testMqMock.wasMessageSent()); CHECK(testMqMock.wasMessageSent());
CommandMessage testMessage; CommandMessage testMessage;
REQUIRE(testMqMock.receiveMessage(&testMessage) == static_cast<uint32_t>(HasReturnvaluesIF::RETURN_OK)); REQUIRE(testMqMock.receiveMessage(&testMessage) == static_cast<uint32_t>(HasReturnvaluesIF::RETURN_OK));

View File

@ -1,8 +1,13 @@
#include "LocalPoolOwnerBase.h" #include "LocalPoolOwnerBase.h"
#include <catch2/catch_test_macros.hpp> #include <catch2/catch_test_macros.hpp>
#include <catch2/catch_approx.hpp>
#include <fsfw/datapoollocal/HasLocalDataPoolIF.h> #include <fsfw/datapoollocal/HasLocalDataPoolIF.h>
#include <fsfw/datapoollocal/StaticLocalDataSet.h> #include <fsfw/datapoollocal/StaticLocalDataSet.h>
#include <fsfw/datapool/PoolReadHelper.h>
#include <fsfw/globalfunctions/bitutility.h>
#include <unittest/core/CatchDefinitions.h> #include <unittest/core/CatchDefinitions.h>
TEST_CASE("LocalDataSet" , "[LocDataSetTest]") { TEST_CASE("LocalDataSet" , "[LocDataSetTest]") {
@ -12,11 +17,193 @@ TEST_CASE("LocalDataSet" , "[LocDataSetTest]") {
REQUIRE(poolOwner->initializeHkManager() == retval::CATCH_OK); REQUIRE(poolOwner->initializeHkManager() == retval::CATCH_OK);
REQUIRE(poolOwner->initializeHkManagerAfterTaskCreation() REQUIRE(poolOwner->initializeHkManagerAfterTaskCreation()
== retval::CATCH_OK); == retval::CATCH_OK);
const uint32_t setId = 0; LocalPoolStaticTestDataSet localSet;
SECTION("BasicTest") { SECTION("BasicTest") {
StaticLocalDataSet<3> localSet = StaticLocalDataSet<3>( /* Test some basic functions */
sid_t(objects::TEST_LOCAL_POOL_OWNER_BASE, setId)); CHECK(localSet.getLocalPoolIdsSerializedSize(false) == 3 * sizeof(lp_id_t));
CHECK(localSet.getLocalPoolIdsSerializedSize(true) ==
3 * sizeof(lp_id_t) + sizeof(uint8_t));
CHECK(localSet.getSid() == lpool::testSid);
CHECK(localSet.getCreatorObjectId() == objects::TEST_LOCAL_POOL_OWNER_BASE);
size_t maxSize = localSet.getLocalPoolIdsSerializedSize(true);
uint8_t localPoolIdBuff[maxSize];
/* Skip size field */
lp_id_t* lpIds = reinterpret_cast<lp_id_t*>(localPoolIdBuff + 1);
size_t serSize = 0;
uint8_t *localPoolIdBuffPtr = reinterpret_cast<uint8_t*>(localPoolIdBuff);
/* Test local pool ID serialization */
CHECK(localSet.serializeLocalPoolIds(&localPoolIdBuffPtr, &serSize,
maxSize, SerializeIF::Endianness::MACHINE) == retval::CATCH_OK);
CHECK(serSize == maxSize);
CHECK(localPoolIdBuff[0] == 3);
CHECK(lpIds[0] == localSet.localPoolVarUint8.getDataPoolId());
CHECK(lpIds[1] == localSet.localPoolVarFloat.getDataPoolId());
CHECK(lpIds[2] == localSet.localPoolUint16Vec.getDataPoolId());
/* Now serialize without fill count */
lpIds = reinterpret_cast<lp_id_t*>(localPoolIdBuff);
localPoolIdBuffPtr = localPoolIdBuff;
serSize = 0;
CHECK(localSet.serializeLocalPoolIds(&localPoolIdBuffPtr, &serSize,
maxSize, SerializeIF::Endianness::MACHINE, false) == retval::CATCH_OK);
CHECK(serSize == maxSize - sizeof(uint8_t));
CHECK(lpIds[0] == localSet.localPoolVarUint8.getDataPoolId());
CHECK(lpIds[1] == localSet.localPoolVarFloat.getDataPoolId());
CHECK(lpIds[2] == localSet.localPoolUint16Vec.getDataPoolId());
{
/* Test read operation. Values should be all zeros */
PoolReadHelper readHelper(&localSet);
REQUIRE(readHelper.getReadResult() == retval::CATCH_OK);
CHECK(not localSet.isValid());
CHECK(localSet.localPoolVarUint8.value == 0);
CHECK(not localSet.localPoolVarUint8.isValid());
CHECK(localSet.localPoolVarFloat.value == Catch::Approx(0.0));
CHECK(not localSet.localPoolVarUint8.isValid());
CHECK(localSet.localPoolUint16Vec.value[0] == 0);
CHECK(localSet.localPoolUint16Vec.value[1] == 0);
CHECK(localSet.localPoolUint16Vec.value[2] == 0);
CHECK(not localSet.localPoolVarUint8.isValid());
/* Now set new values, commit should be done by read helper automatically */
localSet.localPoolVarUint8 = 232;
localSet.localPoolVarFloat = -2324.322;
localSet.localPoolUint16Vec.value[0] = 232;
localSet.localPoolUint16Vec.value[1] = 23923;
localSet.localPoolUint16Vec.value[2] = 1;
localSet.setValidity(true, true);
}
/* Zero out some values for next test */
localSet.localPoolVarUint8 = 0;
localSet.localPoolVarFloat = 0;
{
/* Now we read again and check whether our zeroed values were overwritten with
the values in the pool */
PoolReadHelper readHelper(&localSet);
REQUIRE(readHelper.getReadResult() == retval::CATCH_OK);
CHECK(localSet.isValid());
CHECK(localSet.localPoolVarUint8.value == 232);
CHECK(localSet.localPoolVarUint8.isValid());
CHECK(localSet.localPoolVarFloat.value == Catch::Approx(-2324.322));
CHECK(localSet.localPoolVarFloat.isValid());
CHECK(localSet.localPoolUint16Vec.value[0] == 232);
CHECK(localSet.localPoolUint16Vec.value[1] == 23923);
CHECK(localSet.localPoolUint16Vec.value[2] == 1);
CHECK(localSet.localPoolUint16Vec.isValid());
/* Now we serialize these values into a buffer without the validity buffer */
localSet.setValidityBufferGeneration(false);
maxSize = localSet.getSerializedSize();
CHECK(maxSize == sizeof(uint8_t) + sizeof(uint16_t) * 3 + sizeof(float));
serSize = 0;
/* Already reserve additional space for validity buffer, will be needed later */
uint8_t buffer[maxSize + 1];
uint8_t* buffPtr = buffer;
CHECK(localSet.serialize(&buffPtr, &serSize, maxSize,
SerializeIF::Endianness::MACHINE) == retval::CATCH_OK);
uint8_t rawUint8 = buffer[0];
CHECK(rawUint8 == 232);
float rawFloat = 0.0;
std::memcpy(&rawFloat, buffer + sizeof(uint8_t), sizeof(float));
CHECK(rawFloat == Catch::Approx(-2324.322));
uint16_t rawUint16Vec[3];
std::memcpy(&rawUint16Vec, buffer + sizeof(uint8_t) + sizeof(float),
3 * sizeof(uint16_t));
CHECK(rawUint16Vec[0] == 232);
CHECK(rawUint16Vec[1] == 23923);
CHECK(rawUint16Vec[2] == 1);
size_t sizeToDeserialize = maxSize;
/* Now we zeros out the raw entries and deserialize back into the dataset */
std::memset(buffer, 0, sizeof(buffer));
const uint8_t* constBuffPtr = buffer;
CHECK(localSet.deSerialize(&constBuffPtr, &sizeToDeserialize,
SerializeIF::Endianness::MACHINE) == retval::CATCH_OK);
/* Check whether deserialization was successfull */
CHECK(localSet.localPoolVarUint8.value == 0);
CHECK(localSet.localPoolVarFloat.value == Catch::Approx(0.0));
CHECK(localSet.localPoolVarUint8.value == 0);
CHECK(localSet.localPoolUint16Vec.value[0] == 0);
CHECK(localSet.localPoolUint16Vec.value[1] == 0);
CHECK(localSet.localPoolUint16Vec.value[2] == 0);
/* Validity should be unchanged */
CHECK(localSet.localPoolVarUint8.isValid());
CHECK(localSet.localPoolVarFloat.isValid());
CHECK(localSet.localPoolUint16Vec.isValid());
/* Now we do the same process but with the validity buffer */
localSet.localPoolVarUint8 = 232;
localSet.localPoolVarFloat = -2324.322;
localSet.localPoolUint16Vec.value[0] = 232;
localSet.localPoolUint16Vec.value[1] = 23923;
localSet.localPoolUint16Vec.value[2] = 1;
localSet.localPoolVarUint8.setValid(true);
localSet.localPoolVarFloat.setValid(false);
localSet.localPoolUint16Vec.setValid(true);
localSet.setValidityBufferGeneration(true);
maxSize = localSet.getSerializedSize();
CHECK(maxSize == sizeof(uint8_t) + sizeof(uint16_t) * 3 + sizeof(float) + 1);
serSize = 0;
buffPtr = buffer;
CHECK(localSet.serialize(&buffPtr, &serSize, maxSize,
SerializeIF::Endianness::MACHINE) == retval::CATCH_OK);
CHECK(rawUint8 == 232);
std::memcpy(&rawFloat, buffer + sizeof(uint8_t), sizeof(float));
CHECK(rawFloat == Catch::Approx(-2324.322));
std::memcpy(&rawUint16Vec, buffer + sizeof(uint8_t) + sizeof(float),
3 * sizeof(uint16_t));
CHECK(rawUint16Vec[0] == 232);
CHECK(rawUint16Vec[1] == 23923);
CHECK(rawUint16Vec[2] == 1);
/* We can do it like this because the buffer only has one byte for
less than 8 variables */
uint8_t* validityByte = buffer + sizeof(buffer) - 1;
CHECK(bitutil::bitGet(validityByte, 0) == true);
CHECK(bitutil::bitGet(validityByte, 1) == false);
CHECK(bitutil::bitGet(validityByte, 2) == true);
/* Now we manipulate the validity buffer for the deserialization */
bitutil::bitClear(validityByte, 0);
bitutil::bitSet(validityByte, 1);
bitutil::bitClear(validityByte, 2);
/* Zero out everything except validity buffer */
std::memset(buffer, 0, sizeof(buffer) - 1);
sizeToDeserialize = maxSize;
constBuffPtr = buffer;
CHECK(localSet.deSerialize(&constBuffPtr, &sizeToDeserialize,
SerializeIF::Endianness::MACHINE) == retval::CATCH_OK);
/* Check whether deserialization was successfull */
CHECK(localSet.localPoolVarUint8.value == 0);
CHECK(localSet.localPoolVarFloat.value == Catch::Approx(0.0));
CHECK(localSet.localPoolVarUint8.value == 0);
CHECK(localSet.localPoolUint16Vec.value[0] == 0);
CHECK(localSet.localPoolUint16Vec.value[1] == 0);
CHECK(localSet.localPoolUint16Vec.value[2] == 0);
CHECK(not localSet.localPoolVarUint8.isValid());
CHECK(localSet.localPoolVarFloat.isValid());
CHECK(not localSet.localPoolUint16Vec.isValid());
}
/* Common fault test cases */
LocalPoolObjectBase* variableHandle = poolOwner->getPoolObjectHandle(lpool::uint32VarId);
CHECK(variableHandle != nullptr);
CHECK(localSet.registerVariable(variableHandle) ==
static_cast<int>(DataSetIF::DATA_SET_FULL));
variableHandle = nullptr;
REQUIRE(localSet.registerVariable(variableHandle) ==
static_cast<int>(DataSetIF::POOL_VAR_NULL));
} }
/* we need to reset the subscription list because the pool owner
is a global object. */
CHECK(poolOwner->reset() == retval::CATCH_OK);
} }

View File

@ -160,7 +160,7 @@ TEST_CASE("LocalPoolManagerTest" , "[LocManTest]") {
CHECK(messageSent.getCommand() == static_cast<int>( CHECK(messageSent.getCommand() == static_cast<int>(
HousekeepingMessage::UPDATE_NOTIFICATION_VARIABLE)); HousekeepingMessage::UPDATE_NOTIFICATION_VARIABLE));
/* Now subscribe for the dataset update (HK and update) again with subscription interface */ /* Now subscribe for the dataset update (HK and update) again with subscription interface */
REQUIRE(subscriptionIF->subscribeForSetUpdateMessages(lpool::testSetId, REQUIRE(subscriptionIF->subscribeForSetUpdateMessage(lpool::testSetId,
objects::NO_OBJECT, objects::HK_RECEIVER_MOCK, false) == retval::CATCH_OK); objects::NO_OBJECT, objects::HK_RECEIVER_MOCK, false) == retval::CATCH_OK);
REQUIRE(poolOwner->subscribeWrapperSetUpdateHk() == retval::CATCH_OK); REQUIRE(poolOwner->subscribeWrapperSetUpdateHk() == retval::CATCH_OK);
@ -192,7 +192,7 @@ TEST_CASE("LocalPoolManagerTest" , "[LocManTest]") {
/* we need to reset the subscription list because the pool owner /* we need to reset the subscription list because the pool owner
is a global object. */ is a global object. */
poolOwner->resetSubscriptionList(); CHECK(poolOwner->reset() == retval::CATCH_OK);
mqMock->clearMessages(true); mqMock->clearMessages(true);
} }

View File

@ -10,6 +10,7 @@
#include <testcfg/objects/systemObjectList.h> #include <testcfg/objects/systemObjectList.h>
#include <fsfw/datapoollocal/StaticLocalDataSet.h> #include <fsfw/datapoollocal/StaticLocalDataSet.h>
#include <fsfw/unittest/tests/mocks/MessageQueueMockBase.h> #include <fsfw/unittest/tests/mocks/MessageQueueMockBase.h>
#include "../../../datapool/PoolReadHelper.h"
namespace lpool { namespace lpool {
static constexpr lp_id_t uint8VarId = 0; static constexpr lp_id_t uint8VarId = 0;
@ -31,6 +32,23 @@ static const gp_id_t uint64Vec2Id = gp_id_t(objects::TEST_LOCAL_POOL_OWNER_BASE,
} }
class LocalPoolStaticTestDataSet: public StaticLocalDataSet<3> {
public:
LocalPoolStaticTestDataSet():
StaticLocalDataSet(lpool::testSid) {
}
LocalPoolStaticTestDataSet(HasLocalDataPoolIF* owner, uint32_t setId):
StaticLocalDataSet(owner, setId) {
}
lp_var_t<uint8_t> localPoolVarUint8 = lp_var_t<uint8_t>(lpool::uint8VarGpid, this);
lp_var_t<float> localPoolVarFloat = lp_var_t<float>(lpool::floatVarGpid, this);
lp_vec_t<uint16_t, 3> localPoolUint16Vec = lp_vec_t<uint16_t, 3>(lpool::uint16Vec3Gpid, this);
private:
};
class LocalPoolTestDataSet: public LocalDataSet { class LocalPoolTestDataSet: public LocalDataSet {
public: public:
LocalPoolTestDataSet(): LocalPoolTestDataSet():
@ -41,19 +59,6 @@ public:
LocalDataSet(owner, setId, lpool::dataSetMaxVariables) { LocalDataSet(owner, setId, lpool::dataSetMaxVariables) {
} }
// ReturnValue_t assignPointers() {
// PoolVariableIF** rawVarArray = getContainer();
// localPoolVarUint8 = dynamic_cast<lp_var_t<uint8_t>*>(rawVarArray[0]);
// localPoolVarFloat = dynamic_cast<lp_var_t<float>*>(rawVarArray[1]);
// localPoolUint16Vec = dynamic_cast<lp_vec_t<uint16_t, 3>*>(
// rawVarArray[2]);
// if(localPoolVarUint8 == nullptr or localPoolVarFloat == nullptr or
// localPoolUint16Vec == nullptr) {
// return HasReturnvaluesIF::RETURN_FAILED;
// }
// return HasReturnvaluesIF::RETURN_OK;
// }
lp_var_t<uint8_t> localPoolVarUint8 = lp_var_t<uint8_t>(lpool::uint8VarGpid, this); lp_var_t<uint8_t> localPoolVarUint8 = lp_var_t<uint8_t>(lpool::uint8VarGpid, this);
lp_var_t<float> localPoolVarFloat = lp_var_t<float>(lpool::floatVarGpid, this); lp_var_t<float> localPoolVarFloat = lp_var_t<float>(lpool::floatVarGpid, this);
lp_vec_t<uint16_t, 3> localPoolUint16Vec = lp_vec_t<uint16_t, 3>(lpool::uint16Vec3Gpid, this); lp_vec_t<uint16_t, 3> localPoolUint16Vec = lp_vec_t<uint16_t, 3>(lpool::uint16Vec3Gpid, this);
@ -164,25 +169,62 @@ public:
} }
ReturnValue_t subscribeWrapperSetUpdate() { ReturnValue_t subscribeWrapperSetUpdate() {
return poolManager.subscribeForSetUpdateMessages(lpool::testSetId, return poolManager.subscribeForSetUpdateMessage(lpool::testSetId,
objects::NO_OBJECT, objects::HK_RECEIVER_MOCK, false); objects::NO_OBJECT, objects::HK_RECEIVER_MOCK, false);
} }
ReturnValue_t subscribeWrapperSetUpdateSnapshot() { ReturnValue_t subscribeWrapperSetUpdateSnapshot() {
return poolManager.subscribeForSetUpdateMessages(lpool::testSetId, return poolManager.subscribeForSetUpdateMessage(lpool::testSetId,
objects::NO_OBJECT, objects::HK_RECEIVER_MOCK, true); objects::NO_OBJECT, objects::HK_RECEIVER_MOCK, true);
} }
ReturnValue_t subscribeWrapperSetUpdateHk(bool diagnostics = false) { ReturnValue_t subscribeWrapperSetUpdateHk(bool diagnostics = false) {
return poolManager.subscribeForUpdatePackets(lpool::testSid, diagnostics, return poolManager.subscribeForUpdatePacket(lpool::testSid, diagnostics,
false, objects::HK_RECEIVER_MOCK); false, objects::HK_RECEIVER_MOCK);
} }
ReturnValue_t subscribeWrapperVariableUpdate(lp_id_t localPoolId) { ReturnValue_t subscribeWrapperVariableUpdate(lp_id_t localPoolId) {
return poolManager.subscribeForVariableUpdateMessages(localPoolId, return poolManager.subscribeForVariableUpdateMessage(localPoolId,
MessageQueueIF::NO_QUEUE, objects::HK_RECEIVER_MOCK, false); MessageQueueIF::NO_QUEUE, objects::HK_RECEIVER_MOCK, false);
} }
ReturnValue_t reset() {
resetSubscriptionList();
ReturnValue_t status = HasReturnvaluesIF::RETURN_OK;
{
PoolReadGuard readHelper(&dataset);
if(readHelper.getReadResult() != HasReturnvaluesIF::RETURN_OK) {
status = readHelper.getReadResult();
}
dataset.localPoolVarUint8.value = 0;
dataset.localPoolVarFloat.value = 0.0;
dataset.localPoolUint16Vec.value[0] = 0;
dataset.localPoolUint16Vec.value[1] = 0;
dataset.localPoolUint16Vec.value[2] = 0;
dataset.setValidity(false, true);
}
{
PoolReadGuard readHelper(&testUint32);
if(readHelper.getReadResult() != HasReturnvaluesIF::RETURN_OK) {
status = readHelper.getReadResult();
}
testUint32.value = 0;
testUint32.setValid(false);
}
{
PoolReadGuard readHelper(&testInt64Vec);
if(readHelper.getReadResult() != HasReturnvaluesIF::RETURN_OK) {
status = readHelper.getReadResult();
}
testInt64Vec.value[0] = 0;
testInt64Vec.value[1] = 0;
testInt64Vec.setValid(false);
}
return status;
}
void resetSubscriptionList() { void resetSubscriptionList() {
poolManager.clearReceiversList(); poolManager.clearReceiversList();
} }
@ -191,14 +233,12 @@ public:
LocalPoolTestDataSet dataset; LocalPoolTestDataSet dataset;
private: private:
lp_var_t<uint8_t> testUint8 = lp_var_t<uint8_t>(this, lpool::uint8VarId, lp_var_t<uint8_t> testUint8 = lp_var_t<uint8_t>(this, lpool::uint8VarId);
&dataset); lp_var_t<float> testFloat = lp_var_t<float>(this, lpool::floatVarId);
lp_var_t<float> testFloat = lp_var_t<float>(this, lpool::floatVarId,
&dataset);
lp_var_t<uint32_t> testUint32 = lp_var_t<uint32_t>(this, lpool::uint32VarId); lp_var_t<uint32_t> testUint32 = lp_var_t<uint32_t>(this, lpool::uint32VarId);
lp_vec_t<uint16_t, 3> testUint16Vec = lp_vec_t<uint16_t, 3>(this, lp_vec_t<uint16_t, 3> testUint16Vec = lp_vec_t<uint16_t, 3>(this,
lpool::uint16Vec3Id, &dataset); lpool::uint16Vec3Id);
lp_vec_t<int64_t, 2> testInt64Vec = lp_vec_t<int64_t, 2>(this, lp_vec_t<int64_t, 2> testInt64Vec = lp_vec_t<int64_t, 2>(this,
lpool::int64Vec2Id); lpool::int64Vec2Id);

View File

@ -118,6 +118,8 @@ TEST_CASE("LocalPoolVariable" , "[LocPoolVarTest]") {
lpool::uint8VarId); lpool::uint8VarId);
} }
CHECK(poolOwner->reset() == retval::CATCH_OK);
} }