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

This commit is contained in:
Robin Müller 2021-02-03 13:39:09 +01:00
commit 8c5e261a0d
119 changed files with 9240 additions and 5985 deletions

View File

@ -6,120 +6,120 @@
ActionHelper::ActionHelper(HasActionsIF* setOwner, ActionHelper::ActionHelper(HasActionsIF* setOwner,
MessageQueueIF* useThisQueue) : MessageQueueIF* useThisQueue) :
owner(setOwner), queueToUse(useThisQueue) { owner(setOwner), queueToUse(useThisQueue) {
} }
ActionHelper::~ActionHelper() { ActionHelper::~ActionHelper() {
} }
ReturnValue_t ActionHelper::handleActionMessage(CommandMessage* command) { ReturnValue_t ActionHelper::handleActionMessage(CommandMessage* command) {
if (command->getCommand() == ActionMessage::EXECUTE_ACTION) { if (command->getCommand() == ActionMessage::EXECUTE_ACTION) {
ActionId_t currentAction = ActionMessage::getActionId(command); ActionId_t currentAction = ActionMessage::getActionId(command);
prepareExecution(command->getSender(), currentAction, prepareExecution(command->getSender(), currentAction,
ActionMessage::getStoreId(command)); ActionMessage::getStoreId(command));
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
} else { } else {
return CommandMessage::UNKNOWN_COMMAND; return CommandMessage::UNKNOWN_COMMAND;
} }
} }
ReturnValue_t ActionHelper::initialize(MessageQueueIF* queueToUse_) { ReturnValue_t ActionHelper::initialize(MessageQueueIF* queueToUse_) {
ipcStore = objectManager->get<StorageManagerIF>(objects::IPC_STORE); ipcStore = objectManager->get<StorageManagerIF>(objects::IPC_STORE);
if (ipcStore == nullptr) { if (ipcStore == nullptr) {
return HasReturnvaluesIF::RETURN_FAILED; return HasReturnvaluesIF::RETURN_FAILED;
} }
if(queueToUse_ != nullptr) { if(queueToUse_ != nullptr) {
setQueueToUse(queueToUse_); setQueueToUse(queueToUse_);
} }
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
} }
void ActionHelper::step(uint8_t step, MessageQueueId_t reportTo, void ActionHelper::step(uint8_t step, MessageQueueId_t reportTo,
ActionId_t commandId, ReturnValue_t result) { ActionId_t commandId, ReturnValue_t result) {
CommandMessage reply; CommandMessage reply;
ActionMessage::setStepReply(&reply, commandId, step + STEP_OFFSET, result); ActionMessage::setStepReply(&reply, commandId, step + STEP_OFFSET, result);
queueToUse->sendMessage(reportTo, &reply); queueToUse->sendMessage(reportTo, &reply);
} }
void ActionHelper::finish(MessageQueueId_t reportTo, ActionId_t commandId, void ActionHelper::finish(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, result);
queueToUse->sendMessage(reportTo, &reply); queueToUse->sendMessage(reportTo, &reply);
} }
void ActionHelper::setQueueToUse(MessageQueueIF* queue) { void ActionHelper::setQueueToUse(MessageQueueIF* queue) {
queueToUse = queue; queueToUse = queue;
} }
void ActionHelper::prepareExecution(MessageQueueId_t commandedBy, void ActionHelper::prepareExecution(MessageQueueId_t commandedBy,
ActionId_t actionId, store_address_t dataAddress) { ActionId_t actionId, store_address_t dataAddress) {
const uint8_t* dataPtr = NULL; const uint8_t* dataPtr = NULL;
size_t size = 0; size_t size = 0;
ReturnValue_t result = ipcStore->getData(dataAddress, &dataPtr, &size); ReturnValue_t result = ipcStore->getData(dataAddress, &dataPtr, &size);
if (result != HasReturnvaluesIF::RETURN_OK) { if (result != HasReturnvaluesIF::RETURN_OK) {
CommandMessage reply; CommandMessage reply;
ActionMessage::setStepReply(&reply, actionId, 0, result); ActionMessage::setStepReply(&reply, actionId, 0, result);
queueToUse->sendMessage(commandedBy, &reply); queueToUse->sendMessage(commandedBy, &reply);
return; return;
} }
result = owner->executeAction(actionId, commandedBy, dataPtr, size); result = owner->executeAction(actionId, commandedBy, dataPtr, size);
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, result);
queueToUse->sendMessage(commandedBy, &reply); queueToUse->sendMessage(commandedBy, &reply);
} }
if (result != HasReturnvaluesIF::RETURN_OK) { if (result != HasReturnvaluesIF::RETURN_OK) {
CommandMessage reply; CommandMessage reply;
ActionMessage::setStepReply(&reply, actionId, 0, result); ActionMessage::setStepReply(&reply, actionId, 0, result);
queueToUse->sendMessage(commandedBy, &reply); queueToUse->sendMessage(commandedBy, &reply);
return; return;
} }
} }
ReturnValue_t ActionHelper::reportData(MessageQueueId_t reportTo, ReturnValue_t ActionHelper::reportData(MessageQueueId_t reportTo,
ActionId_t replyId, SerializeIF* data, bool hideSender) { ActionId_t replyId, SerializeIF* data, bool hideSender) {
CommandMessage reply; CommandMessage reply;
store_address_t storeAddress; store_address_t storeAddress;
uint8_t *dataPtr; uint8_t *dataPtr;
size_t maxSize = data->getSerializedSize(); size_t maxSize = data->getSerializedSize();
if (maxSize == 0) { if (maxSize == 0) {
//No error, there's simply nothing to report. //No error, there's simply nothing to report.
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
} }
size_t size = 0; size_t size = 0;
ReturnValue_t result = ipcStore->getFreeElement(&storeAddress, maxSize, ReturnValue_t result = ipcStore->getFreeElement(&storeAddress, maxSize,
&dataPtr); &dataPtr);
if (result != HasReturnvaluesIF::RETURN_OK) { if (result != HasReturnvaluesIF::RETURN_OK) {
return result; return result;
} }
result = data->serialize(&dataPtr, &size, maxSize, result = data->serialize(&dataPtr, &size, maxSize,
SerializeIF::Endianness::BIG); SerializeIF::Endianness::BIG);
if (result != HasReturnvaluesIF::RETURN_OK) { if (result != HasReturnvaluesIF::RETURN_OK) {
ipcStore->deleteData(storeAddress); ipcStore->deleteData(storeAddress);
return result; return result;
} }
// We don't need to report the objectId, as we receive REQUESTED data // We don't need to report the objectId, as we receive REQUESTED data
// before the completion success message. // before the completion success message.
// True aperiodic replies need to be reported with // True aperiodic replies need to be reported with
// another dedicated message. // another dedicated message.
ActionMessage::setDataReply(&reply, replyId, storeAddress); ActionMessage::setDataReply(&reply, replyId, storeAddress);
// If the sender needs to be hidden, for example to handle packet // If the sender needs to be hidden, for example to handle packet
// as unrequested reply, this will be done here. // as unrequested reply, this will be done here.
if (hideSender) { if (hideSender) {
result = MessageQueueSenderIF::sendMessage(reportTo, &reply); result = MessageQueueSenderIF::sendMessage(reportTo, &reply);
} }
else { else {
result = queueToUse->sendMessage(reportTo, &reply); result = queueToUse->sendMessage(reportTo, &reply);
} }
if (result != HasReturnvaluesIF::RETURN_OK){ if (result != HasReturnvaluesIF::RETURN_OK){
ipcStore->deleteData(storeAddress); ipcStore->deleteData(storeAddress);
} }
return result; return result;
} }
void ActionHelper::resetHelper() { void ActionHelper::resetHelper() {
@ -155,7 +155,7 @@ ReturnValue_t ActionHelper::reportData(MessageQueueId_t reportTo,
result = queueToUse->sendMessage(reportTo, &reply); result = queueToUse->sendMessage(reportTo, &reply);
} }
if (result != HasReturnvaluesIF::RETURN_OK){ if (result != HasReturnvaluesIF::RETURN_OK) {
ipcStore->deleteData(storeAddress); ipcStore->deleteData(storeAddress);
} }
return result; return result;

View File

@ -18,68 +18,68 @@ class HasActionsIF;
class ActionHelper { class ActionHelper {
public: public:
/** /**
* Constructor of the action helper * Constructor of the action helper
* @param setOwner Pointer to the owner of the interface * @param setOwner Pointer to the owner of the interface
* @param useThisQueue messageQueue to be used, can be set during * @param useThisQueue messageQueue to be used, can be set during
* initialize function as well. * initialize function as well.
*/ */
ActionHelper(HasActionsIF* setOwner, MessageQueueIF* useThisQueue); ActionHelper(HasActionsIF* setOwner, MessageQueueIF* useThisQueue);
virtual ~ActionHelper(); virtual ~ActionHelper();
/** /**
* Function to be called from the owner with a new command message * Function to be called from the owner with a new command message
* *
* If the message is a valid action message the helper will use the * If the message is a valid action message the helper will use the
* executeAction function from HasActionsIF. * executeAction function from HasActionsIF.
* If the message is invalid or the callback fails a message reply will be * If the message is invalid or the callback fails a message reply will be
* send to the sender of the message automatically. * send to the sender of the message automatically.
* *
* @param command Pointer to a command message received by the owner * @param command Pointer to a command message received by the owner
* @return HasReturnvaluesIF::RETURN_OK if the message is a action message, * @return HasReturnvaluesIF::RETURN_OK if the message is a action message,
* CommandMessage::UNKNOW_COMMAND if this message ID is unkown * CommandMessage::UNKNOW_COMMAND if this message ID is unkown
*/ */
ReturnValue_t handleActionMessage(CommandMessage* command); ReturnValue_t handleActionMessage(CommandMessage* command);
/** /**
* Helper initialize function. Must be called before use of any other * Helper initialize function. Must be called before use of any other
* helper function * helper function
* @param queueToUse_ Pointer to the messageQueue to be used, optional * @param queueToUse_ Pointer to the messageQueue to be used, optional
* if queue was set in constructor * if queue was set in constructor
* @return Returns RETURN_OK if successful * @return Returns RETURN_OK if successful
*/ */
ReturnValue_t initialize(MessageQueueIF* queueToUse_ = nullptr); ReturnValue_t initialize(MessageQueueIF* queueToUse_ = nullptr);
/** /**
* Function to be called from the owner to send a step message. * Function to be called from the owner to send a step message.
* Success or failure will be determined by the result value. * Success or failure will be determined by the result value.
* *
* @param step Number of steps already done * @param step Number of steps already done
* @param reportTo The messageQueueId to report the step message to * @param reportTo The messageQueueId to report the step 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 step(uint8_t step, MessageQueueId_t reportTo, void step(uint8_t step, MessageQueueId_t reportTo,
ActionId_t commandId, ActionId_t commandId,
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 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(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.
* Takes a SerializeIF* pointer and serializes it into the IPC store. * Takes a SerializeIF* pointer and serializes it into the IPC store.
* @param reportTo MessageQueueId_t to report the action completion * @param reportTo MessageQueueId_t to report the action completion
* message to * message to
* @param replyId ID of the executed command * @param replyId ID of the executed command
* @param data Pointer to the data * @param data Pointer to the data
* @return Returns RETURN_OK if successful, otherwise failure code * @return Returns RETURN_OK if successful, otherwise failure code
*/ */
ReturnValue_t reportData(MessageQueueId_t reportTo, ActionId_t replyId, ReturnValue_t reportData(MessageQueueId_t reportTo, ActionId_t replyId,
SerializeIF* data, bool hideSender = false); SerializeIF* data, bool hideSender = false);
/** /**
* 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.
* Takes the raw data and writes it into the IPC store. * Takes the raw data and writes it into the IPC store.
@ -91,35 +91,35 @@ public:
*/ */
ReturnValue_t reportData(MessageQueueId_t reportTo, ActionId_t replyId, ReturnValue_t reportData(MessageQueueId_t reportTo, ActionId_t replyId,
const uint8_t* data, size_t dataSize, bool hideSender = false); const uint8_t* data, size_t dataSize, bool hideSender = false);
/** /**
* Function to setup the MessageQueueIF* of the helper. Can be used to * Function to setup the MessageQueueIF* of the helper. Can be used to
* set the MessageQueueIF* if message queue is unavailable at construction * set the MessageQueueIF* if message queue is unavailable at construction
* and initialize but must be setup before first call of other functions. * and initialize but must be setup before first call of other functions.
* @param queue Queue to be used by the helper * @param queue Queue to be used by the helper
*/ */
void setQueueToUse(MessageQueueIF *queue); void setQueueToUse(MessageQueueIF *queue);
protected: protected:
//!< Increase of value of this per step //! Increase of value of this per step
static const uint8_t STEP_OFFSET = 1; static const uint8_t STEP_OFFSET = 1;
HasActionsIF* owner;//!< Pointer to the owner HasActionsIF* owner;//!< Pointer to the owner
//! Queue to be used as response sender, has to be set in ctor or with //! Queue to be used as response sender, has to be set in ctor or with
//! setQueueToUse //! setQueueToUse
MessageQueueIF* queueToUse; MessageQueueIF* queueToUse;
//! Pointer to an IPC Store, initialized during construction or //! Pointer to an IPC Store, initialized during construction or
StorageManagerIF* ipcStore = nullptr; StorageManagerIF* ipcStore = nullptr;
/** /**
* Internal function called by handleActionMessage * Internal function called by handleActionMessage
* @param commandedBy MessageQueueID of Commander * @param commandedBy MessageQueueID of Commander
* @param actionId ID of action to be done * @param actionId ID of action to be done
* @param dataAddress Address of additional data in IPC Store * @param dataAddress Address of additional data in IPC Store
*/ */
virtual void prepareExecution(MessageQueueId_t commandedBy, virtual void prepareExecution(MessageQueueId_t commandedBy,
ActionId_t actionId, store_address_t dataAddress); ActionId_t actionId, store_address_t dataAddress);
/** /**
* @brief Default implementation is empty. * @brief Default implementation is empty.
*/ */
virtual void resetHelper(); virtual void resetHelper();
}; };
#endif /* FSFW_ACTION_ACTIONHELPER_H_ */ #endif /* FSFW_ACTION_ACTIONHELPER_H_ */

View File

@ -11,71 +11,71 @@ ActionMessage::~ActionMessage() {
} }
void ActionMessage::setCommand(CommandMessage* message, ActionId_t fid, void ActionMessage::setCommand(CommandMessage* message, ActionId_t fid,
store_address_t parameters) { store_address_t parameters) {
message->setCommand(EXECUTE_ACTION); message->setCommand(EXECUTE_ACTION);
message->setParameter(fid); message->setParameter(fid);
message->setParameter2(parameters.raw); message->setParameter2(parameters.raw);
} }
ActionId_t ActionMessage::getActionId(const CommandMessage* message) { ActionId_t ActionMessage::getActionId(const CommandMessage* message) {
return ActionId_t(message->getParameter()); return ActionId_t(message->getParameter());
} }
store_address_t ActionMessage::getStoreId(const CommandMessage* message) { store_address_t ActionMessage::getStoreId(const CommandMessage* message) {
store_address_t temp; store_address_t temp;
temp.raw = message->getParameter2(); temp.raw = message->getParameter2();
return temp; return temp;
} }
void ActionMessage::setStepReply(CommandMessage* message, ActionId_t fid, uint8_t step, void ActionMessage::setStepReply(CommandMessage* message, ActionId_t fid, uint8_t step,
ReturnValue_t result) { ReturnValue_t result) {
if (result == HasReturnvaluesIF::RETURN_OK) { if (result == HasReturnvaluesIF::RETURN_OK) {
message->setCommand(STEP_SUCCESS); message->setCommand(STEP_SUCCESS);
} else { } else {
message->setCommand(STEP_FAILED); message->setCommand(STEP_FAILED);
} }
message->setParameter(fid); message->setParameter(fid);
message->setParameter2((step << 16) + result); message->setParameter2((step << 16) + result);
} }
uint8_t ActionMessage::getStep(const CommandMessage* message) { uint8_t ActionMessage::getStep(const CommandMessage* message) {
return uint8_t((message->getParameter2() >> 16) & 0xFF); return uint8_t((message->getParameter2() >> 16) & 0xFF);
} }
ReturnValue_t ActionMessage::getReturnCode(const CommandMessage* message) { ReturnValue_t ActionMessage::getReturnCode(const CommandMessage* message) {
return message->getParameter2() & 0xFFFF; return message->getParameter2() & 0xFFFF;
} }
void ActionMessage::setDataReply(CommandMessage* message, ActionId_t actionId, void ActionMessage::setDataReply(CommandMessage* message, ActionId_t actionId,
store_address_t data) { store_address_t data) {
message->setCommand(DATA_REPLY); message->setCommand(DATA_REPLY);
message->setParameter(actionId); message->setParameter(actionId);
message->setParameter2(data.raw); message->setParameter2(data.raw);
} }
void ActionMessage::setCompletionReply(CommandMessage* message, void ActionMessage::setCompletionReply(CommandMessage* message,
ActionId_t fid, ReturnValue_t result) { ActionId_t fid, ReturnValue_t result) {
if (result == HasReturnvaluesIF::RETURN_OK or result == HasActionsIF::EXECUTION_FINISHED) { if (result == HasReturnvaluesIF::RETURN_OK or result == HasActionsIF::EXECUTION_FINISHED) {
message->setCommand(COMPLETION_SUCCESS); message->setCommand(COMPLETION_SUCCESS);
} else { } else {
message->setCommand(COMPLETION_FAILED); message->setCommand(COMPLETION_FAILED);
} }
message->setParameter(fid); message->setParameter(fid);
message->setParameter2(result); message->setParameter2(result);
} }
void ActionMessage::clear(CommandMessage* message) { void ActionMessage::clear(CommandMessage* message) {
switch(message->getCommand()) { switch(message->getCommand()) {
case EXECUTE_ACTION: case EXECUTE_ACTION:
case DATA_REPLY: { case DATA_REPLY: {
StorageManagerIF *ipcStore = objectManager->get<StorageManagerIF>( StorageManagerIF *ipcStore = objectManager->get<StorageManagerIF>(
objects::IPC_STORE); objects::IPC_STORE);
if (ipcStore != NULL) { if (ipcStore != NULL) {
ipcStore->deleteData(getStoreId(message)); ipcStore->deleteData(getStoreId(message));
} }
break; break;
} }
default: default:
break; break;
} }
} }

View File

@ -15,29 +15,29 @@ using ActionId_t = uint32_t;
*/ */
class ActionMessage { class ActionMessage {
private: private:
ActionMessage(); ActionMessage();
public: public:
static const uint8_t MESSAGE_ID = messagetypes::ACTION; static const uint8_t MESSAGE_ID = messagetypes::ACTION;
static const Command_t EXECUTE_ACTION = MAKE_COMMAND_ID(1); static const Command_t EXECUTE_ACTION = MAKE_COMMAND_ID(1);
static const Command_t STEP_SUCCESS = MAKE_COMMAND_ID(2); static const Command_t STEP_SUCCESS = MAKE_COMMAND_ID(2);
static const Command_t STEP_FAILED = MAKE_COMMAND_ID(3); static const Command_t STEP_FAILED = MAKE_COMMAND_ID(3);
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 );
static ReturnValue_t getReturnCode(const CommandMessage* message ); static ReturnValue_t getReturnCode(const CommandMessage* message );
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); ReturnValue_t result = HasReturnvaluesIF::RETURN_OK);
static void clear(CommandMessage* message); static void clear(CommandMessage* message);
}; };
#endif /* FSFW_ACTION_ACTIONMESSAGE_H_ */ #endif /* FSFW_ACTION_ACTIONMESSAGE_H_ */

View File

@ -5,123 +5,123 @@
#include "../objectmanager/ObjectManagerIF.h" #include "../objectmanager/ObjectManagerIF.h"
CommandActionHelper::CommandActionHelper(CommandsActionsIF *setOwner) : CommandActionHelper::CommandActionHelper(CommandsActionsIF *setOwner) :
owner(setOwner), queueToUse(NULL), ipcStore( owner(setOwner), queueToUse(NULL), ipcStore(
NULL), commandCount(0), lastTarget(0) { NULL), commandCount(0), lastTarget(0) {
} }
CommandActionHelper::~CommandActionHelper() { CommandActionHelper::~CommandActionHelper() {
} }
ReturnValue_t CommandActionHelper::commandAction(object_id_t commandTo, ReturnValue_t CommandActionHelper::commandAction(object_id_t commandTo,
ActionId_t actionId, SerializeIF *data) { ActionId_t actionId, SerializeIF *data) {
HasActionsIF *receiver = objectManager->get<HasActionsIF>(commandTo); HasActionsIF *receiver = objectManager->get<HasActionsIF>(commandTo);
if (receiver == NULL) { if (receiver == NULL) {
return CommandsActionsIF::OBJECT_HAS_NO_FUNCTIONS; return CommandsActionsIF::OBJECT_HAS_NO_FUNCTIONS;
} }
store_address_t storeId; store_address_t storeId;
uint8_t *storePointer; uint8_t *storePointer;
size_t maxSize = data->getSerializedSize(); size_t maxSize = data->getSerializedSize();
ReturnValue_t result = ipcStore->getFreeElement(&storeId, maxSize, ReturnValue_t result = ipcStore->getFreeElement(&storeId, maxSize,
&storePointer); &storePointer);
if (result != HasReturnvaluesIF::RETURN_OK) { if (result != HasReturnvaluesIF::RETURN_OK) {
return result; return result;
} }
size_t size = 0; size_t size = 0;
result = data->serialize(&storePointer, &size, maxSize, result = data->serialize(&storePointer, &size, maxSize,
SerializeIF::Endianness::BIG); SerializeIF::Endianness::BIG);
if (result != HasReturnvaluesIF::RETURN_OK) { if (result != HasReturnvaluesIF::RETURN_OK) {
return result; return result;
} }
return sendCommand(receiver->getCommandQueue(), actionId, storeId); return sendCommand(receiver->getCommandQueue(), actionId, storeId);
} }
ReturnValue_t CommandActionHelper::commandAction(object_id_t commandTo, ReturnValue_t CommandActionHelper::commandAction(object_id_t commandTo,
ActionId_t actionId, const uint8_t *data, uint32_t size) { ActionId_t actionId, const uint8_t *data, uint32_t size) {
// if (commandCount != 0) { // if (commandCount != 0) {
// return CommandsFunctionsIF::ALREADY_COMMANDING; // return CommandsFunctionsIF::ALREADY_COMMANDING;
// } // }
HasActionsIF *receiver = objectManager->get<HasActionsIF>(commandTo); HasActionsIF *receiver = objectManager->get<HasActionsIF>(commandTo);
if (receiver == NULL) { if (receiver == NULL) {
return CommandsActionsIF::OBJECT_HAS_NO_FUNCTIONS; return CommandsActionsIF::OBJECT_HAS_NO_FUNCTIONS;
} }
store_address_t storeId; store_address_t storeId;
ReturnValue_t result = ipcStore->addData(&storeId, data, size); ReturnValue_t result = ipcStore->addData(&storeId, data, size);
if (result != HasReturnvaluesIF::RETURN_OK) { if (result != HasReturnvaluesIF::RETURN_OK) {
return result; return result;
} }
return sendCommand(receiver->getCommandQueue(), actionId, storeId); return sendCommand(receiver->getCommandQueue(), actionId, storeId);
} }
ReturnValue_t CommandActionHelper::sendCommand(MessageQueueId_t queueId, ReturnValue_t CommandActionHelper::sendCommand(MessageQueueId_t queueId,
ActionId_t actionId, store_address_t storeId) { ActionId_t actionId, store_address_t storeId) {
CommandMessage command; CommandMessage command;
ActionMessage::setCommand(&command, actionId, storeId); ActionMessage::setCommand(&command, actionId, storeId);
ReturnValue_t result = queueToUse->sendMessage(queueId, &command); ReturnValue_t result = queueToUse->sendMessage(queueId, &command);
if (result != HasReturnvaluesIF::RETURN_OK) { if (result != HasReturnvaluesIF::RETURN_OK) {
ipcStore->deleteData(storeId); ipcStore->deleteData(storeId);
} }
lastTarget = queueId; lastTarget = queueId;
commandCount++; commandCount++;
return result; return result;
} }
ReturnValue_t CommandActionHelper::initialize() { ReturnValue_t CommandActionHelper::initialize() {
ipcStore = objectManager->get<StorageManagerIF>(objects::IPC_STORE); ipcStore = objectManager->get<StorageManagerIF>(objects::IPC_STORE);
if (ipcStore == NULL) { if (ipcStore == NULL) {
return HasReturnvaluesIF::RETURN_FAILED; return HasReturnvaluesIF::RETURN_FAILED;
} }
queueToUse = owner->getCommandQueuePtr(); queueToUse = owner->getCommandQueuePtr();
if (queueToUse == NULL) { if (queueToUse == NULL) {
return HasReturnvaluesIF::RETURN_FAILED; return HasReturnvaluesIF::RETURN_FAILED;
} }
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
} }
ReturnValue_t CommandActionHelper::handleReply(CommandMessage *reply) { ReturnValue_t CommandActionHelper::handleReply(CommandMessage *reply) {
if (reply->getSender() != lastTarget) { if (reply->getSender() != lastTarget) {
return HasReturnvaluesIF::RETURN_FAILED; return HasReturnvaluesIF::RETURN_FAILED;
} }
switch (reply->getCommand()) { switch (reply->getCommand()) {
case ActionMessage::COMPLETION_SUCCESS: case ActionMessage::COMPLETION_SUCCESS:
commandCount--; commandCount--;
owner->completionSuccessfulReceived(ActionMessage::getActionId(reply)); owner->completionSuccessfulReceived(ActionMessage::getActionId(reply));
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
case ActionMessage::COMPLETION_FAILED: case ActionMessage::COMPLETION_FAILED:
commandCount--; commandCount--;
owner->completionFailedReceived(ActionMessage::getActionId(reply), owner->completionFailedReceived(ActionMessage::getActionId(reply),
ActionMessage::getReturnCode(reply)); ActionMessage::getReturnCode(reply));
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
case ActionMessage::STEP_SUCCESS: case ActionMessage::STEP_SUCCESS:
owner->stepSuccessfulReceived(ActionMessage::getActionId(reply), owner->stepSuccessfulReceived(ActionMessage::getActionId(reply),
ActionMessage::getStep(reply)); ActionMessage::getStep(reply));
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
case ActionMessage::STEP_FAILED: case ActionMessage::STEP_FAILED:
commandCount--; commandCount--;
owner->stepFailedReceived(ActionMessage::getActionId(reply), owner->stepFailedReceived(ActionMessage::getActionId(reply),
ActionMessage::getStep(reply), ActionMessage::getStep(reply),
ActionMessage::getReturnCode(reply)); ActionMessage::getReturnCode(reply));
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
case ActionMessage::DATA_REPLY: case ActionMessage::DATA_REPLY:
extractDataForOwner(ActionMessage::getActionId(reply), extractDataForOwner(ActionMessage::getActionId(reply),
ActionMessage::getStoreId(reply)); ActionMessage::getStoreId(reply));
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
default: default:
return HasReturnvaluesIF::RETURN_FAILED; return HasReturnvaluesIF::RETURN_FAILED;
} }
} }
uint8_t CommandActionHelper::getCommandCount() const { uint8_t CommandActionHelper::getCommandCount() const {
return commandCount; return commandCount;
} }
void CommandActionHelper::extractDataForOwner(ActionId_t actionId, store_address_t storeId) { void CommandActionHelper::extractDataForOwner(ActionId_t actionId, store_address_t storeId) {
const uint8_t * data = NULL; const uint8_t * data = NULL;
size_t size = 0; size_t size = 0;
ReturnValue_t result = ipcStore->getData(storeId, &data, &size); ReturnValue_t result = ipcStore->getData(storeId, &data, &size);
if (result != HasReturnvaluesIF::RETURN_OK) { if (result != HasReturnvaluesIF::RETURN_OK) {
return; return;
} }
owner->dataReceived(actionId, data, size); owner->dataReceived(actionId, data, size);
ipcStore->deleteData(storeId); ipcStore->deleteData(storeId);
} }

View File

@ -11,26 +11,26 @@
class CommandsActionsIF; class CommandsActionsIF;
class CommandActionHelper { class CommandActionHelper {
friend class CommandsActionsIF; friend class CommandsActionsIF;
public: public:
CommandActionHelper(CommandsActionsIF* owner); CommandActionHelper(CommandsActionsIF* owner);
virtual ~CommandActionHelper(); virtual ~CommandActionHelper();
ReturnValue_t commandAction(object_id_t commandTo, ReturnValue_t commandAction(object_id_t commandTo,
ActionId_t actionId, const uint8_t* data, uint32_t size); ActionId_t actionId, const uint8_t* data, uint32_t size);
ReturnValue_t commandAction(object_id_t commandTo, ReturnValue_t commandAction(object_id_t commandTo,
ActionId_t actionId, SerializeIF* data); ActionId_t actionId, SerializeIF* data);
ReturnValue_t initialize(); ReturnValue_t initialize();
ReturnValue_t handleReply(CommandMessage* reply); ReturnValue_t handleReply(CommandMessage* reply);
uint8_t getCommandCount() const; uint8_t getCommandCount() const;
private: private:
CommandsActionsIF* owner; CommandsActionsIF* owner;
MessageQueueIF* queueToUse; MessageQueueIF* queueToUse;
StorageManagerIF* ipcStore; StorageManagerIF* ipcStore;
uint8_t commandCount; uint8_t commandCount;
MessageQueueId_t lastTarget; MessageQueueId_t lastTarget;
void extractDataForOwner(ActionId_t actionId, store_address_t storeId); void extractDataForOwner(ActionId_t actionId, store_address_t storeId);
ReturnValue_t sendCommand(MessageQueueId_t queueId, ActionId_t actionId, ReturnValue_t sendCommand(MessageQueueId_t queueId, ActionId_t actionId,
store_address_t storeId); store_address_t storeId);
}; };
#endif /* COMMANDACTIONHELPER_H_ */ #endif /* COMMANDACTIONHELPER_H_ */

View File

@ -15,22 +15,22 @@
* - replyReceived(id, step, cause) (if cause == OK, it's a success). * - replyReceived(id, step, cause) (if cause == OK, it's a success).
*/ */
class CommandsActionsIF { class CommandsActionsIF {
friend class CommandActionHelper; friend class CommandActionHelper;
public: public:
static const uint8_t INTERFACE_ID = CLASS_ID::COMMANDS_ACTIONS_IF; static const uint8_t INTERFACE_ID = CLASS_ID::COMMANDS_ACTIONS_IF;
static const ReturnValue_t OBJECT_HAS_NO_FUNCTIONS = MAKE_RETURN_CODE(1); static const ReturnValue_t OBJECT_HAS_NO_FUNCTIONS = MAKE_RETURN_CODE(1);
static const ReturnValue_t ALREADY_COMMANDING = MAKE_RETURN_CODE(2); static const ReturnValue_t ALREADY_COMMANDING = MAKE_RETURN_CODE(2);
virtual ~CommandsActionsIF() {} virtual ~CommandsActionsIF() {}
virtual MessageQueueIF* getCommandQueuePtr() = 0; virtual MessageQueueIF* getCommandQueuePtr() = 0;
protected: protected:
virtual void stepSuccessfulReceived(ActionId_t actionId, uint8_t step) = 0; virtual void stepSuccessfulReceived(ActionId_t actionId, uint8_t step) = 0;
virtual void stepFailedReceived(ActionId_t actionId, uint8_t step, virtual void stepFailedReceived(ActionId_t actionId, uint8_t step,
ReturnValue_t returnCode) = 0; ReturnValue_t returnCode) = 0;
virtual void dataReceived(ActionId_t actionId, const uint8_t* data, virtual void dataReceived(ActionId_t actionId, const uint8_t* data,
uint32_t size) = 0; uint32_t size) = 0;
virtual void completionSuccessfulReceived(ActionId_t actionId) = 0; virtual void completionSuccessfulReceived(ActionId_t actionId) = 0;
virtual void completionFailedReceived(ActionId_t actionId, virtual void completionFailedReceived(ActionId_t actionId,
ReturnValue_t returnCode) = 0; ReturnValue_t returnCode) = 0;
}; };

View File

@ -35,28 +35,28 @@
*/ */
class HasActionsIF { class HasActionsIF {
public: public:
static const uint8_t INTERFACE_ID = CLASS_ID::HAS_ACTIONS_IF; static const uint8_t INTERFACE_ID = CLASS_ID::HAS_ACTIONS_IF;
static const ReturnValue_t IS_BUSY = MAKE_RETURN_CODE(1); static const ReturnValue_t IS_BUSY = MAKE_RETURN_CODE(1);
static const ReturnValue_t INVALID_PARAMETERS = MAKE_RETURN_CODE(2); static const ReturnValue_t INVALID_PARAMETERS = MAKE_RETURN_CODE(2);
static const ReturnValue_t EXECUTION_FINISHED = MAKE_RETURN_CODE(3); static const ReturnValue_t EXECUTION_FINISHED = MAKE_RETURN_CODE(3);
static const ReturnValue_t INVALID_ACTION_ID = MAKE_RETURN_CODE(4); static const ReturnValue_t INVALID_ACTION_ID = MAKE_RETURN_CODE(4);
virtual ~HasActionsIF() { } virtual ~HasActionsIF() { }
/** /**
* Function to get the MessageQueueId_t of the implementing object * Function to get the MessageQueueId_t of the implementing object
* @return MessageQueueId_t of the object * @return MessageQueueId_t of the object
*/ */
virtual MessageQueueId_t getCommandQueue() const = 0; virtual MessageQueueId_t getCommandQueue() const = 0;
/** /**
* Execute or initialize the execution of a certain function. * Execute or initialize the execution of a certain function.
* The ActionHelpers will execute this function and behave differently * The ActionHelpers will execute this function and behave differently
* depending on the returnvalue. * depending on the returnvalue.
* *
* @return * @return
* -@c EXECUTION_FINISHED Finish reply will be generated * -@c EXECUTION_FINISHED Finish reply will be generated
* -@c Not RETURN_OK Step failure reply will be generated * -@c Not RETURN_OK Step failure reply will be generated
*/ */
virtual ReturnValue_t executeAction(ActionId_t actionId, virtual ReturnValue_t executeAction(ActionId_t actionId,
MessageQueueId_t commandedBy, const uint8_t* data, size_t size) = 0; MessageQueueId_t commandedBy, const uint8_t* data, size_t size) = 0;
}; };

View File

@ -2,74 +2,74 @@
#include "SimpleActionHelper.h" #include "SimpleActionHelper.h"
SimpleActionHelper::SimpleActionHelper(HasActionsIF* setOwner, SimpleActionHelper::SimpleActionHelper(HasActionsIF* setOwner,
MessageQueueIF* useThisQueue) : MessageQueueIF* useThisQueue) :
ActionHelper(setOwner, useThisQueue), isExecuting(false) { ActionHelper(setOwner, useThisQueue), isExecuting(false) {
} }
SimpleActionHelper::~SimpleActionHelper() { SimpleActionHelper::~SimpleActionHelper() {
} }
void SimpleActionHelper::step(ReturnValue_t result) { void SimpleActionHelper::step(ReturnValue_t result) {
// STEP_OFFESET is subtracted to compensate for adding offset in base // STEP_OFFESET is subtracted to compensate for adding offset in base
// method, which is not necessary here. // method, which is not necessary here.
ActionHelper::step(stepCount - STEP_OFFSET, lastCommander, lastAction, ActionHelper::step(stepCount - STEP_OFFSET, lastCommander, lastAction,
result); result);
if (result != HasReturnvaluesIF::RETURN_OK) { if (result != HasReturnvaluesIF::RETURN_OK) {
resetHelper(); resetHelper();
} }
} }
void SimpleActionHelper::finish(ReturnValue_t result) { void SimpleActionHelper::finish(ReturnValue_t result) {
ActionHelper::finish(lastCommander, lastAction, result); ActionHelper::finish(lastCommander, lastAction, result);
resetHelper(); resetHelper();
} }
ReturnValue_t SimpleActionHelper::reportData(SerializeIF* data) { ReturnValue_t SimpleActionHelper::reportData(SerializeIF* data) {
return ActionHelper::reportData(lastCommander, lastAction, data); return ActionHelper::reportData(lastCommander, lastAction, data);
} }
void SimpleActionHelper::resetHelper() { void SimpleActionHelper::resetHelper() {
stepCount = 0; stepCount = 0;
isExecuting = false; isExecuting = false;
lastAction = 0; lastAction = 0;
lastCommander = 0; lastCommander = 0;
} }
void SimpleActionHelper::prepareExecution(MessageQueueId_t commandedBy, void SimpleActionHelper::prepareExecution(MessageQueueId_t commandedBy,
ActionId_t actionId, store_address_t dataAddress) { ActionId_t actionId, store_address_t dataAddress) {
CommandMessage reply; CommandMessage reply;
if (isExecuting) { if (isExecuting) {
ipcStore->deleteData(dataAddress); ipcStore->deleteData(dataAddress);
ActionMessage::setStepReply(&reply, actionId, 0, ActionMessage::setStepReply(&reply, actionId, 0,
HasActionsIF::IS_BUSY); HasActionsIF::IS_BUSY);
queueToUse->sendMessage(commandedBy, &reply); queueToUse->sendMessage(commandedBy, &reply);
} }
const uint8_t* dataPtr = NULL; const uint8_t* dataPtr = NULL;
size_t size = 0; size_t size = 0;
ReturnValue_t result = ipcStore->getData(dataAddress, &dataPtr, &size); ReturnValue_t result = ipcStore->getData(dataAddress, &dataPtr, &size);
if (result != HasReturnvaluesIF::RETURN_OK) { if (result != HasReturnvaluesIF::RETURN_OK) {
ActionMessage::setStepReply(&reply, actionId, 0, result); ActionMessage::setStepReply(&reply, actionId, 0, result);
queueToUse->sendMessage(commandedBy, &reply); queueToUse->sendMessage(commandedBy, &reply);
return; return;
} }
lastCommander = commandedBy; lastCommander = commandedBy;
lastAction = actionId; lastAction = actionId;
result = owner->executeAction(actionId, commandedBy, dataPtr, size); result = owner->executeAction(actionId, commandedBy, dataPtr, size);
ipcStore->deleteData(dataAddress); ipcStore->deleteData(dataAddress);
switch (result) { switch (result) {
case HasReturnvaluesIF::RETURN_OK: case HasReturnvaluesIF::RETURN_OK:
isExecuting = true; isExecuting = true;
stepCount++; stepCount++;
break; break;
case HasActionsIF::EXECUTION_FINISHED: case HasActionsIF::EXECUTION_FINISHED:
ActionMessage::setCompletionReply(&reply, actionId, ActionMessage::setCompletionReply(&reply, actionId,
HasReturnvaluesIF::RETURN_OK); HasReturnvaluesIF::RETURN_OK);
queueToUse->sendMessage(commandedBy, &reply); queueToUse->sendMessage(commandedBy, &reply);
break; break;
default: default:
ActionMessage::setStepReply(&reply, actionId, 0, result); ActionMessage::setStepReply(&reply, actionId, 0, result);
queueToUse->sendMessage(commandedBy, &reply); queueToUse->sendMessage(commandedBy, &reply);
break; break;
} }
} }

View File

@ -4,27 +4,27 @@
#include "ActionHelper.h" #include "ActionHelper.h"
/** /**
* @brief This is an action helper which is only able to service one action * @brief This is an action helper which is only able to service one action
* at a time but remembers last commander and last action which * at a time but remembers last commander and last action which
* simplifies usage * simplifies usage
*/ */
class SimpleActionHelper: public ActionHelper { class SimpleActionHelper: public ActionHelper {
public: public:
SimpleActionHelper(HasActionsIF* setOwner, MessageQueueIF* useThisQueue); SimpleActionHelper(HasActionsIF* setOwner, MessageQueueIF* useThisQueue);
virtual ~SimpleActionHelper(); virtual ~SimpleActionHelper();
void step(ReturnValue_t result = HasReturnvaluesIF::RETURN_OK); void step(ReturnValue_t result = HasReturnvaluesIF::RETURN_OK);
void finish(ReturnValue_t result = HasReturnvaluesIF::RETURN_OK); void finish(ReturnValue_t result = HasReturnvaluesIF::RETURN_OK);
ReturnValue_t reportData(SerializeIF* data); ReturnValue_t reportData(SerializeIF* data);
protected: protected:
void prepareExecution(MessageQueueId_t commandedBy, ActionId_t actionId, void prepareExecution(MessageQueueId_t commandedBy, ActionId_t actionId,
store_address_t dataAddress); store_address_t dataAddress);
virtual void resetHelper(); virtual void resetHelper();
private: private:
bool isExecuting; bool isExecuting;
MessageQueueId_t lastCommander = MessageQueueIF::NO_QUEUE; MessageQueueId_t lastCommander = MessageQueueIF::NO_QUEUE;
ActionId_t lastAction = 0; ActionId_t lastAction = 0;
uint8_t stepCount = 0; uint8_t stepCount = 0;
}; };
#endif /* SIMPLEACTIONHELPER_H_ */ #endif /* SIMPLEACTIONHELPER_H_ */

View File

@ -6,7 +6,7 @@
#include "../serialize/SerializeIF.h" #include "../serialize/SerializeIF.h"
/** /**
* @brief A List that stores its values in an array. * @brief A List that stores its values in an array.
* @details * @details
* The underlying storage is an array that can be allocated by the class * The underlying storage is an array that can be allocated by the class
* itself or supplied via ctor. * itself or supplied via ctor.
@ -15,237 +15,237 @@
*/ */
template<typename T, typename count_t = uint8_t> template<typename T, typename count_t = uint8_t>
class ArrayList { class ArrayList {
template<typename U, typename count> friend class SerialArrayListAdapter; template<typename U, typename count> friend class SerialArrayListAdapter;
public: public:
static const uint8_t INTERFACE_ID = CLASS_ID::ARRAY_LIST; static const uint8_t INTERFACE_ID = CLASS_ID::ARRAY_LIST;
static const ReturnValue_t FULL = MAKE_RETURN_CODE(0x01); static const ReturnValue_t FULL = MAKE_RETURN_CODE(0x01);
/** /**
* This is the allocating constructor. * This is the allocating constructor.
* It allocates an array of the specified size. * It allocates an array of the specified size.
* @param maxSize * @param maxSize
*/ */
ArrayList(count_t maxSize) : ArrayList(count_t maxSize) :
size(0), maxSize_(maxSize), allocated(true) { size(0), maxSize_(maxSize), allocated(true) {
entries = new T[maxSize]; entries = new T[maxSize];
} }
/** /**
* This is the non-allocating constructor * This is the non-allocating constructor
* *
* It expects a pointer to an array of a certain size and initializes * It expects a pointer to an array of a certain size and initializes
* itself to it. * itself to it.
* *
* @param storage the array to use as backend * @param storage the array to use as backend
* @param maxSize size of storage * @param maxSize size of storage
* @param size size of data already present in storage * @param size size of data already present in storage
*/ */
ArrayList(T *storage, count_t maxSize, count_t size = 0) : ArrayList(T *storage, count_t maxSize, count_t size = 0) :
size(size), entries(storage), maxSize_(maxSize), allocated(false) { size(size), entries(storage), maxSize_(maxSize), allocated(false) {
} }
/** /**
* Copying is forbiden by declaring copy ctor and copy assignment deleted * Copying is forbiden by declaring copy ctor and copy assignment deleted
* It is too ambigous in this case. * It is too ambigous in this case.
* (Allocate a new backend? Use the same? What to do in an modifying call?) * (Allocate a new backend? Use the same? What to do in an modifying call?)
*/ */
ArrayList(const ArrayList& other) = delete; ArrayList(const ArrayList& other) = delete;
const ArrayList& operator=(const ArrayList& other) = delete; const ArrayList& operator=(const ArrayList& other) = delete;
/** /**
* Number of Elements stored in this List * Number of Elements stored in this List
*/ */
count_t size; count_t size;
/** /**
* Destructor, if the allocating constructor was used, it deletes the array. * Destructor, if the allocating constructor was used, it deletes the array.
*/ */
virtual ~ArrayList() { virtual ~ArrayList() {
if (allocated) { if (allocated) {
delete[] entries; delete[] entries;
} }
} }
/** /**
* An Iterator to go trough an ArrayList * An Iterator to go trough an ArrayList
* *
* It stores a pointer to an element and increments the * It stores a pointer to an element and increments the
* pointer when incremented itself. * pointer when incremented itself.
*/ */
class Iterator { class Iterator {
public: public:
/** /**
* Empty ctor, points to NULL * Empty ctor, points to NULL
*/ */
Iterator(): value(0) {} Iterator(): value(0) {}
/** /**
* Initializes the Iterator to point to an element * Initializes the Iterator to point to an element
* *
* @param initialize * @param initialize
*/ */
Iterator(T *initialize) { Iterator(T *initialize) {
value = initialize; value = initialize;
} }
/** /**
* The current element the iterator points to * The current element the iterator points to
*/ */
T *value; T *value;
Iterator& operator++() { Iterator& operator++() {
value++; value++;
return *this; return *this;
} }
Iterator operator++(int) { Iterator operator++(int) {
Iterator tmp(*this); Iterator tmp(*this);
operator++(); operator++();
return tmp; return tmp;
} }
Iterator& operator--() { Iterator& operator--() {
value--; value--;
return *this; return *this;
} }
Iterator operator--(int) { Iterator operator--(int) {
Iterator tmp(*this); Iterator tmp(*this);
operator--(); operator--();
return tmp; return tmp;
} }
T& operator*() { T& operator*() {
return *value; return *value;
} }
const T& operator*() const { const T& operator*() const {
return *value; return *value;
} }
T *operator->() { T *operator->() {
return value; return value;
} }
const T *operator->() const { const T *operator->() const {
return value; return value;
} }
}; };
friend bool operator==(const ArrayList::Iterator& lhs, friend bool operator==(const ArrayList::Iterator& lhs,
const ArrayList::Iterator& rhs) { const ArrayList::Iterator& rhs) {
return (lhs.value == rhs.value); return (lhs.value == rhs.value);
} }
friend bool operator!=(const ArrayList::Iterator& lhs, friend bool operator!=(const ArrayList::Iterator& lhs,
const ArrayList::Iterator& rhs) { const ArrayList::Iterator& rhs) {
return not (lhs.value == rhs.value); return not (lhs.value == rhs.value);
} }
/** /**
* Iterator pointing to the first stored elmement * Iterator pointing to the first stored elmement
* *
* @return Iterator to the first element * @return Iterator to the first element
*/ */
Iterator begin() const { Iterator begin() const {
return Iterator(&entries[0]); return Iterator(&entries[0]);
} }
/** /**
* returns an Iterator pointing to the element after the last stored entry * returns an Iterator pointing to the element after the last stored entry
* *
* @return Iterator to the element after the last entry * @return Iterator to the element after the last entry
*/ */
Iterator end() const { Iterator end() const {
return Iterator(&entries[size]); return Iterator(&entries[size]);
} }
T & operator[](count_t i) const { T & operator[](count_t i) const {
return entries[i]; return entries[i];
} }
/** /**
* The first element * The first element
* *
* @return pointer to the first stored element * @return pointer to the first stored element
*/ */
T *front() { T *front() {
return entries; return entries;
} }
/** /**
* The last element * The last element
* *
* does not return a valid pointer if called on an empty list. * does not return a valid pointer if called on an empty list.
* *
* @return pointer to the last stored element * @return pointer to the last stored element
*/ */
T *back() { T *back() {
return &entries[size - 1]; return &entries[size - 1];
//Alternative solution //Alternative solution
//return const_cast<T*>(static_cast<const T*>(*this).back()); //return const_cast<T*>(static_cast<const T*>(*this).back());
} }
const T* back() const{ const T* back() const{
return &entries[size-1]; return &entries[size-1];
} }
/** /**
* The maximum number of elements this List can contain * The maximum number of elements this List can contain
* *
* @return maximum number of elements * @return maximum number of elements
*/ */
size_t maxSize() const { size_t maxSize() const {
return this->maxSize_; return this->maxSize_;
} }
/** /**
* Insert a new element into the list. * Insert a new element into the list.
* *
* The new element is inserted after the last stored element. * The new element is inserted after the last stored element.
* *
* @param entry * @param entry
* @return * @return
* -@c FULL if the List is full * -@c FULL if the List is full
* -@c RETURN_OK else * -@c RETURN_OK else
*/ */
ReturnValue_t insert(T entry) { ReturnValue_t insert(T entry) {
if (size >= maxSize_) { if (size >= maxSize_) {
return FULL; return FULL;
} }
entries[size] = entry; entries[size] = entry;
++size; ++size;
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
} }
/** /**
* clear the List * clear the List
* *
* This does not actually clear all entries, it only sets the size to 0. * This does not actually clear all entries, it only sets the size to 0.
*/ */
void clear() { void clear() {
size = 0; size = 0;
} }
count_t remaining() { count_t remaining() {
return (maxSize_ - size); return (maxSize_ - size);
} }
protected: protected:
/** /**
* pointer to the array in which the entries are stored * pointer to the array in which the entries are stored
*/ */
T *entries; T *entries;
/** /**
* remembering the maximum size * remembering the maximum size
*/ */
size_t maxSize_; size_t maxSize_;
/** /**
* true if the array was allocated and needs to be deleted in the destructor. * true if the array was allocated and needs to be deleted in the destructor.
*/ */
bool allocated; bool allocated;
}; };

View File

@ -7,65 +7,65 @@
template<typename Tp> template<typename Tp>
class BinaryNode { class BinaryNode {
public: public:
BinaryNode(Tp* setValue) : BinaryNode(Tp* setValue) :
value(setValue), left(NULL), right(NULL), parent(NULL) { value(setValue), left(NULL), right(NULL), parent(NULL) {
} }
Tp *value; Tp *value;
BinaryNode* left; BinaryNode* left;
BinaryNode* right; BinaryNode* right;
BinaryNode* parent; BinaryNode* parent;
}; };
template<typename Tp> template<typename Tp>
class ExplicitNodeIterator { class ExplicitNodeIterator {
public: public:
typedef ExplicitNodeIterator<Tp> _Self; typedef ExplicitNodeIterator<Tp> _Self;
typedef BinaryNode<Tp> _Node; typedef BinaryNode<Tp> _Node;
typedef Tp value_type; typedef Tp value_type;
typedef Tp* pointer; typedef Tp* pointer;
typedef Tp& reference; typedef Tp& reference;
ExplicitNodeIterator() : ExplicitNodeIterator() :
element(NULL) { element(NULL) {
} }
ExplicitNodeIterator(_Node* node) : ExplicitNodeIterator(_Node* node) :
element(node) { element(node) {
} }
BinaryNode<Tp>* element; BinaryNode<Tp>* element;
_Self up() { _Self up() {
return _Self(element->parent); return _Self(element->parent);
} }
_Self left() { _Self left() {
if (element != NULL) { if (element != NULL) {
return _Self(element->left); return _Self(element->left);
} else { } else {
return _Self(NULL); return _Self(NULL);
} }
} }
_Self right() { _Self right() {
if (element != NULL) { if (element != NULL) {
return _Self(element->right); return _Self(element->right);
} else { } else {
return _Self(NULL); return _Self(NULL);
} }
} }
bool operator==(const _Self& __x) const { bool operator==(const _Self& __x) const {
return element == __x.element; return element == __x.element;
} }
bool operator!=(const _Self& __x) const { bool operator!=(const _Self& __x) const {
return element != __x.element; return element != __x.element;
} }
pointer pointer
operator->() const { operator->() const {
if (element != NULL) { if (element != NULL) {
return element->value; return element->value;
} else { } else {
return NULL; return NULL;
} }
} }
pointer operator*() const { pointer operator*() const {
return this->operator->(); return this->operator->();
} }
}; };
@ -75,77 +75,77 @@ public:
template<typename Tp> template<typename Tp>
class BinaryTree { class BinaryTree {
public: public:
typedef ExplicitNodeIterator<Tp> iterator; typedef ExplicitNodeIterator<Tp> iterator;
typedef BinaryNode<Tp> Node; typedef BinaryNode<Tp> Node;
typedef std::pair<iterator, iterator> children; typedef std::pair<iterator, iterator> children;
BinaryTree() : BinaryTree() :
rootNode(NULL) { rootNode(NULL) {
} }
BinaryTree(Node* rootNode) : BinaryTree(Node* rootNode) :
rootNode(rootNode) { rootNode(rootNode) {
} }
iterator begin() const { iterator begin() const {
return iterator(rootNode); return iterator(rootNode);
} }
static iterator end() { static iterator end() {
return iterator(NULL); return iterator(NULL);
} }
iterator insert(bool insertLeft, iterator parentNode, Node* newNode ) { iterator insert(bool insertLeft, iterator parentNode, Node* newNode ) {
newNode->parent = parentNode.element; newNode->parent = parentNode.element;
if (parentNode.element != NULL) { if (parentNode.element != NULL) {
if (insertLeft) { if (insertLeft) {
parentNode.element->left = newNode; parentNode.element->left = newNode;
} else { } else {
parentNode.element->right = newNode; parentNode.element->right = newNode;
} }
} else { } else {
//Insert first element. //Insert first element.
rootNode = newNode; rootNode = newNode;
} }
return iterator(newNode); return iterator(newNode);
} }
//No recursion to children. Needs to be done externally. //No recursion to children. Needs to be done externally.
children erase(iterator node) { children erase(iterator node) {
if (node.element == rootNode) { if (node.element == rootNode) {
//We're root node //We're root node
rootNode = NULL; rootNode = NULL;
} else { } else {
//Delete parent's reference //Delete parent's reference
if (node.up().left() == node) { if (node.up().left() == node) {
node.up().element->left = NULL; node.up().element->left = NULL;
} else { } else {
node.up().element->right = NULL; node.up().element->right = NULL;
} }
} }
return children(node.element->left, node.element->right); return children(node.element->left, node.element->right);
} }
static uint32_t countLeft(iterator start) { static uint32_t countLeft(iterator start) {
if (start == end()) { if (start == end()) {
return 0; return 0;
} }
//We also count the start node itself. //We also count the start node itself.
uint32_t count = 1; uint32_t count = 1;
while (start.left() != end()) { while (start.left() != end()) {
count++; count++;
start = start.left(); start = start.left();
} }
return count; return count;
} }
static uint32_t countRight(iterator start) { static uint32_t countRight(iterator start) {
if (start == end()) { if (start == end()) {
return 0; return 0;
} }
//We also count the start node itself. //We also count the start node itself.
uint32_t count = 1; uint32_t count = 1;
while (start.right() != end()) { while (start.right() != end()) {
count++; count++;
start = start.right(); start = start.right();
} }
return count; return count;
} }
protected: protected:
Node* rootNode; Node* rootNode;
}; };

View File

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

View File

@ -5,8 +5,8 @@
#include <array> #include <array>
/** /**
* @brief Simple First-In-First-Out data structure with size fixed at * @brief Simple First-In-First-Out data structure with size fixed at
* compile time * compile time
* @details * @details
* Performs no dynamic memory allocation. * Performs no dynamic memory allocation.
* The public interface of FIFOBase exposes the user interface for the FIFO. * The public interface of FIFOBase exposes the user interface for the FIFO.
@ -16,32 +16,32 @@
template<typename T, size_t capacity> template<typename T, size_t capacity>
class FIFO: public FIFOBase<T> { class FIFO: public FIFOBase<T> {
public: public:
FIFO(): FIFOBase<T>(nullptr, capacity) { FIFO(): FIFOBase<T>(nullptr, capacity) {
this->setContainer(fifoArray.data()); this->setContainer(fifoArray.data());
}; };
/** /**
* @brief Custom copy constructor to set pointer correctly. * @brief Custom copy constructor to set pointer correctly.
* @param other * @param other
*/ */
FIFO(const FIFO& other): FIFOBase<T>(other) { FIFO(const FIFO& other): FIFOBase<T>(other) {
this->fifoArray = other.fifoArray; this->fifoArray = other.fifoArray;
this->setContainer(fifoArray.data()); this->setContainer(fifoArray.data());
} }
/** /**
* @brief Custom assignment operator * @brief Custom assignment operator
* @param other * @param other
*/ */
FIFO& operator=(const FIFO& other){ FIFO& operator=(const FIFO& other){
FIFOBase<T>::operator=(other); FIFOBase<T>::operator=(other);
this->fifoArray = other.fifoArray; this->fifoArray = other.fifoArray;
this->setContainer(fifoArray.data()); this->setContainer(fifoArray.data());
return *this; return *this;
} }
private: private:
std::array<T, capacity> fifoArray; std::array<T, capacity> fifoArray;
}; };
#endif /* FSFW_CONTAINER_FIFO_H_ */ #endif /* FSFW_CONTAINER_FIFO_H_ */

View File

@ -8,70 +8,70 @@
template <typename T> template <typename T>
class FIFOBase { class FIFOBase {
public: public:
static const uint8_t INTERFACE_ID = CLASS_ID::FIFO_CLASS; static const uint8_t INTERFACE_ID = CLASS_ID::FIFO_CLASS;
static const ReturnValue_t FULL = MAKE_RETURN_CODE(1); static const ReturnValue_t FULL = MAKE_RETURN_CODE(1);
static const ReturnValue_t EMPTY = MAKE_RETURN_CODE(2); static const ReturnValue_t EMPTY = MAKE_RETURN_CODE(2);
/** Default ctor, takes pointer to first entry of underlying container /** Default ctor, takes pointer to first entry of underlying container
* and maximum capacity */ * and maximum capacity */
FIFOBase(T* values, const size_t maxCapacity); FIFOBase(T* values, const size_t maxCapacity);
/** /**
* Insert value into FIFO * Insert value into FIFO
* @param value * @param value
* @return RETURN_OK on success, FULL if full * @return RETURN_OK on success, FULL if full
*/ */
ReturnValue_t insert(T value); ReturnValue_t insert(T value);
/** /**
* Retrieve item from FIFO. This removes the item from the FIFO. * Retrieve item from FIFO. This removes the item from the FIFO.
* @param value Must point to a valid T * @param value Must point to a valid T
* @return RETURN_OK on success, EMPTY if empty and FAILED if nullptr check failed * @return RETURN_OK on success, EMPTY if empty and FAILED if nullptr check failed
*/ */
ReturnValue_t retrieve(T *value); ReturnValue_t retrieve(T *value);
/** /**
* Retrieve item from FIFO without removing it from FIFO. * Retrieve item from FIFO without removing it from FIFO.
* @param value Must point to a valid T * @param value Must point to a valid T
* @return RETURN_OK on success, EMPTY if empty and FAILED if nullptr check failed * @return RETURN_OK on success, EMPTY if empty and FAILED if nullptr check failed
*/ */
ReturnValue_t peek(T * value); ReturnValue_t peek(T * value);
/** /**
* Remove item from FIFO. * Remove item from FIFO.
* @return RETURN_OK on success, EMPTY if empty * @return RETURN_OK on success, EMPTY if empty
*/ */
ReturnValue_t pop(); ReturnValue_t pop();
/*** /***
* Check if FIFO is empty * Check if FIFO is empty
* @return True if empty, False if not * @return True if empty, False if not
*/ */
bool empty(); bool empty();
/*** /***
* Check if FIFO is Full * Check if FIFO is Full
* @return True if full, False if not * @return True if full, False if not
*/ */
bool full(); bool full();
/*** /***
* Current used size (elements) used * Current used size (elements) used
* @return size_t in elements * @return size_t in elements
*/ */
size_t size(); size_t size();
/*** /***
* Get maximal capacity of fifo * Get maximal capacity of fifo
* @return size_t with max capacity of this fifo * @return size_t with max capacity of this fifo
*/ */
size_t getMaxCapacity() const; size_t getMaxCapacity() const;
protected: protected:
void setContainer(T* data); void setContainer(T* data);
size_t maxCapacity = 0; size_t maxCapacity = 0;
T* values; T* values;
size_t readIndex = 0; size_t readIndex = 0;
size_t writeIndex = 0; size_t writeIndex = 0;
size_t currentSize = 0; size_t currentSize = 0;
size_t next(size_t current); size_t next(size_t current);
}; };
#include "FIFOBase.tpp" #include "FIFOBase.tpp"

View File

@ -7,87 +7,87 @@
template<typename T> template<typename T>
inline FIFOBase<T>::FIFOBase(T* values, const size_t maxCapacity): inline FIFOBase<T>::FIFOBase(T* values, const size_t maxCapacity):
maxCapacity(maxCapacity), values(values){}; maxCapacity(maxCapacity), values(values){};
template<typename T> template<typename T>
inline ReturnValue_t FIFOBase<T>::insert(T value) { inline ReturnValue_t FIFOBase<T>::insert(T value) {
if (full()) { if (full()) {
return FULL; return FULL;
} else { } else {
values[writeIndex] = value; values[writeIndex] = value;
writeIndex = next(writeIndex); writeIndex = next(writeIndex);
++currentSize; ++currentSize;
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
} }
}; };
template<typename T> template<typename T>
inline ReturnValue_t FIFOBase<T>::retrieve(T* value) { inline ReturnValue_t FIFOBase<T>::retrieve(T* value) {
if (empty()) { if (empty()) {
return EMPTY; return EMPTY;
} else { } else {
if (value == nullptr){ if (value == nullptr){
return HasReturnvaluesIF::RETURN_FAILED; return HasReturnvaluesIF::RETURN_FAILED;
} }
*value = values[readIndex]; *value = values[readIndex];
readIndex = next(readIndex); readIndex = next(readIndex);
--currentSize; --currentSize;
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
} }
}; };
template<typename T> template<typename T>
inline ReturnValue_t FIFOBase<T>::peek(T* value) { inline ReturnValue_t FIFOBase<T>::peek(T* value) {
if(empty()) { if(empty()) {
return EMPTY; return EMPTY;
} else { } else {
if (value == nullptr){ if (value == nullptr){
return HasReturnvaluesIF::RETURN_FAILED; return HasReturnvaluesIF::RETURN_FAILED;
} }
*value = values[readIndex]; *value = values[readIndex];
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
} }
}; };
template<typename T> template<typename T>
inline ReturnValue_t FIFOBase<T>::pop() { inline ReturnValue_t FIFOBase<T>::pop() {
T value; T value;
return this->retrieve(&value); return this->retrieve(&value);
}; };
template<typename T> template<typename T>
inline bool FIFOBase<T>::empty() { inline bool FIFOBase<T>::empty() {
return (currentSize == 0); return (currentSize == 0);
}; };
template<typename T> template<typename T>
inline bool FIFOBase<T>::full() { inline bool FIFOBase<T>::full() {
return (currentSize == maxCapacity); return (currentSize == maxCapacity);
} }
template<typename T> template<typename T>
inline size_t FIFOBase<T>::size() { inline size_t FIFOBase<T>::size() {
return currentSize; return currentSize;
} }
template<typename T> template<typename T>
inline size_t FIFOBase<T>::next(size_t current) { inline size_t FIFOBase<T>::next(size_t current) {
++current; ++current;
if (current == maxCapacity) { if (current == maxCapacity) {
current = 0; current = 0;
} }
return current; return current;
} }
template<typename T> template<typename T>
inline size_t FIFOBase<T>::getMaxCapacity() const { inline size_t FIFOBase<T>::getMaxCapacity() const {
return maxCapacity; return maxCapacity;
} }
template<typename T> template<typename T>
inline void FIFOBase<T>::setContainer(T *data) { inline void FIFOBase<T>::setContainer(T *data) {
this->values = data; this->values = data;
} }
#endif #endif

View File

@ -8,30 +8,30 @@
*/ */
template<typename T, size_t MAX_SIZE, typename count_t = uint8_t> template<typename T, size_t MAX_SIZE, typename count_t = uint8_t>
class FixedArrayList: public ArrayList<T, count_t> { class FixedArrayList: public ArrayList<T, count_t> {
static_assert(MAX_SIZE <= (pow(2,sizeof(count_t)*8)-1), "count_t is not large enough to hold MAX_SIZE"); static_assert(MAX_SIZE <= (pow(2,sizeof(count_t)*8)-1), "count_t is not large enough to hold MAX_SIZE");
private: private:
T data[MAX_SIZE]; T data[MAX_SIZE];
public: public:
FixedArrayList() : FixedArrayList() :
ArrayList<T, count_t>(data, MAX_SIZE) { ArrayList<T, count_t>(data, MAX_SIZE) {
} }
FixedArrayList(const FixedArrayList& other) : FixedArrayList(const FixedArrayList& other) :
ArrayList<T, count_t>(data, MAX_SIZE) { ArrayList<T, count_t>(data, MAX_SIZE) {
memcpy(this->data, other.data, sizeof(this->data)); memcpy(this->data, other.data, sizeof(this->data));
this->entries = data; this->entries = data;
this->size = other.size; this->size = other.size;
} }
FixedArrayList& operator=(FixedArrayList other) { FixedArrayList& operator=(FixedArrayList other) {
memcpy(this->data, other.data, sizeof(this->data)); memcpy(this->data, other.data, sizeof(this->data));
this->entries = data; this->entries = data;
this->size = other.size; this->size = other.size;
return *this; return *this;
} }
virtual ~FixedArrayList() { virtual ~FixedArrayList() {
} }
}; };

View File

@ -18,212 +18,212 @@
*/ */
template<typename key_t, typename T> template<typename key_t, typename T>
class FixedMap: public SerializeIF { class FixedMap: public SerializeIF {
static_assert (std::is_trivially_copyable<T>::value or static_assert (std::is_trivially_copyable<T>::value or
std::is_base_of<SerializeIF, T>::value, std::is_base_of<SerializeIF, T>::value,
"Types used in FixedMap must either be trivial copy-able or a " "Types used in FixedMap must either be trivial copy-able or a "
"derived class from SerializeIF to be serialize-able"); "derived class from SerializeIF to be serialize-able");
public: public:
static const uint8_t INTERFACE_ID = CLASS_ID::FIXED_MAP; static const uint8_t INTERFACE_ID = CLASS_ID::FIXED_MAP;
static const ReturnValue_t KEY_ALREADY_EXISTS = MAKE_RETURN_CODE(0x01); static const ReturnValue_t KEY_ALREADY_EXISTS = MAKE_RETURN_CODE(0x01);
static const ReturnValue_t MAP_FULL = MAKE_RETURN_CODE(0x02); static const ReturnValue_t MAP_FULL = MAKE_RETURN_CODE(0x02);
static const ReturnValue_t KEY_DOES_NOT_EXIST = MAKE_RETURN_CODE(0x03); static const ReturnValue_t KEY_DOES_NOT_EXIST = MAKE_RETURN_CODE(0x03);
private: private:
static const key_t EMPTY_SLOT = -1; static const key_t EMPTY_SLOT = -1;
ArrayList<std::pair<key_t, T>, uint32_t> theMap; ArrayList<std::pair<key_t, T>, uint32_t> theMap;
uint32_t _size; uint32_t _size;
uint32_t findIndex(key_t key) const { uint32_t findIndex(key_t key) const {
if (_size == 0) { if (_size == 0) {
return 1; return 1;
} }
uint32_t i = 0; uint32_t i = 0;
for (i = 0; i < _size; ++i) { for (i = 0; i < _size; ++i) {
if (theMap[i].first == key) { if (theMap[i].first == key) {
return i; return i;
} }
} }
return i; return i;
} }
public: public:
FixedMap(uint32_t maxSize) : FixedMap(uint32_t maxSize) :
theMap(maxSize), _size(0) { theMap(maxSize), _size(0) {
} }
class Iterator: public ArrayList<std::pair<key_t, T>, uint32_t>::Iterator { class Iterator: public ArrayList<std::pair<key_t, T>, uint32_t>::Iterator {
public: public:
Iterator() : Iterator() :
ArrayList<std::pair<key_t, T>, uint32_t>::Iterator() { ArrayList<std::pair<key_t, T>, uint32_t>::Iterator() {
} }
Iterator(std::pair<key_t, T> *pair) : Iterator(std::pair<key_t, T> *pair) :
ArrayList<std::pair<key_t, T>, uint32_t>::Iterator(pair) { ArrayList<std::pair<key_t, T>, uint32_t>::Iterator(pair) {
} }
}; };
friend bool operator==(const typename FixedMap::Iterator& lhs, friend bool operator==(const typename FixedMap::Iterator& lhs,
const typename FixedMap::Iterator& rhs) { const typename FixedMap::Iterator& rhs) {
return (lhs.value == rhs.value); return (lhs.value == rhs.value);
} }
friend bool operator!=(const typename FixedMap::Iterator& lhs, friend bool operator!=(const typename FixedMap::Iterator& lhs,
const typename FixedMap::Iterator& rhs) { const typename FixedMap::Iterator& rhs) {
return not (lhs.value == rhs.value); return not (lhs.value == rhs.value);
} }
Iterator begin() const { Iterator begin() const {
return Iterator(&theMap[0]); return Iterator(&theMap[0]);
} }
Iterator end() const { Iterator end() const {
return Iterator(&theMap[_size]); return Iterator(&theMap[_size]);
} }
uint32_t size() const { uint32_t size() const {
return _size; return _size;
} }
ReturnValue_t insert(key_t key, T value, Iterator *storedValue = nullptr) { ReturnValue_t insert(key_t key, T value, Iterator *storedValue = nullptr) {
if (exists(key) == HasReturnvaluesIF::RETURN_OK) { if (exists(key) == HasReturnvaluesIF::RETURN_OK) {
return KEY_ALREADY_EXISTS; return KEY_ALREADY_EXISTS;
} }
if (_size == theMap.maxSize()) { if (_size == theMap.maxSize()) {
return MAP_FULL; return MAP_FULL;
} }
theMap[_size].first = key; theMap[_size].first = key;
theMap[_size].second = value; theMap[_size].second = value;
if (storedValue != nullptr) { if (storedValue != nullptr) {
*storedValue = Iterator(&theMap[_size]); *storedValue = Iterator(&theMap[_size]);
} }
++_size; ++_size;
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
} }
ReturnValue_t insert(std::pair<key_t, T> pair) { ReturnValue_t insert(std::pair<key_t, T> pair) {
return insert(pair.first, pair.second); return insert(pair.first, pair.second);
} }
ReturnValue_t exists(key_t key) const { ReturnValue_t exists(key_t key) const {
ReturnValue_t result = KEY_DOES_NOT_EXIST; ReturnValue_t result = KEY_DOES_NOT_EXIST;
if (findIndex(key) < _size) { if (findIndex(key) < _size) {
result = HasReturnvaluesIF::RETURN_OK; result = HasReturnvaluesIF::RETURN_OK;
} }
return result; return result;
} }
ReturnValue_t erase(Iterator *iter) { ReturnValue_t erase(Iterator *iter) {
uint32_t i; uint32_t i;
if ((i = findIndex((*iter).value->first)) >= _size) { if ((i = findIndex((*iter).value->first)) >= _size) {
return KEY_DOES_NOT_EXIST; return KEY_DOES_NOT_EXIST;
} }
theMap[i] = theMap[_size - 1]; theMap[i] = theMap[_size - 1];
--_size; --_size;
--((*iter).value); --((*iter).value);
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
} }
ReturnValue_t erase(key_t key) { ReturnValue_t erase(key_t key) {
uint32_t i; uint32_t i;
if ((i = findIndex(key)) >= _size) { if ((i = findIndex(key)) >= _size) {
return KEY_DOES_NOT_EXIST; return KEY_DOES_NOT_EXIST;
} }
theMap[i] = theMap[_size - 1]; theMap[i] = theMap[_size - 1];
--_size; --_size;
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
} }
T *findValue(key_t key) const { T *findValue(key_t key) const {
return &theMap[findIndex(key)].second; return &theMap[findIndex(key)].second;
} }
Iterator find(key_t key) const { Iterator find(key_t key) const {
ReturnValue_t result = exists(key); ReturnValue_t result = exists(key);
if (result != HasReturnvaluesIF::RETURN_OK) { if (result != HasReturnvaluesIF::RETURN_OK) {
return end(); return end();
} }
return Iterator(&theMap[findIndex(key)]); return Iterator(&theMap[findIndex(key)]);
} }
ReturnValue_t find(key_t key, T **value) const { ReturnValue_t find(key_t key, T **value) const {
ReturnValue_t result = exists(key); ReturnValue_t result = exists(key);
if (result != HasReturnvaluesIF::RETURN_OK) { if (result != HasReturnvaluesIF::RETURN_OK) {
return result; return result;
} }
*value = &theMap[findIndex(key)].second; *value = &theMap[findIndex(key)].second;
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
} }
bool empty() { bool empty() {
if(_size == 0) { if(_size == 0) {
return true; return true;
} }
else { else {
return false; return false;
} }
} }
bool full() { bool full() {
if(_size >= theMap.maxSize()) { if(_size >= theMap.maxSize()) {
return true; return true;
} }
else { else {
return false; return false;
} }
} }
void clear() { void clear() {
_size = 0; _size = 0;
} }
uint32_t maxSize() const { uint32_t maxSize() const {
return theMap.maxSize(); return theMap.maxSize();
} }
virtual ReturnValue_t serialize(uint8_t** buffer, size_t* size, virtual ReturnValue_t serialize(uint8_t** buffer, size_t* size,
size_t maxSize, Endianness streamEndianness) const { size_t maxSize, Endianness streamEndianness) const {
ReturnValue_t result = SerializeAdapter::serialize(&this->_size, ReturnValue_t result = SerializeAdapter::serialize(&this->_size,
buffer, size, maxSize, streamEndianness); buffer, size, maxSize, streamEndianness);
uint32_t i = 0; uint32_t i = 0;
while ((result == HasReturnvaluesIF::RETURN_OK) && (i < this->_size)) { while ((result == HasReturnvaluesIF::RETURN_OK) && (i < this->_size)) {
result = SerializeAdapter::serialize(&theMap[i].first, buffer, result = SerializeAdapter::serialize(&theMap[i].first, buffer,
size, maxSize, streamEndianness); size, maxSize, streamEndianness);
result = SerializeAdapter::serialize(&theMap[i].second, buffer, size, result = SerializeAdapter::serialize(&theMap[i].second, buffer, size,
maxSize, streamEndianness); maxSize, streamEndianness);
++i; ++i;
} }
return result; return result;
} }
virtual size_t getSerializedSize() const { virtual size_t getSerializedSize() const {
uint32_t printSize = sizeof(_size); uint32_t printSize = sizeof(_size);
uint32_t i = 0; uint32_t i = 0;
for (i = 0; i < _size; ++i) { for (i = 0; i < _size; ++i) {
printSize += SerializeAdapter::getSerializedSize( printSize += SerializeAdapter::getSerializedSize(
&theMap[i].first); &theMap[i].first);
printSize += SerializeAdapter::getSerializedSize(&theMap[i].second); printSize += SerializeAdapter::getSerializedSize(&theMap[i].second);
} }
return printSize; return printSize;
} }
virtual ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size, virtual ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size,
Endianness streamEndianness) { Endianness streamEndianness) {
ReturnValue_t result = SerializeAdapter::deSerialize(&this->_size, ReturnValue_t result = SerializeAdapter::deSerialize(&this->_size,
buffer, size, streamEndianness); buffer, size, streamEndianness);
if (this->_size > theMap.maxSize()) { if (this->_size > theMap.maxSize()) {
return SerializeIF::TOO_MANY_ELEMENTS; return SerializeIF::TOO_MANY_ELEMENTS;
} }
uint32_t i = 0; uint32_t i = 0;
while ((result == HasReturnvaluesIF::RETURN_OK) && (i < this->_size)) { while ((result == HasReturnvaluesIF::RETURN_OK) && (i < this->_size)) {
result = SerializeAdapter::deSerialize(&theMap[i].first, buffer, result = SerializeAdapter::deSerialize(&theMap[i].first, buffer,
size, streamEndianness); size, streamEndianness);
result = SerializeAdapter::deSerialize(&theMap[i].second, buffer, size, result = SerializeAdapter::deSerialize(&theMap[i].second, buffer, size,
streamEndianness); streamEndianness);
++i; ++i;
} }
return result; return result;
} }
}; };

View File

@ -34,172 +34,172 @@
template<typename key_t, typename T, typename KEY_COMPARE = std::less<key_t>> template<typename key_t, typename T, typename KEY_COMPARE = std::less<key_t>>
class FixedOrderedMultimap { class FixedOrderedMultimap {
public: public:
static const uint8_t INTERFACE_ID = CLASS_ID::FIXED_MULTIMAP; static const uint8_t INTERFACE_ID = CLASS_ID::FIXED_MULTIMAP;
static const ReturnValue_t MAP_FULL = MAKE_RETURN_CODE(0x01); static const ReturnValue_t MAP_FULL = MAKE_RETURN_CODE(0x01);
static const ReturnValue_t KEY_DOES_NOT_EXIST = MAKE_RETURN_CODE(0x02); static const ReturnValue_t KEY_DOES_NOT_EXIST = MAKE_RETURN_CODE(0x02);
/*** /***
* Constructor which needs a size_t for the maximum allowed size * Constructor which needs a size_t for the maximum allowed size
* *
* Can not be resized during runtime * Can not be resized during runtime
* *
* Allocates memory at construction * Allocates memory at construction
* @param maxSize size_t of Maximum allowed size * @param maxSize size_t of Maximum allowed size
*/ */
FixedOrderedMultimap(size_t maxSize):theMap(maxSize), _size(0){ FixedOrderedMultimap(size_t maxSize):theMap(maxSize), _size(0){
} }
/*** /***
* Virtual destructor frees Memory by deleting its member * Virtual destructor frees Memory by deleting its member
*/ */
virtual ~FixedOrderedMultimap() { virtual ~FixedOrderedMultimap() {
} }
/*** /***
* Special iterator for FixedOrderedMultimap * Special iterator for FixedOrderedMultimap
*/ */
class Iterator: public ArrayList<std::pair<key_t, T>, size_t>::Iterator { class Iterator: public ArrayList<std::pair<key_t, T>, size_t>::Iterator {
public: public:
Iterator() : Iterator() :
ArrayList<std::pair<key_t, T>, size_t>::Iterator() { ArrayList<std::pair<key_t, T>, size_t>::Iterator() {
} }
Iterator(std::pair<key_t, T> *pair) : Iterator(std::pair<key_t, T> *pair) :
ArrayList<std::pair<key_t, T>, size_t>::Iterator(pair) { ArrayList<std::pair<key_t, T>, size_t>::Iterator(pair) {
} }
}; };
/*** /***
* Returns an iterator pointing to the first element * Returns an iterator pointing to the first element
* @return Iterator pointing to first element * @return Iterator pointing to first element
*/ */
Iterator begin() const { Iterator begin() const {
return Iterator(&theMap[0]); return Iterator(&theMap[0]);
} }
/** /**
* Returns an iterator pointing to one element past the end * Returns an iterator pointing to one element past the end
* @return Iterator pointing to one element past the end * @return Iterator pointing to one element past the end
*/ */
Iterator end() const { Iterator end() const {
return Iterator(&theMap[_size]); return Iterator(&theMap[_size]);
} }
/*** /***
* Returns the current size of the map (not maximum size!) * Returns the current size of the map (not maximum size!)
* @return Current size * @return Current size
*/ */
size_t size() const{ size_t size() const{
return _size; return _size;
} }
/** /**
* Clears the map, does not deallocate any memory * Clears the map, does not deallocate any memory
*/ */
void clear(){ void clear(){
_size = 0; _size = 0;
} }
/** /**
* Returns the maximum size of the map * Returns the maximum size of the map
* @return Maximum size of the map * @return Maximum size of the map
*/ */
size_t maxSize() const{ size_t maxSize() const{
return theMap.maxSize(); return theMap.maxSize();
} }
/*** /***
* Used to insert a key and value separately. * Used to insert a key and value separately.
* *
* @param[in] key Key of the new element * @param[in] key Key of the new element
* @param[in] value Value of the new element * @param[in] value Value of the new element
* @param[in/out] (optional) storedValue On success this points to the new value, otherwise a nullptr * @param[in/out] (optional) storedValue On success this points to the new value, otherwise a nullptr
* @return RETURN_OK if insert was successful, MAP_FULL if no space is available * @return RETURN_OK if insert was successful, MAP_FULL if no space is available
*/ */
ReturnValue_t insert(key_t key, T value, Iterator *storedValue = nullptr); ReturnValue_t insert(key_t key, T value, Iterator *storedValue = nullptr);
/*** /***
* Used to insert new pair instead of single values * Used to insert new pair instead of single values
* *
* @param pair Pair to be inserted * @param pair Pair to be inserted
* @return RETURN_OK if insert was successful, MAP_FULL if no space is available * @return RETURN_OK if insert was successful, MAP_FULL if no space is available
*/ */
ReturnValue_t insert(std::pair<key_t, T> pair); ReturnValue_t insert(std::pair<key_t, T> pair);
/*** /***
* Can be used to check if a certain key is in the map * Can be used to check if a certain key is in the map
* @param key Key to be checked * @param key Key to be checked
* @return RETURN_OK if the key exists KEY_DOES_NOT_EXIST otherwise * @return RETURN_OK if the key exists KEY_DOES_NOT_EXIST otherwise
*/ */
ReturnValue_t exists(key_t key) const; ReturnValue_t exists(key_t key) const;
/*** /***
* Used to delete the element in the iterator * Used to delete the element in the iterator
* *
* The iterator will point to the element before or begin(), * The iterator will point to the element before or begin(),
* but never to one element in front of the map. * but never to one element in front of the map.
* *
* @warning The iterator needs to be valid and dereferenceable * @warning The iterator needs to be valid and dereferenceable
* @param[in/out] iter Pointer to iterator to the element that needs to be ereased * @param[in/out] iter Pointer to iterator to the element that needs to be ereased
* @return RETURN_OK if erased, KEY_DOES_NOT_EXIST if the there is no element like this * @return RETURN_OK if erased, KEY_DOES_NOT_EXIST if the there is no element like this
*/ */
ReturnValue_t erase(Iterator *iter); ReturnValue_t erase(Iterator *iter);
/*** /***
* Used to erase by key * Used to erase by key
* @param key Key to be erased * @param key Key to be erased
* @return RETURN_OK if erased, KEY_DOES_NOT_EXIST if the there is no element like this * @return RETURN_OK if erased, KEY_DOES_NOT_EXIST if the there is no element like this
*/ */
ReturnValue_t erase(key_t key); ReturnValue_t erase(key_t key);
/*** /***
* Find returns the first appearance of the key * Find returns the first appearance of the key
* *
* If the key does not exist, it points to end() * If the key does not exist, it points to end()
* *
* @param key Key to search for * @param key Key to search for
* @return Iterator pointing to the first entry of key * @return Iterator pointing to the first entry of key
*/ */
Iterator find(key_t key) const{ Iterator find(key_t key) const{
ReturnValue_t result = exists(key); ReturnValue_t result = exists(key);
if (result != HasReturnvaluesIF::RETURN_OK) { if (result != HasReturnvaluesIF::RETURN_OK) {
return end(); return end();
} }
return Iterator(&theMap[findFirstIndex(key)]); return Iterator(&theMap[findFirstIndex(key)]);
}; };
/*** /***
* Finds first entry of the given key and returns a * Finds first entry of the given key and returns a
* pointer to the value * pointer to the value
* *
* @param key Key to search for * @param key Key to search for
* @param value Found value * @param value Found value
* @return RETURN_OK if it points to the value, * @return RETURN_OK if it points to the value,
* KEY_DOES_NOT_EXIST if the key is not in the map * KEY_DOES_NOT_EXIST if the key is not in the map
*/ */
ReturnValue_t find(key_t key, T **value) const; ReturnValue_t find(key_t key, T **value) const;
friend bool operator==(const typename FixedOrderedMultimap::Iterator& lhs, friend bool operator==(const typename FixedOrderedMultimap::Iterator& lhs,
const typename FixedOrderedMultimap::Iterator& rhs) { const typename FixedOrderedMultimap::Iterator& rhs) {
return (lhs.value == rhs.value); return (lhs.value == rhs.value);
} }
friend bool operator!=(const typename FixedOrderedMultimap::Iterator& lhs, friend bool operator!=(const typename FixedOrderedMultimap::Iterator& lhs,
const typename FixedOrderedMultimap::Iterator& rhs) { const typename FixedOrderedMultimap::Iterator& rhs) {
return not (lhs.value == rhs.value); return not (lhs.value == rhs.value);
} }
private: private:
typedef KEY_COMPARE compare; typedef KEY_COMPARE compare;
compare myComp; compare myComp;
ArrayList<std::pair<key_t, T>, size_t> theMap; ArrayList<std::pair<key_t, T>, size_t> theMap;
size_t _size; size_t _size;
size_t findFirstIndex(key_t key, size_t startAt = 0) const; size_t findFirstIndex(key_t key, size_t startAt = 0) const;
size_t findNicePlace(key_t key) const; size_t findNicePlace(key_t key) const;
void removeFromPosition(size_t position); void removeFromPosition(size_t position);
}; };
#include "FixedOrderedMultimap.tpp" #include "FixedOrderedMultimap.tpp"

View File

@ -4,105 +4,105 @@
template<typename key_t, typename T, typename KEY_COMPARE> template<typename key_t, typename T, typename KEY_COMPARE>
inline ReturnValue_t FixedOrderedMultimap<key_t, T, KEY_COMPARE>::insert(key_t key, T value, Iterator *storedValue) { inline ReturnValue_t FixedOrderedMultimap<key_t, T, KEY_COMPARE>::insert(key_t key, T value, Iterator *storedValue) {
if (_size == theMap.maxSize()) { if (_size == theMap.maxSize()) {
return MAP_FULL; return MAP_FULL;
} }
size_t position = findNicePlace(key); size_t position = findNicePlace(key);
memmove(static_cast<void*>(&theMap[position + 1]),static_cast<void*>(&theMap[position]), memmove(static_cast<void*>(&theMap[position + 1]),static_cast<void*>(&theMap[position]),
(_size - position) * sizeof(std::pair<key_t,T>)); (_size - position) * sizeof(std::pair<key_t,T>));
theMap[position].first = key; theMap[position].first = key;
theMap[position].second = value; theMap[position].second = value;
++_size; ++_size;
if (storedValue != nullptr) { if (storedValue != nullptr) {
*storedValue = Iterator(&theMap[position]); *storedValue = Iterator(&theMap[position]);
} }
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
} }
template<typename key_t, typename T, typename KEY_COMPARE> template<typename key_t, typename T, typename KEY_COMPARE>
inline ReturnValue_t FixedOrderedMultimap<key_t, T, KEY_COMPARE>::insert(std::pair<key_t, T> pair) { inline ReturnValue_t FixedOrderedMultimap<key_t, T, KEY_COMPARE>::insert(std::pair<key_t, T> pair) {
return insert(pair.first, pair.second); return insert(pair.first, pair.second);
} }
template<typename key_t, typename T, typename KEY_COMPARE> template<typename key_t, typename T, typename KEY_COMPARE>
inline ReturnValue_t FixedOrderedMultimap<key_t, T, KEY_COMPARE>::exists(key_t key) const { inline ReturnValue_t FixedOrderedMultimap<key_t, T, KEY_COMPARE>::exists(key_t key) const {
ReturnValue_t result = KEY_DOES_NOT_EXIST; ReturnValue_t result = KEY_DOES_NOT_EXIST;
if (findFirstIndex(key) < _size) { if (findFirstIndex(key) < _size) {
result = HasReturnvaluesIF::RETURN_OK; result = HasReturnvaluesIF::RETURN_OK;
} }
return result; return result;
} }
template<typename key_t, typename T, typename KEY_COMPARE> template<typename key_t, typename T, typename KEY_COMPARE>
inline ReturnValue_t FixedOrderedMultimap<key_t, T, KEY_COMPARE>::erase(Iterator *iter) { inline ReturnValue_t FixedOrderedMultimap<key_t, T, KEY_COMPARE>::erase(Iterator *iter) {
size_t i; size_t i;
if ((i = findFirstIndex((*iter).value->first)) >= _size) { if ((i = findFirstIndex((*iter).value->first)) >= _size) {
return KEY_DOES_NOT_EXIST; return KEY_DOES_NOT_EXIST;
} }
removeFromPosition(i); removeFromPosition(i);
if (*iter != begin()) { if (*iter != begin()) {
(*iter)--; (*iter)--;
} else { } else {
*iter = begin(); *iter = begin();
} }
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
} }
template<typename key_t, typename T, typename KEY_COMPARE> template<typename key_t, typename T, typename KEY_COMPARE>
inline ReturnValue_t FixedOrderedMultimap<key_t, T, KEY_COMPARE>::erase(key_t key) { inline ReturnValue_t FixedOrderedMultimap<key_t, T, KEY_COMPARE>::erase(key_t key) {
size_t i; size_t i;
if ((i = findFirstIndex(key)) >= _size) { if ((i = findFirstIndex(key)) >= _size) {
return KEY_DOES_NOT_EXIST; return KEY_DOES_NOT_EXIST;
} }
do { do {
removeFromPosition(i); removeFromPosition(i);
i = findFirstIndex(key, i); i = findFirstIndex(key, i);
} while (i < _size); } while (i < _size);
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
} }
template<typename key_t, typename T, typename KEY_COMPARE> template<typename key_t, typename T, typename KEY_COMPARE>
inline ReturnValue_t FixedOrderedMultimap<key_t, T, KEY_COMPARE>::find(key_t key, T **value) const { inline ReturnValue_t FixedOrderedMultimap<key_t, T, KEY_COMPARE>::find(key_t key, T **value) const {
ReturnValue_t result = exists(key); ReturnValue_t result = exists(key);
if (result != HasReturnvaluesIF::RETURN_OK) { if (result != HasReturnvaluesIF::RETURN_OK) {
return result; return result;
} }
*value = &theMap[findFirstIndex(key)].second; *value = &theMap[findFirstIndex(key)].second;
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
} }
template<typename key_t, typename T, typename KEY_COMPARE> template<typename key_t, typename T, typename KEY_COMPARE>
inline size_t FixedOrderedMultimap<key_t, T, KEY_COMPARE>::findFirstIndex(key_t key, size_t startAt) const { inline size_t FixedOrderedMultimap<key_t, T, KEY_COMPARE>::findFirstIndex(key_t key, size_t startAt) const {
if (startAt >= _size) { if (startAt >= _size) {
return startAt + 1; return startAt + 1;
} }
size_t i = startAt; size_t i = startAt;
for (i = startAt; i < _size; ++i) { for (i = startAt; i < _size; ++i) {
if (theMap[i].first == key) { if (theMap[i].first == key) {
return i; return i;
} }
} }
return i; return i;
} }
template<typename key_t, typename T, typename KEY_COMPARE> template<typename key_t, typename T, typename KEY_COMPARE>
inline size_t FixedOrderedMultimap<key_t, T, KEY_COMPARE>::findNicePlace(key_t key) const { inline size_t FixedOrderedMultimap<key_t, T, KEY_COMPARE>::findNicePlace(key_t key) const {
size_t i = 0; size_t i = 0;
for (i = 0; i < _size; ++i) { for (i = 0; i < _size; ++i) {
if (myComp(key, theMap[i].first)) { if (myComp(key, theMap[i].first)) {
return i; return i;
} }
} }
return i; return i;
} }
template<typename key_t, typename T, typename KEY_COMPARE> template<typename key_t, typename T, typename KEY_COMPARE>
inline void FixedOrderedMultimap<key_t, T, KEY_COMPARE>::removeFromPosition(size_t position) { inline void FixedOrderedMultimap<key_t, T, KEY_COMPARE>::removeFromPosition(size_t position) {
if (_size <= position) { if (_size <= position) {
return; return;
} }
memmove(static_cast<void*>(&theMap[position]), static_cast<void*>(&theMap[position + 1]), memmove(static_cast<void*>(&theMap[position]), static_cast<void*>(&theMap[position + 1]),
(_size - position - 1) * sizeof(std::pair<key_t,T>)); (_size - position - 1) * sizeof(std::pair<key_t,T>));
--_size; --_size;
} }

View File

@ -6,85 +6,85 @@
template<typename T, typename count_t = uint8_t> template<typename T, typename count_t = uint8_t>
class HybridIterator: public LinkedElement<T>::Iterator, class HybridIterator: public LinkedElement<T>::Iterator,
public ArrayList<T, count_t>::Iterator { public ArrayList<T, count_t>::Iterator {
public: public:
HybridIterator() {} HybridIterator() {}
HybridIterator(typename LinkedElement<T>::Iterator *iter) : HybridIterator(typename LinkedElement<T>::Iterator *iter) :
LinkedElement<T>::Iterator(*iter), value(iter->value), LinkedElement<T>::Iterator(*iter), value(iter->value),
linked(true) { linked(true) {
} }
HybridIterator(LinkedElement<T> *start) : HybridIterator(LinkedElement<T> *start) :
LinkedElement<T>::Iterator(start), value(start->value), LinkedElement<T>::Iterator(start), value(start->value),
linked(true) { linked(true) {
} }
HybridIterator(typename ArrayList<T, count_t>::Iterator start, HybridIterator(typename ArrayList<T, count_t>::Iterator start,
typename ArrayList<T, count_t>::Iterator end) : typename ArrayList<T, count_t>::Iterator end) :
ArrayList<T, count_t>::Iterator(start), value(start.value), ArrayList<T, count_t>::Iterator(start), value(start.value),
linked(false), end(end.value) { linked(false), end(end.value) {
if (value == this->end) { if (value == this->end) {
value = NULL; value = NULL;
} }
} }
HybridIterator(T *firstElement, T *lastElement) : HybridIterator(T *firstElement, T *lastElement) :
ArrayList<T, count_t>::Iterator(firstElement), value(firstElement), ArrayList<T, count_t>::Iterator(firstElement), value(firstElement),
linked(false), end(++lastElement) { linked(false), end(++lastElement) {
if (value == end) { if (value == end) {
value = NULL; value = NULL;
} }
} }
HybridIterator& operator++() { HybridIterator& operator++() {
if (linked) { if (linked) {
LinkedElement<T>::Iterator::operator++(); LinkedElement<T>::Iterator::operator++();
if (LinkedElement<T>::Iterator::value != nullptr) { if (LinkedElement<T>::Iterator::value != nullptr) {
value = LinkedElement<T>::Iterator::value->value; value = LinkedElement<T>::Iterator::value->value;
} else { } else {
value = nullptr; value = nullptr;
} }
} else { } else {
ArrayList<T, count_t>::Iterator::operator++(); ArrayList<T, count_t>::Iterator::operator++();
value = ArrayList<T, count_t>::Iterator::value; value = ArrayList<T, count_t>::Iterator::value;
if (value == end) { if (value == end) {
value = nullptr; value = nullptr;
} }
} }
return *this; return *this;
} }
HybridIterator operator++(int) { HybridIterator operator++(int) {
HybridIterator tmp(*this); HybridIterator tmp(*this);
operator++(); operator++();
return tmp; return tmp;
} }
bool operator==(const HybridIterator& other) const { bool operator==(const HybridIterator& other) const {
return value == other.value; return value == other.value;
} }
bool operator!=(const HybridIterator& other) const { bool operator!=(const HybridIterator& other) const {
return !(*this == other); return !(*this == other);
} }
T operator*() { T operator*() {
return *value; return *value;
} }
T *operator->() { T *operator->() {
return value; return value;
} }
T* value = nullptr; T* value = nullptr;
private: private:
bool linked = false; bool linked = false;
T *end = nullptr; T *end = nullptr;
}; };
#endif /* FRAMEWORK_CONTAINER_HYBRIDITERATOR_H_ */ #endif /* FRAMEWORK_CONTAINER_HYBRIDITERATOR_H_ */

File diff suppressed because it is too large Load Diff

View File

@ -22,50 +22,50 @@
*/ */
class PlacementFactory { class PlacementFactory {
public: public:
PlacementFactory(StorageManagerIF* backend) : PlacementFactory(StorageManagerIF* backend) :
dataBackend(backend) { dataBackend(backend) {
} }
/*** /***
* Generates an object of type T in the backend storage. * Generates an object of type T in the backend storage.
* *
* @warning Do not use with any Type that allocates memory internally! * @warning Do not use with any Type that allocates memory internally!
* *
* @tparam T Type of Object * @tparam T Type of Object
* @param args Constructor Arguments to be passed * @param args Constructor Arguments to be passed
* @return A pointer to the new object or a nullptr in case of failure * @return A pointer to the new object or a nullptr in case of failure
*/ */
template<typename T, typename ... Args> template<typename T, typename ... Args>
T* generate(Args&&... args) { T* generate(Args&&... args) {
store_address_t tempId; store_address_t tempId;
uint8_t* pData = nullptr; uint8_t* pData = nullptr;
ReturnValue_t result = dataBackend->getFreeElement(&tempId, sizeof(T), ReturnValue_t result = dataBackend->getFreeElement(&tempId, sizeof(T),
&pData); &pData);
if (result != HasReturnvaluesIF::RETURN_OK) { if (result != HasReturnvaluesIF::RETURN_OK) {
return nullptr; return nullptr;
} }
T* temp = new (pData) T(std::forward<Args>(args)...); T* temp = new (pData) T(std::forward<Args>(args)...);
return temp; return temp;
} }
/*** /***
* Function to destroy the object allocated with generate and free space in backend. * Function to destroy the object allocated with generate and free space in backend.
* This must be called by the user. * This must be called by the user.
* *
* @param thisElement Element to be destroyed * @param thisElement Element to be destroyed
* @return RETURN_OK if the element was destroyed, different errors on failure * @return RETURN_OK if the element was destroyed, different errors on failure
*/ */
template<typename T> template<typename T>
ReturnValue_t destroy(T* thisElement) { ReturnValue_t destroy(T* thisElement) {
if (thisElement == nullptr){ if (thisElement == nullptr){
return HasReturnvaluesIF::RETURN_FAILED; return HasReturnvaluesIF::RETURN_FAILED;
} }
//Need to call destructor first, in case something was allocated by the object (shouldn't do that, however). //Need to call destructor first, in case something was allocated by the object (shouldn't do that, however).
thisElement->~T(); thisElement->~T();
uint8_t* pointer = (uint8_t*) (thisElement); uint8_t* pointer = (uint8_t*) (thisElement);
return dataBackend->deleteData(pointer, sizeof(T)); return dataBackend->deleteData(pointer, sizeof(T));
} }
private: private:
StorageManagerIF* dataBackend; StorageManagerIF* dataBackend;
}; };
#endif /* FRAMEWORK_CONTAINER_PLACEMENTFACTORY_H_ */ #endif /* FRAMEWORK_CONTAINER_PLACEMENTFACTORY_H_ */

View File

@ -7,107 +7,107 @@
template<uint8_t N_READ_PTRS = 1> template<uint8_t N_READ_PTRS = 1>
class RingBufferBase { class RingBufferBase {
public: public:
RingBufferBase(size_t startAddress, const size_t size, bool overwriteOld) : RingBufferBase(size_t startAddress, const size_t size, bool overwriteOld) :
start(startAddress), write(startAddress), size(size), start(startAddress), write(startAddress), size(size),
overwriteOld(overwriteOld) { overwriteOld(overwriteOld) {
for (uint8_t count = 0; count < N_READ_PTRS; count++) { for (uint8_t count = 0; count < N_READ_PTRS; count++) {
read[count] = startAddress; read[count] = startAddress;
} }
} }
virtual ~RingBufferBase() {} virtual ~RingBufferBase() {}
bool isFull(uint8_t n = 0) { bool isFull(uint8_t n = 0) {
return (availableWriteSpace(n) == 0); return (availableWriteSpace(n) == 0);
} }
bool isEmpty(uint8_t n = 0) { bool isEmpty(uint8_t n = 0) {
return (getAvailableReadData(n) == 0); return (getAvailableReadData(n) == 0);
} }
size_t getAvailableReadData(uint8_t n = 0) const { size_t getAvailableReadData(uint8_t n = 0) const {
return ((write + size) - read[n]) % size; return ((write + size) - read[n]) % size;
} }
size_t availableWriteSpace(uint8_t n = 0) const { size_t availableWriteSpace(uint8_t n = 0) const {
//One less to avoid ambiguous full/empty problem. //One less to avoid ambiguous full/empty problem.
return (((read[n] + size) - write - 1) % size); return (((read[n] + size) - write - 1) % size);
} }
bool overwritesOld() const { bool overwritesOld() const {
return overwriteOld; return overwriteOld;
} }
size_t getMaxSize() const { size_t getMaxSize() const {
return size - 1; return size - 1;
} }
void clear() { void clear() {
write = start; write = start;
for (uint8_t count = 0; count < N_READ_PTRS; count++) { for (uint8_t count = 0; count < N_READ_PTRS; count++) {
read[count] = start; read[count] = start;
} }
} }
size_t writeTillWrap() { size_t writeTillWrap() {
return (start + size) - write; return (start + size) - write;
} }
size_t readTillWrap(uint8_t n = 0) { size_t readTillWrap(uint8_t n = 0) {
return (start + size) - read[n]; return (start + size) - read[n];
} }
size_t getStart() const { size_t getStart() const {
return start; return start;
} }
protected: protected:
const size_t start; const size_t start;
size_t write; size_t write;
size_t read[N_READ_PTRS]; size_t read[N_READ_PTRS];
const size_t size; const size_t size;
const bool overwriteOld; const bool overwriteOld;
void incrementWrite(uint32_t amount) { void incrementWrite(uint32_t amount) {
write = ((write + amount - start) % size) + start; write = ((write + amount - start) % size) + start;
} }
void incrementRead(uint32_t amount, uint8_t n = 0) { void incrementRead(uint32_t amount, uint8_t n = 0) {
read[n] = ((read[n] + amount - start) % size) + start; read[n] = ((read[n] + amount - start) % size) + start;
} }
ReturnValue_t readData(uint32_t amount, uint8_t n = 0) { ReturnValue_t readData(uint32_t amount, uint8_t n = 0) {
if (getAvailableReadData(n) >= amount) { if (getAvailableReadData(n) >= amount) {
incrementRead(amount, n); incrementRead(amount, n);
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
} else { } else {
return HasReturnvaluesIF::RETURN_FAILED; return HasReturnvaluesIF::RETURN_FAILED;
} }
} }
ReturnValue_t writeData(uint32_t amount) { ReturnValue_t writeData(uint32_t amount) {
if (availableWriteSpace() >= amount or overwriteOld) { if (availableWriteSpace() >= amount or overwriteOld) {
incrementWrite(amount); incrementWrite(amount);
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
} else { } else {
return HasReturnvaluesIF::RETURN_FAILED; return HasReturnvaluesIF::RETURN_FAILED;
} }
} }
size_t getRead(uint8_t n = 0) const { size_t getRead(uint8_t n = 0) const {
return read[n]; return read[n];
} }
void setRead(uint32_t read, uint8_t n = 0) { void setRead(uint32_t read, uint8_t n = 0) {
if (read >= start && read < (start+size)) { if (read >= start && read < (start+size)) {
this->read[n] = read; this->read[n] = read;
} }
} }
uint32_t getWrite() const { uint32_t getWrite() const {
return write; return write;
} }
void setWrite(uint32_t write) { void setWrite(uint32_t write) {
this->write = write; this->write = write;
} }
}; };
#endif /* FSFW_CONTAINER_RINGBUFFERBASE_H_ */ #endif /* FSFW_CONTAINER_RINGBUFFERBASE_H_ */

View File

@ -3,23 +3,23 @@
#include "../ipc/MutexHelper.h" #include "../ipc/MutexHelper.h"
SharedRingBuffer::SharedRingBuffer(object_id_t objectId, const size_t size, SharedRingBuffer::SharedRingBuffer(object_id_t objectId, const size_t size,
bool overwriteOld, size_t maxExcessBytes): bool overwriteOld, size_t maxExcessBytes):
SystemObject(objectId), SimpleRingBuffer(size, overwriteOld, SystemObject(objectId), SimpleRingBuffer(size, overwriteOld,
maxExcessBytes) { maxExcessBytes) {
mutex = MutexFactory::instance()->createMutex(); mutex = MutexFactory::instance()->createMutex();
} }
SharedRingBuffer::SharedRingBuffer(object_id_t objectId, uint8_t *buffer, SharedRingBuffer::SharedRingBuffer(object_id_t objectId, uint8_t *buffer,
const size_t size, bool overwriteOld, size_t maxExcessBytes): const size_t size, bool overwriteOld, size_t maxExcessBytes):
SystemObject(objectId), SimpleRingBuffer(buffer, size, overwriteOld, SystemObject(objectId), SimpleRingBuffer(buffer, size, overwriteOld,
maxExcessBytes) { maxExcessBytes) {
mutex = MutexFactory::instance()->createMutex(); mutex = MutexFactory::instance()->createMutex();
} }
void SharedRingBuffer::setToUseReceiveSizeFIFO(size_t fifoDepth) { void SharedRingBuffer::setToUseReceiveSizeFIFO(size_t fifoDepth) {
this->fifoDepth = fifoDepth; this->fifoDepth = fifoDepth;
} }
ReturnValue_t SharedRingBuffer::lockRingBufferMutex( ReturnValue_t SharedRingBuffer::lockRingBufferMutex(
@ -38,20 +38,20 @@ MutexIF* SharedRingBuffer::getMutexHandle() const {
} }
ReturnValue_t SharedRingBuffer::initialize() { ReturnValue_t SharedRingBuffer::initialize() {
if(fifoDepth > 0) { if(fifoDepth > 0) {
receiveSizesFIFO = new DynamicFIFO<size_t>(fifoDepth); receiveSizesFIFO = new DynamicFIFO<size_t>(fifoDepth);
} }
return SystemObject::initialize(); return SystemObject::initialize();
} }
DynamicFIFO<size_t>* SharedRingBuffer::getReceiveSizesFIFO() { DynamicFIFO<size_t>* SharedRingBuffer::getReceiveSizesFIFO() {
if(receiveSizesFIFO == nullptr) { if(receiveSizesFIFO == nullptr) {
// Configuration error. // Configuration error.
#if FSFW_CPP_OSTREAM_ENABLED == 1 #if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning << "SharedRingBuffer::getReceiveSizesFIFO: Ring buffer" sif::warning << "SharedRingBuffer::getReceiveSizesFIFO: Ring buffer"
<< " was not configured to have sizes FIFO, returning nullptr!" << " was not configured to have sizes FIFO, returning nullptr!"
<< std::endl; << std::endl;
#endif #endif
} }
return receiveSizesFIFO; return receiveSizesFIFO;
} }

View File

@ -15,76 +15,76 @@
* and unlock operations. * and unlock operations.
*/ */
class SharedRingBuffer: public SystemObject, class SharedRingBuffer: public SystemObject,
public SimpleRingBuffer { public SimpleRingBuffer {
public: public:
/** /**
* This constructor allocates a new internal buffer with the supplied size. * This constructor allocates a new internal buffer with the supplied size.
* @param size * @param size
* @param overwriteOld * @param overwriteOld
* If the ring buffer is overflowing at a write operartion, the oldest data * If the ring buffer is overflowing at a write operartion, the oldest data
* will be overwritten. * will be overwritten.
*/ */
SharedRingBuffer(object_id_t objectId, const size_t size, SharedRingBuffer(object_id_t objectId, const size_t size,
bool overwriteOld, size_t maxExcessBytes); bool overwriteOld, size_t maxExcessBytes);
/** /**
* @brief This function can be used to add an optional FIFO to the class * @brief This function can be used to add an optional FIFO to the class
* @details * @details
* This FIFO will be allocated in the initialize function (and will * This FIFO will be allocated in the initialize function (and will
* have a fixed maximum size after that). It can be used to store * have a fixed maximum size after that). It can be used to store
* values like packet sizes, for example for a shared ring buffer * values like packet sizes, for example for a shared ring buffer
* used by producer/consumer tasks. * used by producer/consumer tasks.
*/ */
void setToUseReceiveSizeFIFO(size_t fifoDepth); void setToUseReceiveSizeFIFO(size_t fifoDepth);
/** /**
* This constructor takes an external buffer with the specified size. * This constructor takes an external buffer with the specified size.
* @param buffer * @param buffer
* @param size * @param size
* @param overwriteOld * @param overwriteOld
* If the ring buffer is overflowing at a write operartion, the oldest data * If the ring buffer is overflowing at a write operartion, the oldest data
* will be overwritten. * will be overwritten.
*/ */
SharedRingBuffer(object_id_t objectId, uint8_t* buffer, const size_t size, SharedRingBuffer(object_id_t objectId, uint8_t* buffer, const size_t size,
bool overwriteOld, size_t maxExcessBytes); bool overwriteOld, size_t maxExcessBytes);
/** /**
* Unless a read-only constant value is read, all operations on the * Unless a read-only constant value is read, all operations on the
* shared ring buffer should be protected by calling this function. * shared ring buffer should be protected by calling this function.
* @param timeoutType * @param timeoutType
* @param timeout * @param timeout
* @return * @return
*/ */
virtual ReturnValue_t lockRingBufferMutex(MutexIF::TimeoutType timeoutType, virtual ReturnValue_t lockRingBufferMutex(MutexIF::TimeoutType timeoutType,
dur_millis_t timeout); dur_millis_t timeout);
/** /**
* Any locked mutex also has to be unlocked, otherwise, access to the * Any locked mutex also has to be unlocked, otherwise, access to the
* shared ring buffer will be blocked. * shared ring buffer will be blocked.
* @return * @return
*/ */
virtual ReturnValue_t unlockRingBufferMutex(); virtual ReturnValue_t unlockRingBufferMutex();
/** /**
* The mutex handle can be accessed directly, for example to perform * The mutex handle can be accessed directly, for example to perform
* the lock with the #MutexHelper for a RAII compliant lock operation. * the lock with the #MutexHelper for a RAII compliant lock operation.
* @return * @return
*/ */
MutexIF* getMutexHandle() const; MutexIF* getMutexHandle() const;
ReturnValue_t initialize() override; ReturnValue_t initialize() override;
/** /**
* If the shared ring buffer was configured to have a sizes FIFO, a handle * If the shared ring buffer was configured to have a sizes FIFO, a handle
* to that FIFO can be retrieved with this function. * to that FIFO can be retrieved with this function.
* Do not forget to protect access with a lock if required! * Do not forget to protect access with a lock if required!
* @return * @return
*/ */
DynamicFIFO<size_t>* getReceiveSizesFIFO(); DynamicFIFO<size_t>* getReceiveSizesFIFO();
private: private:
MutexIF* mutex = nullptr; MutexIF* mutex = nullptr;
size_t fifoDepth = 0; size_t fifoDepth = 0;
DynamicFIFO<size_t>* receiveSizesFIFO = nullptr; DynamicFIFO<size_t>* receiveSizesFIFO = nullptr;
}; };

View File

@ -2,31 +2,31 @@
#include <cstring> #include <cstring>
SimpleRingBuffer::SimpleRingBuffer(const size_t size, bool overwriteOld, SimpleRingBuffer::SimpleRingBuffer(const size_t size, bool overwriteOld,
size_t maxExcessBytes) : size_t maxExcessBytes) :
RingBufferBase<>(0, size, overwriteOld), RingBufferBase<>(0, size, overwriteOld),
maxExcessBytes(maxExcessBytes) { maxExcessBytes(maxExcessBytes) {
if(maxExcessBytes > size) { if(maxExcessBytes > size) {
this->maxExcessBytes = size; this->maxExcessBytes = size;
} }
else { else {
this->maxExcessBytes = maxExcessBytes; this->maxExcessBytes = maxExcessBytes;
} }
buffer = new uint8_t[size + maxExcessBytes]; buffer = new uint8_t[size + maxExcessBytes];
} }
SimpleRingBuffer::SimpleRingBuffer(uint8_t *buffer, const size_t size, SimpleRingBuffer::SimpleRingBuffer(uint8_t *buffer, const size_t size,
bool overwriteOld, size_t maxExcessBytes): bool overwriteOld, size_t maxExcessBytes):
RingBufferBase<>(0, size, overwriteOld), buffer(buffer) { RingBufferBase<>(0, size, overwriteOld), buffer(buffer) {
if(maxExcessBytes > size) { if(maxExcessBytes > size) {
this->maxExcessBytes = size; this->maxExcessBytes = size;
} }
else { else {
this->maxExcessBytes = maxExcessBytes; this->maxExcessBytes = maxExcessBytes;
} }
} }
SimpleRingBuffer::~SimpleRingBuffer() { SimpleRingBuffer::~SimpleRingBuffer() {
delete[] buffer; delete[] buffer;
} }
ReturnValue_t SimpleRingBuffer::getFreeElement(uint8_t **writePointer, ReturnValue_t SimpleRingBuffer::getFreeElement(uint8_t **writePointer,
@ -48,58 +48,58 @@ ReturnValue_t SimpleRingBuffer::getFreeElement(uint8_t **writePointer,
} }
void SimpleRingBuffer::confirmBytesWritten(size_t amount) { void SimpleRingBuffer::confirmBytesWritten(size_t amount) {
if(getExcessBytes() > 0) { if(getExcessBytes() > 0) {
moveExcessBytesToStart(); moveExcessBytesToStart();
} }
incrementWrite(amount); incrementWrite(amount);
} }
ReturnValue_t SimpleRingBuffer::writeData(const uint8_t* data, ReturnValue_t SimpleRingBuffer::writeData(const uint8_t* data,
size_t amount) { size_t amount) {
if (availableWriteSpace() >= amount or overwriteOld) { if (availableWriteSpace() >= amount or overwriteOld) {
size_t amountTillWrap = writeTillWrap(); size_t amountTillWrap = writeTillWrap();
if (amountTillWrap >= amount) { if (amountTillWrap >= amount) {
// remaining size in buffer is sufficient to fit full amount. // remaining size in buffer is sufficient to fit full amount.
memcpy(&buffer[write], data, amount); memcpy(&buffer[write], data, amount);
} }
else { else {
memcpy(&buffer[write], data, amountTillWrap); memcpy(&buffer[write], data, amountTillWrap);
memcpy(buffer, data + amountTillWrap, amount - amountTillWrap); memcpy(buffer, data + amountTillWrap, amount - amountTillWrap);
} }
incrementWrite(amount); incrementWrite(amount);
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
} else { } else {
return HasReturnvaluesIF::RETURN_FAILED; return HasReturnvaluesIF::RETURN_FAILED;
} }
} }
ReturnValue_t SimpleRingBuffer::readData(uint8_t* data, size_t amount, ReturnValue_t SimpleRingBuffer::readData(uint8_t* data, size_t amount,
bool incrementReadPtr, bool readRemaining, size_t* trueAmount) { bool incrementReadPtr, bool readRemaining, size_t* trueAmount) {
size_t availableData = getAvailableReadData(READ_PTR); size_t availableData = getAvailableReadData(READ_PTR);
size_t amountTillWrap = readTillWrap(READ_PTR); size_t amountTillWrap = readTillWrap(READ_PTR);
if (availableData < amount) { if (availableData < amount) {
if (readRemaining) { if (readRemaining) {
// more data available than amount specified. // more data available than amount specified.
amount = availableData; amount = availableData;
} else { } else {
return HasReturnvaluesIF::RETURN_FAILED; return HasReturnvaluesIF::RETURN_FAILED;
} }
} }
if (trueAmount != nullptr) { if (trueAmount != nullptr) {
*trueAmount = amount; *trueAmount = amount;
} }
if (amountTillWrap >= amount) { if (amountTillWrap >= amount) {
memcpy(data, &buffer[read[READ_PTR]], amount); memcpy(data, &buffer[read[READ_PTR]], amount);
} else { } else {
memcpy(data, &buffer[read[READ_PTR]], amountTillWrap); memcpy(data, &buffer[read[READ_PTR]], amountTillWrap);
memcpy(data + amountTillWrap, buffer, amount - amountTillWrap); memcpy(data + amountTillWrap, buffer, amount - amountTillWrap);
} }
if(incrementReadPtr) { if(incrementReadPtr) {
deleteData(amount, readRemaining); deleteData(amount, readRemaining);
} }
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
} }
size_t SimpleRingBuffer::getExcessBytes() const { size_t SimpleRingBuffer::getExcessBytes() const {
@ -114,18 +114,18 @@ void SimpleRingBuffer::moveExcessBytesToStart() {
} }
ReturnValue_t SimpleRingBuffer::deleteData(size_t amount, ReturnValue_t SimpleRingBuffer::deleteData(size_t amount,
bool deleteRemaining, size_t* trueAmount) { bool deleteRemaining, size_t* trueAmount) {
size_t availableData = getAvailableReadData(READ_PTR); size_t availableData = getAvailableReadData(READ_PTR);
if (availableData < amount) { if (availableData < amount) {
if (deleteRemaining) { if (deleteRemaining) {
amount = availableData; amount = availableData;
} else { } else {
return HasReturnvaluesIF::RETURN_FAILED; return HasReturnvaluesIF::RETURN_FAILED;
} }
} }
if (trueAmount != nullptr) { if (trueAmount != nullptr) {
*trueAmount = amount; *trueAmount = amount;
} }
incrementRead(amount, READ_PTR); incrementRead(amount, READ_PTR);
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
} }

View File

@ -5,7 +5,7 @@
#include <cstddef> #include <cstddef>
/** /**
* @brief Circular buffer implementation, useful for buffering * @brief Circular buffer implementation, useful for buffering
* into data streams. * into data streams.
* @details * @details
* Note that the deleteData() has to be called to increment the read pointer. * Note that the deleteData() has to be called to increment the read pointer.
@ -25,104 +25,104 @@ public:
* with getFreeElement. * with getFreeElement.
* *
*/ */
SimpleRingBuffer(const size_t size, bool overwriteOld, SimpleRingBuffer(const size_t size, bool overwriteOld,
size_t maxExcessBytes = 0); size_t maxExcessBytes = 0);
/** /**
* This constructor takes an external buffer with the specified size. * This constructor takes an external buffer with the specified size.
* @param buffer * @param buffer
* @param size * @param size
* @param overwriteOld * @param overwriteOld
* If the ring buffer is overflowing at a write operartion, the oldest data * If the ring buffer is overflowing at a write operartion, the oldest data
* will be overwritten. * will be overwritten.
* @param maxExcessBytes * @param maxExcessBytes
* If the buffer can accomodate additional bytes for contigous write * If the buffer can accomodate additional bytes for contigous write
* operations with getFreeElement, this is the maximum allowed additional * operations with getFreeElement, this is the maximum allowed additional
* size * size
*/ */
SimpleRingBuffer(uint8_t* buffer, const size_t size, bool overwriteOld, SimpleRingBuffer(uint8_t* buffer, const size_t size, bool overwriteOld,
size_t maxExcessBytes = 0); size_t maxExcessBytes = 0);
virtual ~SimpleRingBuffer(); virtual ~SimpleRingBuffer();
/** /**
* Write to circular buffer and increment write pointer by amount. * Write to circular buffer and increment write pointer by amount.
* @param data * @param data
* @param amount * @param amount
* @return -@c RETURN_OK if write operation was successfull * @return -@c RETURN_OK if write operation was successfull
* -@c RETURN_FAILED if * -@c RETURN_FAILED if
*/ */
ReturnValue_t writeData(const uint8_t* data, size_t amount); ReturnValue_t writeData(const uint8_t* data, size_t amount);
/** /**
* Returns a pointer to a free element. If the remaining buffer is * Returns a pointer to a free element. If the remaining buffer is
* not large enough, the data will be written past the actual size * not large enough, the data will be written past the actual size
* and the amount of excess bytes will be cached. This function * and the amount of excess bytes will be cached. This function
* does not increment the write pointer! * does not increment the write pointer!
* @param writePointer Pointer to a pointer which can be used to write * @param writePointer Pointer to a pointer which can be used to write
* contiguous blocks into the ring buffer * contiguous blocks into the ring buffer
* @param amount * @param amount
* @return * @return
*/ */
ReturnValue_t getFreeElement(uint8_t** writePointer, size_t amount); ReturnValue_t getFreeElement(uint8_t** writePointer, size_t amount);
/** /**
* This increments the write pointer and also copies the excess bytes * This increments the write pointer and also copies the excess bytes
* to the beginning. It should be called if the write operation * to the beginning. It should be called if the write operation
* conducted after calling getFreeElement() was performed. * conducted after calling getFreeElement() was performed.
* @return * @return
*/ */
void confirmBytesWritten(size_t amount); void confirmBytesWritten(size_t amount);
virtual size_t getExcessBytes() const; virtual size_t getExcessBytes() const;
/** /**
* Helper functions which moves any excess bytes to the start * Helper functions which moves any excess bytes to the start
* of the ring buffer. * of the ring buffer.
* @return * @return
*/ */
virtual void moveExcessBytesToStart(); virtual void moveExcessBytesToStart();
/** /**
* Read from circular buffer at read pointer. * Read from circular buffer at read pointer.
* @param data * @param data
* @param amount * @param amount
* @param incrementReadPtr * @param incrementReadPtr
* If this is set to true, the read pointer will be incremented. * If this is set to true, the read pointer will be incremented.
* If readRemaining is set to true, the read pointer will be incremented * If readRemaining is set to true, the read pointer will be incremented
* accordingly. * accordingly.
* @param readRemaining * @param readRemaining
* If this is set to true, the data will be read even if the amount * If this is set to true, the data will be read even if the amount
* specified exceeds the read data available. * specified exceeds the read data available.
* @param trueAmount [out] * @param trueAmount [out]
* If readRemaining was set to true, the true amount read will be assigned * If readRemaining was set to true, the true amount read will be assigned
* to the passed value. * to the passed value.
* @return * @return
* - @c RETURN_OK if data was read successfully * - @c RETURN_OK if data was read successfully
* - @c RETURN_FAILED if not enough data was available and readRemaining * - @c RETURN_FAILED if not enough data was available and readRemaining
* was set to false. * was set to false.
*/ */
ReturnValue_t readData(uint8_t* data, size_t amount, ReturnValue_t readData(uint8_t* data, size_t amount,
bool incrementReadPtr = false, bool readRemaining = false, bool incrementReadPtr = false, bool readRemaining = false,
size_t* trueAmount = nullptr); size_t* trueAmount = nullptr);
/** /**
* Delete data by incrementing read pointer. * Delete data by incrementing read pointer.
* @param amount * @param amount
* @param deleteRemaining * @param deleteRemaining
* If the amount specified is larger than the remaing size to read and this * If the amount specified is larger than the remaing size to read and this
* is set to true, the remaining amount will be deleted as well * is set to true, the remaining amount will be deleted as well
* @param trueAmount [out] * @param trueAmount [out]
* If deleteRemaining was set to true, the amount deleted will be assigned * If deleteRemaining was set to true, the amount deleted will be assigned
* to the passed value. * to the passed value.
* @return * @return
*/ */
ReturnValue_t deleteData(size_t amount, bool deleteRemaining = false, ReturnValue_t deleteData(size_t amount, bool deleteRemaining = false,
size_t* trueAmount = nullptr); size_t* trueAmount = nullptr);
private: private:
static const uint8_t READ_PTR = 0; static const uint8_t READ_PTR = 0;
uint8_t* buffer = nullptr; uint8_t* buffer = nullptr;
size_t maxExcessBytes; size_t maxExcessBytes;
size_t excessBytes = 0; size_t excessBytes = 0;
}; };
#endif /* FSFW_CONTAINER_SIMPLERINGBUFFER_H_ */ #endif /* FSFW_CONTAINER_SIMPLERINGBUFFER_H_ */

View File

@ -5,71 +5,71 @@
#include <cstdint> #include <cstdint>
/** /**
* @brief Linked list data structure, * @brief Linked list data structure,
* each entry has a pointer to the next entry (singly) * each entry has a pointer to the next entry (singly)
* @ingroup container * @ingroup container
*/ */
template<typename T> template<typename T>
class LinkedElement { class LinkedElement {
public: public:
T *value; T *value;
class Iterator { class Iterator {
public: public:
LinkedElement<T> *value = nullptr; LinkedElement<T> *value = nullptr;
Iterator() {} Iterator() {}
Iterator(LinkedElement<T> *element) : Iterator(LinkedElement<T> *element) :
value(element) { value(element) {
} }
Iterator& operator++() { Iterator& operator++() {
value = value->getNext(); value = value->getNext();
return *this; return *this;
} }
Iterator operator++(int) { Iterator operator++(int) {
Iterator tmp(*this); Iterator tmp(*this);
operator++(); operator++();
return tmp; return tmp;
} }
bool operator==(Iterator other) { bool operator==(Iterator other) {
return value == other.value; return value == other.value;
} }
bool operator!=(Iterator other) { bool operator!=(Iterator other) {
return !(*this == other); return !(*this == other);
} }
T *operator->() { T *operator->() {
return value->value; return value->value;
} }
}; };
LinkedElement(T* setElement, LinkedElement<T>* setNext = nullptr): LinkedElement(T* setElement, LinkedElement<T>* setNext = nullptr):
value(setElement), next(setNext) {} value(setElement), next(setNext) {}
virtual ~LinkedElement(){} virtual ~LinkedElement(){}
virtual LinkedElement* getNext() const { virtual LinkedElement* getNext() const {
return next; return next;
} }
virtual void setNext(LinkedElement* next) { virtual void setNext(LinkedElement* next) {
this->next = next; this->next = next;
} }
virtual void setEnd() { virtual void setEnd() {
this->next = nullptr; this->next = nullptr;
} }
LinkedElement* begin() { LinkedElement* begin() {
return this; return this;
} }
LinkedElement* end() { LinkedElement* end() {
return nullptr; return nullptr;
} }
private: private:
LinkedElement *next; LinkedElement *next;
}; };
template<typename T> template<typename T>
@ -77,52 +77,52 @@ class SinglyLinkedList {
public: public:
using ElementIterator = typename LinkedElement<T>::Iterator; using ElementIterator = typename LinkedElement<T>::Iterator;
SinglyLinkedList() {} SinglyLinkedList() {}
SinglyLinkedList(ElementIterator start) : SinglyLinkedList(ElementIterator start) :
start(start.value) {} start(start.value) {}
SinglyLinkedList(LinkedElement<T>* startElement) : SinglyLinkedList(LinkedElement<T>* startElement) :
start(startElement) {} start(startElement) {}
ElementIterator begin() const { ElementIterator begin() const {
return ElementIterator::Iterator(start); return ElementIterator::Iterator(start);
} }
/** Returns iterator to nulltr */ /** Returns iterator to nulltr */
ElementIterator end() const { ElementIterator end() const {
return ElementIterator::Iterator(); return ElementIterator::Iterator();
} }
/** /**
* Returns last element in singly linked list. * Returns last element in singly linked list.
* @return * @return
*/ */
ElementIterator back() const { ElementIterator back() const {
LinkedElement<T> *element = start; LinkedElement<T> *element = start;
while (element->getNext() != nullptr) { while (element->getNext() != nullptr) {
element = element->getNext(); element = element->getNext();
} }
return ElementIterator::Iterator(element); return ElementIterator::Iterator(element);
} }
size_t getSize() const { size_t getSize() const {
size_t size = 0; size_t size = 0;
LinkedElement<T> *element = start; LinkedElement<T> *element = start;
while (element != nullptr) { while (element != nullptr) {
size++; size++;
element = element->getNext(); element = element->getNext();
} }
return size; return size;
} }
void setStart(LinkedElement<T>* firstElement) { void setStart(LinkedElement<T>* firstElement) {
start = firstElement; start = firstElement;
} }
void setNext(LinkedElement<T>* currentElement, void setNext(LinkedElement<T>* currentElement,
LinkedElement<T>* nextElement) { LinkedElement<T>* nextElement) {
currentElement->setNext(nextElement); currentElement->setNext(nextElement);
} }
void setLast(LinkedElement<T>* lastElement) { void setLast(LinkedElement<T>* lastElement) {
lastElement->setEnd(); lastElement->setEnd();
@ -148,7 +148,7 @@ public:
} }
protected: protected:
LinkedElement<T> *start = nullptr; LinkedElement<T> *start = nullptr;
}; };
#endif /* SINGLYLINKEDLIST_H_ */ #endif /* SINGLYLINKEDLIST_H_ */

View File

@ -1,4 +1,4 @@
target_sources(${LIB_FSFW_NAME} target_sources(${LIB_FSFW_NAME}
PRIVATE PRIVATE
ControllerBase.cpp ControllerBase.cpp
) )

View File

@ -5,128 +5,128 @@
#include "../action/HasActionsIF.h" #include "../action/HasActionsIF.h"
ControllerBase::ControllerBase(object_id_t setObjectId, object_id_t parentId, ControllerBase::ControllerBase(object_id_t setObjectId, object_id_t parentId,
size_t commandQueueDepth) : size_t commandQueueDepth) :
SystemObject(setObjectId), parentId(parentId), mode(MODE_OFF), SystemObject(setObjectId), parentId(parentId), mode(MODE_OFF),
submode(SUBMODE_NONE), modeHelper(this), submode(SUBMODE_NONE), modeHelper(this),
healthHelper(this, setObjectId) { healthHelper(this, setObjectId) {
commandQueue = QueueFactory::instance()->createMessageQueue( commandQueue = QueueFactory::instance()->createMessageQueue(
commandQueueDepth); commandQueueDepth);
} }
ControllerBase::~ControllerBase() { ControllerBase::~ControllerBase() {
QueueFactory::instance()->deleteMessageQueue(commandQueue); QueueFactory::instance()->deleteMessageQueue(commandQueue);
} }
ReturnValue_t ControllerBase::initialize() { ReturnValue_t ControllerBase::initialize() {
ReturnValue_t result = SystemObject::initialize(); ReturnValue_t result = SystemObject::initialize();
if (result != RETURN_OK) { if (result != RETURN_OK) {
return result; return result;
} }
MessageQueueId_t parentQueue = 0; MessageQueueId_t parentQueue = 0;
if (parentId != objects::NO_OBJECT) { if (parentId != objects::NO_OBJECT) {
SubsystemBase *parent = objectManager->get<SubsystemBase>(parentId); SubsystemBase *parent = objectManager->get<SubsystemBase>(parentId);
if (parent == nullptr) { if (parent == nullptr) {
return RETURN_FAILED; return RETURN_FAILED;
} }
parentQueue = parent->getCommandQueue(); parentQueue = parent->getCommandQueue();
parent->registerChild(getObjectId()); parent->registerChild(getObjectId());
} }
result = healthHelper.initialize(parentQueue); result = healthHelper.initialize(parentQueue);
if (result != RETURN_OK) { if (result != RETURN_OK) {
return result; return result;
} }
result = modeHelper.initialize(parentQueue); result = modeHelper.initialize(parentQueue);
if (result != RETURN_OK) { if (result != RETURN_OK) {
return result; return result;
} }
return RETURN_OK; return RETURN_OK;
} }
MessageQueueId_t ControllerBase::getCommandQueue() const { MessageQueueId_t ControllerBase::getCommandQueue() const {
return commandQueue->getId(); return commandQueue->getId();
} }
void ControllerBase::handleQueue() { void ControllerBase::handleQueue() {
CommandMessage command; CommandMessage command;
ReturnValue_t result = HasReturnvaluesIF::RETURN_OK; ReturnValue_t result = HasReturnvaluesIF::RETURN_OK;
for (result = commandQueue->receiveMessage(&command); for (result = commandQueue->receiveMessage(&command);
result == RETURN_OK; result == RETURN_OK;
result = commandQueue->receiveMessage(&command)) { result = commandQueue->receiveMessage(&command)) {
result = modeHelper.handleModeCommand(&command); result = modeHelper.handleModeCommand(&command);
if (result == RETURN_OK) { if (result == RETURN_OK) {
continue; continue;
} }
result = healthHelper.handleHealthCommand(&command); result = healthHelper.handleHealthCommand(&command);
if (result == RETURN_OK) { if (result == RETURN_OK) {
continue; continue;
} }
result = handleCommandMessage(&command); result = handleCommandMessage(&command);
if (result == RETURN_OK) { if (result == RETURN_OK) {
continue; continue;
} }
command.setToUnknownCommand(); command.setToUnknownCommand();
commandQueue->reply(&command); commandQueue->reply(&command);
} }
} }
void ControllerBase::startTransition(Mode_t mode, Submode_t submode) { void ControllerBase::startTransition(Mode_t mode, Submode_t submode) {
changeHK(this->mode, this->submode, false); changeHK(this->mode, this->submode, false);
triggerEvent(CHANGING_MODE, mode, submode); triggerEvent(CHANGING_MODE, mode, submode);
this->mode = mode; this->mode = mode;
this->submode = submode; this->submode = submode;
modeHelper.modeChanged(mode, submode); modeHelper.modeChanged(mode, submode);
modeChanged(mode, submode); modeChanged(mode, submode);
announceMode(false); announceMode(false);
changeHK(this->mode, this->submode, true); changeHK(this->mode, this->submode, true);
} }
void ControllerBase::getMode(Mode_t* mode, Submode_t* submode) { void ControllerBase::getMode(Mode_t* mode, Submode_t* submode) {
*mode = this->mode; *mode = this->mode;
*submode = this->submode; *submode = this->submode;
} }
void ControllerBase::setToExternalControl() { void ControllerBase::setToExternalControl() {
healthHelper.setHealth(EXTERNAL_CONTROL); healthHelper.setHealth(EXTERNAL_CONTROL);
} }
void ControllerBase::announceMode(bool recursive) { void ControllerBase::announceMode(bool recursive) {
triggerEvent(MODE_INFO, mode, submode); triggerEvent(MODE_INFO, mode, submode);
} }
ReturnValue_t ControllerBase::performOperation(uint8_t opCode) { ReturnValue_t ControllerBase::performOperation(uint8_t opCode) {
handleQueue(); handleQueue();
performControlOperation(); performControlOperation();
return RETURN_OK; return RETURN_OK;
} }
void ControllerBase::modeChanged(Mode_t mode, Submode_t submode) { void ControllerBase::modeChanged(Mode_t mode, Submode_t submode) {
return; return;
} }
ReturnValue_t ControllerBase::setHealth(HealthState health) { ReturnValue_t ControllerBase::setHealth(HealthState health) {
switch (health) { switch (health) {
case HEALTHY: case HEALTHY:
case EXTERNAL_CONTROL: case EXTERNAL_CONTROL:
healthHelper.setHealth(health); healthHelper.setHealth(health);
return RETURN_OK; return RETURN_OK;
default: default:
return INVALID_HEALTH_STATE; return INVALID_HEALTH_STATE;
} }
} }
HasHealthIF::HealthState ControllerBase::getHealth() { HasHealthIF::HealthState ControllerBase::getHealth() {
return healthHelper.getHealth(); return healthHelper.getHealth();
} }
void ControllerBase::setTaskIF(PeriodicTaskIF* task_){ void ControllerBase::setTaskIF(PeriodicTaskIF* task_){
executingTask = task_; executingTask = task_;
} }
void ControllerBase::changeHK(Mode_t mode, Submode_t submode, bool enable) { void ControllerBase::changeHK(Mode_t mode, Submode_t submode, bool enable) {

View File

@ -17,39 +17,39 @@
* a mode and a health state. This avoids boilerplate code. * a mode and a health state. This avoids boilerplate code.
*/ */
class ControllerBase: public HasModesIF, class ControllerBase: public HasModesIF,
public HasHealthIF, public HasHealthIF,
public ExecutableObjectIF, public ExecutableObjectIF,
public SystemObject, public SystemObject,
public HasReturnvaluesIF { public HasReturnvaluesIF {
public: public:
static const Mode_t MODE_NORMAL = 2; static const Mode_t MODE_NORMAL = 2;
ControllerBase(object_id_t setObjectId, object_id_t parentId, ControllerBase(object_id_t setObjectId, object_id_t parentId,
size_t commandQueueDepth = 3); size_t commandQueueDepth = 3);
virtual ~ControllerBase(); virtual ~ControllerBase();
/** SystemObject override */ /** SystemObject override */
virtual ReturnValue_t initialize() override; virtual ReturnValue_t initialize() override;
virtual MessageQueueId_t getCommandQueue() const override; virtual MessageQueueId_t getCommandQueue() const override;
/** HasHealthIF overrides */ /** HasHealthIF overrides */
virtual ReturnValue_t setHealth(HealthState health) override; virtual ReturnValue_t setHealth(HealthState health) override;
virtual HasHealthIF::HealthState getHealth() override; virtual HasHealthIF::HealthState getHealth() override;
/** ExecutableObjectIF overrides */ /** ExecutableObjectIF overrides */
virtual ReturnValue_t performOperation(uint8_t opCode) override; virtual ReturnValue_t performOperation(uint8_t opCode) override;
virtual void setTaskIF(PeriodicTaskIF* task) override; virtual void setTaskIF(PeriodicTaskIF* task) override;
virtual ReturnValue_t initializeAfterTaskCreation() override; virtual ReturnValue_t initializeAfterTaskCreation() override;
protected: protected:
/** /**
* Implemented by child class. Handle command messages which are not * Implemented by child class. Handle command messages which are not
* mode or health messages. * mode or health messages.
* @param message * @param message
* @return * @return
*/ */
virtual ReturnValue_t handleCommandMessage(CommandMessage *message) = 0; virtual ReturnValue_t handleCommandMessage(CommandMessage *message) = 0;
/** /**
@ -60,35 +60,35 @@ protected:
virtual ReturnValue_t checkModeCommand(Mode_t mode, Submode_t submode, virtual ReturnValue_t checkModeCommand(Mode_t mode, Submode_t submode,
uint32_t *msToReachTheMode) = 0; uint32_t *msToReachTheMode) = 0;
const object_id_t parentId; const object_id_t parentId;
Mode_t mode; Mode_t mode;
Submode_t submode; Submode_t submode;
MessageQueueIF* commandQueue = nullptr; MessageQueueIF* commandQueue = nullptr;
ModeHelper modeHelper; ModeHelper modeHelper;
HealthHelper healthHelper; HealthHelper healthHelper;
/** /**
* Pointer to the task which executes this component, * Pointer to the task which executes this component,
* is invalid before setTaskIF was called. * is invalid before setTaskIF was called.
*/ */
PeriodicTaskIF* executingTask = nullptr; PeriodicTaskIF* executingTask = nullptr;
/** Handle mode and health messages */ /** Handle mode and health messages */
virtual void handleQueue(); virtual void handleQueue();
/** Mode helpers */ /** Mode helpers */
virtual void modeChanged(Mode_t mode, Submode_t submode); virtual void modeChanged(Mode_t mode, Submode_t submode);
virtual void startTransition(Mode_t mode, Submode_t submode); virtual void startTransition(Mode_t mode, Submode_t submode);
virtual void getMode(Mode_t *mode, Submode_t *submode); virtual void getMode(Mode_t *mode, Submode_t *submode);
virtual void setToExternalControl(); virtual void setToExternalControl();
virtual void announceMode(bool recursive); virtual void announceMode(bool recursive);
/** HK helpers */ /** HK helpers */
virtual void changeHK(Mode_t mode, Submode_t submode, bool enable); virtual void changeHK(Mode_t mode, Submode_t submode, bool enable);
}; };
#endif /* FSFW_CONTROLLER_CONTROLLERBASE_H_ */ #endif /* FSFW_CONTROLLER_CONTROLLERBASE_H_ */

View File

@ -18,7 +18,7 @@ public:
* This function is protected because it should only be used by the * This function is protected because it should only be used by the
* class imlementing the interface. * class imlementing the interface.
*/ */
virtual LocalDataPoolManager* getHkManagerHandle() = 0; virtual LocalDataPoolManager* getPoolManagerHandle() = 0;
protected: protected:

View File

@ -5,8 +5,8 @@
#include "internal/LocalPoolDataSetAttorney.h" #include "internal/LocalPoolDataSetAttorney.h"
#include "internal/HasLocalDpIFManagerAttorney.h" #include "internal/HasLocalDpIFManagerAttorney.h"
#include "../housekeeping/HousekeepingPacketUpdate.h"
#include "../housekeeping/HousekeepingSetPacket.h" #include "../housekeeping/HousekeepingSetPacket.h"
#include "../housekeeping/HousekeepingSnapshot.h"
#include "../housekeeping/AcceptsHkPacketsIF.h" #include "../housekeeping/AcceptsHkPacketsIF.h"
#include "../timemanager/CCSDSTime.h" #include "../timemanager/CCSDSTime.h"
#include "../ipc/MutexFactory.h" #include "../ipc/MutexFactory.h"
@ -226,7 +226,7 @@ ReturnValue_t LocalDataPoolManager::handleNotificationSnapshot(
Clock::getClock_timeval(&now); Clock::getClock_timeval(&now);
CCSDSTime::CDS_short cds; CCSDSTime::CDS_short cds;
CCSDSTime::convertToCcsds(&cds, &now); CCSDSTime::convertToCcsds(&cds, &now);
HousekeepingPacketUpdate updatePacket(reinterpret_cast<uint8_t*>(&cds), HousekeepingSnapshot updatePacket(reinterpret_cast<uint8_t*>(&cds),
sizeof(cds), HasLocalDpIFManagerAttorney::getPoolObjectHandle(owner, sizeof(cds), HasLocalDpIFManagerAttorney::getPoolObjectHandle(owner,
receiver.dataId.localPoolId)); receiver.dataId.localPoolId));
@ -264,7 +264,7 @@ ReturnValue_t LocalDataPoolManager::handleNotificationSnapshot(
Clock::getClock_timeval(&now); Clock::getClock_timeval(&now);
CCSDSTime::CDS_short cds; CCSDSTime::CDS_short cds;
CCSDSTime::convertToCcsds(&cds, &now); CCSDSTime::convertToCcsds(&cds, &now);
HousekeepingPacketUpdate updatePacket(reinterpret_cast<uint8_t*>(&cds), HousekeepingSnapshot updatePacket(reinterpret_cast<uint8_t*>(&cds),
sizeof(cds), HasLocalDpIFManagerAttorney::getDataSetHandle(owner, sizeof(cds), HasLocalDpIFManagerAttorney::getDataSetHandle(owner,
receiver.dataId.sid)); receiver.dataId.sid));
@ -292,7 +292,7 @@ ReturnValue_t LocalDataPoolManager::handleNotificationSnapshot(
} }
ReturnValue_t LocalDataPoolManager::addUpdateToStore( ReturnValue_t LocalDataPoolManager::addUpdateToStore(
HousekeepingPacketUpdate& updatePacket, store_address_t& storeId) { HousekeepingSnapshot& updatePacket, store_address_t& storeId) {
size_t updatePacketSize = updatePacket.getSerializedSize(); size_t updatePacketSize = updatePacket.getSerializedSize();
uint8_t *storePtr = nullptr; uint8_t *storePtr = nullptr;
ReturnValue_t result = ipcStore->getFreeElement(&storeId, ReturnValue_t result = ipcStore->getFreeElement(&storeId,
@ -890,7 +890,7 @@ void LocalDataPoolManager::printWarningOrError(sif::OutputTypes outputType,
<< std::dec << std::setfill(' ') << std::endl; << std::dec << std::setfill(' ') << std::endl;
#else #else
sif::printWarning("LocalDataPoolManager::%s: Object ID 0x%08x | %s\n", sif::printWarning("LocalDataPoolManager::%s: Object ID 0x%08x | %s\n",
owner->getObjectId(), errorPrint); functionName, owner->getObjectId(), errorPrint);
#endif #endif
} }
else if(outputType == sif::OutputTypes::OUT_ERROR) { else if(outputType == sif::OutputTypes::OUT_ERROR) {
@ -901,11 +901,11 @@ void LocalDataPoolManager::printWarningOrError(sif::OutputTypes outputType,
<< std::dec << std::setfill(' ') << std::endl; << std::dec << std::setfill(' ') << std::endl;
#else #else
sif::printError("LocalDataPoolManager::%s: Object ID 0x%08x | %s\n", sif::printError("LocalDataPoolManager::%s: Object ID 0x%08x | %s\n",
owner->getObjectId(), errorPrint); functionName, owner->getObjectId(), errorPrint);
#endif #endif
} }
} }
LocalDataPoolManager* LocalDataPoolManager::getHkManagerHandle() { LocalDataPoolManager* LocalDataPoolManager::getPoolManagerHandle() {
return this; return this;
} }

View File

@ -24,7 +24,7 @@ void setStaticFrameworkObjectIds();
} }
class LocalPoolDataSetBase; class LocalPoolDataSetBase;
class HousekeepingPacketUpdate; class HousekeepingSnapshot;
class HasLocalDataPoolIF; class HasLocalDataPoolIF;
class LocalDataPool; class LocalDataPool;
@ -52,17 +52,17 @@ class LocalDataPool;
* Each pool entry has a valid state too. * Each pool entry has a valid state too.
* @author R. Mueller * @author R. Mueller
*/ */
class LocalDataPoolManager: public ProvidesDataPoolSubscriptionIF, class LocalDataPoolManager:
public AccessPoolManagerIF { public ProvidesDataPoolSubscriptionIF,
friend void (Factory::setStaticFrameworkObjectIds)(); public AccessPoolManagerIF {
//! Some classes using the pool manager directly need to access class internals of the friend void (Factory::setStaticFrameworkObjectIds)();
//! manager. The attorney provides granular control of access to these internals. //! Some classes using the pool manager directly need to access class internals of the
friend class LocalDpManagerAttorney; //! manager. The attorney provides granular control of access to these internals.
friend class LocalDpManagerAttorney;
public: public:
static constexpr uint8_t INTERFACE_ID = CLASS_ID::HOUSEKEEPING_MANAGER; static constexpr uint8_t INTERFACE_ID = CLASS_ID::HOUSEKEEPING_MANAGER;
static constexpr ReturnValue_t QUEUE_OR_DESTINATION_INVALID = MAKE_RETURN_CODE(0); static constexpr ReturnValue_t QUEUE_OR_DESTINATION_INVALID = MAKE_RETURN_CODE(0);
static constexpr ReturnValue_t WRONG_HK_PACKET_TYPE = MAKE_RETURN_CODE(1); static constexpr ReturnValue_t WRONG_HK_PACKET_TYPE = MAKE_RETURN_CODE(1);
static constexpr ReturnValue_t REPORTING_STATUS_UNCHANGED = MAKE_RETURN_CODE(2); static constexpr ReturnValue_t REPORTING_STATUS_UNCHANGED = MAKE_RETURN_CODE(2);
static constexpr ReturnValue_t PERIODIC_HELPER_INVALID = MAKE_RETURN_CODE(3); static constexpr ReturnValue_t PERIODIC_HELPER_INVALID = MAKE_RETURN_CODE(3);
@ -81,29 +81,29 @@ public:
* @param appendValidityBuffer Specify whether a buffer containing the * @param appendValidityBuffer Specify whether a buffer containing the
* validity state is generated when serializing or deserializing packets. * validity state is generated when serializing or deserializing packets.
*/ */
LocalDataPoolManager(HasLocalDataPoolIF* owner, MessageQueueIF* queueToUse, LocalDataPoolManager(HasLocalDataPoolIF* owner, MessageQueueIF* queueToUse,
bool appendValidityBuffer = true); bool appendValidityBuffer = true);
virtual~ LocalDataPoolManager(); virtual~ LocalDataPoolManager();
/** /**
* Assigns the queue to use. Make sure to call this in the #initialize * Assigns the queue to use. Make sure to call this in the #initialize
* function of the owner. * function of the owner.
* @param queueToUse * @param queueToUse
* @param nonDiagInvlFactor See #setNonDiagnosticIntervalFactor doc * @param nonDiagInvlFactor See #setNonDiagnosticIntervalFactor doc
* @return * @return
*/ */
ReturnValue_t initialize(MessageQueueIF* queueToUse); ReturnValue_t initialize(MessageQueueIF* queueToUse);
/** /**
* Initializes the map by calling the map initialization function and * Initializes the map by calling the map initialization function and
* setting the periodic factor for non-diagnostic packets. * setting the periodic factor for non-diagnostic packets.
* Don't forget to call this in the #initializeAfterTaskCreation call of * Don't forget to call this in the #initializeAfterTaskCreation call of
* the owner, otherwise the map will be invalid! * the owner, otherwise the map will be invalid!
* @param nonDiagInvlFactor * @param nonDiagInvlFactor
* @return * @return
*/ */
ReturnValue_t initializeAfterTaskCreation( ReturnValue_t initializeAfterTaskCreation(
uint8_t nonDiagInvlFactor = 5); uint8_t nonDiagInvlFactor = 5);
/** /**
* @brief This should be called in the periodic handler of the owner. * @brief This should be called in the periodic handler of the owner.
@ -116,49 +116,49 @@ public:
*/ */
virtual ReturnValue_t performHkOperation(); virtual ReturnValue_t performHkOperation();
/** /**
* @brief Subscribe for the generation of periodic packets. * @brief Subscribe for the generation of periodic packets.
* @details * @details
* This subscription mechanism will generally be used by the data creator * This subscription mechanism will generally be used by the data creator
* to generate housekeeping packets which are downlinked directly. * to generate housekeeping packets which are downlinked directly.
* @return * @return
*/ */
ReturnValue_t subscribeForPeriodicPacket(sid_t sid, bool enableReporting, ReturnValue_t subscribeForPeriodicPacket(sid_t sid, bool enableReporting,
float collectionInterval, bool isDiagnostics, float collectionInterval, bool isDiagnostics,
object_id_t packetDestination = defaultHkDestination) override; object_id_t packetDestination = defaultHkDestination) override;
/** /**
* @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.
* @details * @details
* This subscription mechanism will generally be used by the data creator. * This subscription mechanism will generally be used by the data creator.
* @param sid * @param sid
* @param isDiagnostics * @param isDiagnostics
* @param packetDestination * @param packetDestination
* @return * @return
*/ */
ReturnValue_t subscribeForUpdatePackets(sid_t sid, bool reportingEnabled, ReturnValue_t subscribeForUpdatePackets(sid_t sid, bool reportingEnabled,
bool isDiagnostics, bool isDiagnostics,
object_id_t packetDestination = defaultHkDestination) override; object_id_t packetDestination = defaultHkDestination) override;
/** /**
* @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.
* @details * @details
* This subscription mechanism will generally be used internally by * This subscription mechanism will generally be used internally by
* other software components. * other software components.
* @param setId Set ID of the set to receive update messages from. * @param setId Set ID of the set to receive update messages from.
* @param destinationObject * @param destinationObject
* @param targetQueueId * @param targetQueueId
* @param generateSnapshot If this is set to true, a copy of the current * @param generateSnapshot If this is set to true, a copy of the current
* data with a timestamp will be generated and sent via message. * data with a timestamp will be generated and sent via message.
* 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 subscribeForSetUpdateMessages(const uint32_t setId,
object_id_t destinationObject, object_id_t destinationObject,
MessageQueueId_t targetQueueId, MessageQueueId_t targetQueueId,
bool generateSnapshot) override; bool generateSnapshot) override;
/** /**
* @brief Subscribe for an notification message which will be sent if a * @brief Subscribe for an notification message which will be sent if a
@ -179,18 +179,16 @@ public:
MessageQueueId_t targetQueueId, MessageQueueId_t targetQueueId,
bool generateSnapshot) override; bool generateSnapshot) override;
MutexIF* getLocalPoolMutex() override; /**
* Non-Diagnostics packets usually have a lower minimum sampling frequency
/** * than diagnostic packets.
* Non-Diagnostics packets usually have a lower minimum sampling frequency * A factor can be specified to determine the minimum sampling frequency
* than diagnostic packets. * for non-diagnostic packets. The minimum sampling frequency of the
* A factor can be specified to determine the minimum sampling frequency * diagnostics packets,which is usually jusst the period of the
* for non-diagnostic packets. The minimum sampling frequency of the * performOperation calls, is multiplied with that factor.
* diagnostics packets,which is usually jusst the period of the * @param factor
* performOperation calls, is multiplied with that factor. */
* @param factor void setNonDiagnosticIntervalFactor(uint8_t nonDiagInvlFactor);
*/
void setNonDiagnosticIntervalFactor(uint8_t nonDiagInvlFactor);
/** /**
* @brief The manager is also able to handle housekeeping messages. * @brief The manager is also able to handle housekeeping messages.
@ -206,18 +204,18 @@ public:
*/ */
virtual ReturnValue_t handleHousekeepingMessage(CommandMessage* message); virtual ReturnValue_t handleHousekeepingMessage(CommandMessage* message);
/** /**
* Generate a housekeeping packet with a given SID. * Generate a housekeeping packet with a given SID.
* @param sid * @param sid
* @return * @return
*/ */
ReturnValue_t generateHousekeepingPacket(sid_t sid, ReturnValue_t generateHousekeepingPacket(sid_t sid,
LocalPoolDataSetBase* dataSet, bool forDownlink, LocalPoolDataSetBase* dataSet, bool forDownlink,
MessageQueueId_t destination = MessageQueueIF::NO_QUEUE); MessageQueueId_t destination = MessageQueueIF::NO_QUEUE);
HasLocalDataPoolIF* getOwner(); HasLocalDataPoolIF* getOwner();
ReturnValue_t printPoolEntry(lp_id_t localPoolId); ReturnValue_t printPoolEntry(lp_id_t localPoolId);
/** /**
* Different types of housekeeping reporting are possible. * Different types of housekeeping reporting are possible.
@ -236,22 +234,19 @@ public:
PERIODIC, PERIODIC,
//! Housekeeping packet will be generated if values have changed. //! Housekeeping packet will be generated if values have changed.
UPDATE_HK, UPDATE_HK,
//! Update notification will be sent out as message. //! Update notification will be sent out as message.
UPDATE_NOTIFICATION, UPDATE_NOTIFICATION,
//! Notification will be sent out as message and a snapshot of the //! Notification will be sent out as message and a snapshot of the
//! current data will be generated. //! current data will be generated.
UPDATE_SNAPSHOT, UPDATE_SNAPSHOT,
}; };
/** /** Different data types are possible in the HK receiver map. For example, updates can be
* Different data types are possible in the HK receiver map. requested for full datasets or for single pool variables. Periodic reporting is only possible
* For example, updates can be requested for full datasets or for data sets. */
* for single pool variables. Periodic reporting is only possible for
* data sets.
*/
enum class DataType: uint8_t { enum class DataType: uint8_t {
LOCAL_POOL_VARIABLE, LOCAL_POOL_VARIABLE,
DATA_SET DATA_SET
}; };
/* Copying forbidden */ /* Copying forbidden */
@ -267,11 +262,19 @@ public:
object_id_t getCreatorObjectId() const; object_id_t getCreatorObjectId() const;
virtual LocalDataPoolManager* getHkManagerHandle() override; /**
* Get the pointer to the mutex. Can be used to lock the data pool
* externally. Use with care and don't forget to unlock locked mutexes!
* For now, only friend classes can accss this function.
* @return
*/
MutexIF* getMutexHandle();
virtual LocalDataPoolManager* getPoolManagerHandle() override;
private: private:
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. */
MutexIF* mutex = nullptr; MutexIF* mutex = nullptr;
/** The class which actually owns the manager (and its datapool). */ /** The class which actually owns the manager (and its datapool). */
@ -279,9 +282,9 @@ private:
uint8_t nonDiagnosticIntervalFactor = 0; uint8_t nonDiagnosticIntervalFactor = 0;
/** Default receiver for periodic HK packets */ /** Default receiver for periodic HK packets */
static object_id_t defaultHkDestination; static object_id_t defaultHkDestination;
MessageQueueId_t hkDestinationId = MessageQueueIF::NO_QUEUE; MessageQueueId_t hkDestinationId = MessageQueueIF::NO_QUEUE;
union DataId { union DataId {
DataId(): sid() {}; DataId(): sid() {};
@ -291,10 +294,10 @@ private:
/** The data pool manager will keep an internal map of HK receivers. */ /** The data pool manager will keep an internal map of HK receivers. */
struct HkReceiver { struct HkReceiver {
/** Object ID of receiver */ /** Object ID of receiver */
object_id_t objectId = objects::NO_OBJECT; object_id_t objectId = objects::NO_OBJECT;
DataType dataType = DataType::DATA_SET; DataType dataType = DataType::DATA_SET;
DataId dataId; DataId dataId;
ReportingType reportingType = ReportingType::PERIODIC; ReportingType reportingType = ReportingType::PERIODIC;
@ -324,37 +327,30 @@ private:
* of generated housekeeping packets. */ * of generated housekeeping packets. */
bool appendValidityBuffer = true; bool appendValidityBuffer = true;
/** /**
* @brief Queue used for communication, for example commands. * @brief Queue used for communication, for example commands.
* Is also used to send messages. Can be set either in the constructor * Is also used to send messages. Can be set either in the constructor
* or in the initialize() function. * or in the initialize() function.
*/ */
MessageQueueIF* hkQueue = nullptr; MessageQueueIF* hkQueue = nullptr;
/** Global IPC store is used to store all packets. */ /** Global IPC store is used to store all packets. */
StorageManagerIF* ipcStore = nullptr; StorageManagerIF* ipcStore = nullptr;
/**
* Get the pointer to the mutex. Can be used to lock the data pool
* externally. Use with care and don't forget to unlock locked mutexes!
* For now, only friend classes can accss this function.
* @return
*/
MutexIF* getMutexHandle();
/** /**
* 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 friend classes like LocalPoolVar may access 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
@ -364,55 +360,57 @@ private:
*/ */
ReturnValue_t initializeHousekeepingPoolEntriesOnce(); ReturnValue_t initializeHousekeepingPoolEntriesOnce();
ReturnValue_t serializeHkPacketIntoStore( MutexIF* getLocalPoolMutex() override;
HousekeepingPacketDownlink& hkPacket,
store_address_t& storeId, bool forDownlink, size_t* serializedSize);
void performPeriodicHkGeneration(HkReceiver& hkReceiver); ReturnValue_t serializeHkPacketIntoStore(
ReturnValue_t togglePeriodicGeneration(sid_t sid, bool enable, HousekeepingPacketDownlink& hkPacket,
bool isDiagnostics); store_address_t& storeId, bool forDownlink, size_t* serializedSize);
ReturnValue_t changeCollectionInterval(sid_t sid,
float newCollectionInterval, bool isDiagnostics);
ReturnValue_t generateSetStructurePacket(sid_t sid, bool isDiagnostics);
void handleHkUpdateResetListInsertion(DataType dataType, DataId dataId); void performPeriodicHkGeneration(HkReceiver& hkReceiver);
void handleChangeResetLogic(DataType type, ReturnValue_t togglePeriodicGeneration(sid_t sid, bool enable,
DataId dataId, MarkChangedIF* toReset); bool isDiagnostics);
void resetHkUpdateResetHelper(); ReturnValue_t changeCollectionInterval(sid_t sid,
float newCollectionInterval, bool isDiagnostics);
ReturnValue_t generateSetStructurePacket(sid_t sid, bool isDiagnostics);
ReturnValue_t handleHkUpdate(HkReceiver& hkReceiver, void handleHkUpdateResetListInsertion(DataType dataType, DataId dataId);
void handleChangeResetLogic(DataType type,
DataId dataId, MarkChangedIF* toReset);
void resetHkUpdateResetHelper();
ReturnValue_t handleHkUpdate(HkReceiver& hkReceiver,
ReturnValue_t& status); ReturnValue_t& status);
ReturnValue_t handleNotificationUpdate(HkReceiver& hkReceiver, ReturnValue_t handleNotificationUpdate(HkReceiver& hkReceiver,
ReturnValue_t& status);
ReturnValue_t handleNotificationSnapshot(HkReceiver& hkReceiver,
ReturnValue_t& status); ReturnValue_t& status);
ReturnValue_t addUpdateToStore(HousekeepingPacketUpdate& updatePacket, ReturnValue_t handleNotificationSnapshot(HkReceiver& hkReceiver,
store_address_t& storeId); 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_ERROR, "fetchPoolEntry", printWarningOrError(sif::OutputTypes::OUT_WARNING, "fetchPoolEntry",
localpool::POOL_ENTRY_NOT_FOUND); localpool::POOL_ENTRY_NOT_FOUND);
return localpool::POOL_ENTRY_NOT_FOUND; return localpool::POOL_ENTRY_NOT_FOUND;
} }
*poolEntry = dynamic_cast< PoolEntry<T>* >(poolIter->second); *poolEntry = dynamic_cast< PoolEntry<T>* >(poolIter->second);
if(*poolEntry == nullptr) { if(*poolEntry == nullptr) {
printWarningOrError(sif::OutputTypes::OUT_ERROR, "fetchPoolEntry", printWarningOrError(sif::OutputTypes::OUT_WARNING, "fetchPoolEntry",
localpool::POOL_ENTRY_TYPE_CONFLICT); localpool::POOL_ENTRY_TYPE_CONFLICT);
return localpool::POOL_ENTRY_TYPE_CONFLICT; return localpool::POOL_ENTRY_TYPE_CONFLICT;
} }
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
} }

View File

@ -4,11 +4,26 @@
#include "LocalPoolDataSetBase.h" #include "LocalPoolDataSetBase.h"
#include <vector> #include <vector>
/**
* @brief This dataset type can be used to group related pool variables if the number of
* variables should not be fixed.
* @details
* This will is the primary data structure to organize pool variables into
* sets which can be accessed via the housekeeping service interface or
* which can be sent to other software objects.
*
* It is recommended to read the documentation of the LocalPoolDataSetBase
* class for more information on how this class works and how to use it.
* @tparam capacity Capacity of the static dataset, which is usually known
* beforehand.
*/
class LocalDataSet: public LocalPoolDataSetBase { class LocalDataSet: public LocalPoolDataSetBase {
public: public:
LocalDataSet(HasLocalDataPoolIF* hkOwner, uint32_t setId, LocalDataSet(HasLocalDataPoolIF* hkOwner, uint32_t setId,
const size_t maxSize); const size_t maxSize);
LocalDataSet(sid_t sid, const size_t maxSize); LocalDataSet(sid_t sid, const size_t maxSize);
virtual~ LocalDataSet(); virtual~ LocalDataSet();
//! Copying forbidden for now. //! Copying forbidden for now.

View File

@ -28,7 +28,7 @@ LocalPoolDataSetBase::LocalPoolDataSetBase(HasLocalDataPoolIF *hkOwner,
AccessPoolManagerIF* accessor = HasLocalDpIFUserAttorney::getAccessorHandle(hkOwner); AccessPoolManagerIF* accessor = HasLocalDpIFUserAttorney::getAccessorHandle(hkOwner);
if(accessor != nullptr) { if(accessor != nullptr) {
poolManager = accessor->getHkManagerHandle(); poolManager = accessor->getPoolManagerHandle();
mutexIfSingleDataCreator = accessor->getLocalPoolMutex(); mutexIfSingleDataCreator = accessor->getLocalPoolMutex();
} }

View File

@ -22,7 +22,7 @@ LocalPoolObjectBase::LocalPoolObjectBase(lp_id_t poolId, HasLocalDataPoolIF* hkO
return; return;
} }
AccessPoolManagerIF* poolManAccessor = HasLocalDpIFUserAttorney::getAccessorHandle(hkOwner); AccessPoolManagerIF* poolManAccessor = HasLocalDpIFUserAttorney::getAccessorHandle(hkOwner);
hkManager = poolManAccessor->getHkManagerHandle(); hkManager = poolManAccessor->getPoolManagerHandle();
if (dataSet != nullptr) { if (dataSet != nullptr) {
dataSet->registerVariable(this); dataSet->registerVariable(this);
@ -50,7 +50,7 @@ LocalPoolObjectBase::LocalPoolObjectBase(object_id_t poolOwner, lp_id_t poolId,
AccessPoolManagerIF* accessor = HasLocalDpIFUserAttorney::getAccessorHandle(hkOwner); AccessPoolManagerIF* accessor = HasLocalDpIFUserAttorney::getAccessorHandle(hkOwner);
if(accessor != nullptr) { if(accessor != nullptr) {
hkManager = accessor->getHkManagerHandle(); hkManager = accessor->getPoolManagerHandle();
} }
if(dataSet != nullptr) { if(dataSet != nullptr) {

View File

@ -77,8 +77,7 @@ public:
* @param dataSet * @param dataSet
* @param setReadWriteMode * @param setReadWriteMode
*/ */
LocalPoolVector(gp_id_t globalPoolId, LocalPoolVector(gp_id_t globalPoolId, DataSetIF* dataSet = nullptr,
DataSetIF* dataSet = nullptr,
pool_rwm_t setReadWriteMode = pool_rwm_t::VAR_READ_WRITE); pool_rwm_t setReadWriteMode = pool_rwm_t::VAR_READ_WRITE);
/** /**
@ -87,7 +86,7 @@ public:
* The user can work on this attribute just like he would on a local * The user can work on this attribute just like he would on a local
* array of this type. * array of this type.
*/ */
T value[vectorSize]; T value[vectorSize]= {};
/** /**
* @brief The classes destructor is empty. * @brief The classes destructor is empty.
* @details If commit() was not called, the local value is * @details If commit() was not called, the local value is

View File

@ -16,7 +16,6 @@ inline LocalPoolVector<T, vectorSize>::LocalPoolVector(object_id_t poolOwner,
lp_id_t poolId, DataSetIF *dataSet, pool_rwm_t setReadWriteMode): lp_id_t poolId, DataSetIF *dataSet, pool_rwm_t setReadWriteMode):
LocalPoolObjectBase(poolOwner, poolId, dataSet, setReadWriteMode) {} LocalPoolObjectBase(poolOwner, poolId, dataSet, setReadWriteMode) {}
template<typename T, uint16_t vectorSize> template<typename T, uint16_t vectorSize>
inline LocalPoolVector<T, vectorSize>::LocalPoolVector(gp_id_t globalPoolId, inline LocalPoolVector<T, vectorSize>::LocalPoolVector(gp_id_t globalPoolId,
DataSetIF *dataSet, pool_rwm_t setReadWriteMode): DataSetIF *dataSet, pool_rwm_t setReadWriteMode):

View File

@ -2,11 +2,15 @@
#define FSFW_DATAPOOLLOCAL_STATICLOCALDATASET_H_ #define FSFW_DATAPOOLLOCAL_STATICLOCALDATASET_H_
#include "LocalPoolDataSetBase.h" #include "LocalPoolDataSetBase.h"
#include "LocalPoolVariable.h"
#include "LocalPoolVector.h"
#include "../objectmanager/SystemObjectIF.h" #include "../objectmanager/SystemObjectIF.h"
#include <array> #include <array>
/** /**
* @brief This local dataset type is created on the stack. * @brief This dataset type can be used to group related pool variables if the number of
* variables is fixed.
* @details * @details
* This will is the primary data structure to organize pool variables into * This will is the primary data structure to organize pool variables into
* sets which can be accessed via the housekeeping service interface or * sets which can be accessed via the housekeeping service interface or

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -209,20 +209,20 @@ void DeviceHandlerFailureIsolation::startRecovery(Event reason) {
} }
ReturnValue_t DeviceHandlerFailureIsolation::getParameter(uint8_t domainId, ReturnValue_t DeviceHandlerFailureIsolation::getParameter(uint8_t domainId,
uint16_t parameterId, ParameterWrapper* parameterWrapper, uint8_t uniqueId, ParameterWrapper* parameterWrapper,
const ParameterWrapper* newValues, uint16_t startAtIndex) { const ParameterWrapper* newValues, uint16_t startAtIndex) {
ReturnValue_t result = strangeReplyCount.getParameter(domainId, parameterId, ReturnValue_t result = strangeReplyCount.getParameter(domainId, uniqueId,
parameterWrapper, newValues, startAtIndex); parameterWrapper, newValues, startAtIndex);
if (result != INVALID_DOMAIN_ID) { if (result != INVALID_DOMAIN_ID) {
return result; return result;
} }
result = missedReplyCount.getParameter(domainId, parameterId, result = missedReplyCount.getParameter(domainId, uniqueId, parameterWrapper, newValues,
parameterWrapper, newValues, startAtIndex); startAtIndex);
if (result != INVALID_DOMAIN_ID) { if (result != INVALID_DOMAIN_ID) {
return result; return result;
} }
result = recoveryCounter.getParameter(domainId, parameterId, result = recoveryCounter.getParameter(domainId, uniqueId, parameterWrapper, newValues,
parameterWrapper, newValues, startAtIndex); startAtIndex);
if (result != INVALID_DOMAIN_ID) { if (result != INVALID_DOMAIN_ID) {
return result; return result;
} }

View File

@ -17,9 +17,9 @@ public:
ReturnValue_t initialize(); ReturnValue_t initialize();
void triggerEvent(Event event, uint32_t parameter1 = 0, void triggerEvent(Event event, uint32_t parameter1 = 0,
uint32_t parameter2 = 0);bool isFdirActionInProgress(); uint32_t parameter2 = 0);bool isFdirActionInProgress();
virtual ReturnValue_t getParameter(uint8_t domainId, uint16_t parameterId, virtual ReturnValue_t getParameter(uint8_t domainId, uint8_t uniqueId,
ParameterWrapper *parameterWrapper, ParameterWrapper *parameterWrapper, const ParameterWrapper *newValues,
const ParameterWrapper *newValues, uint16_t startAtIndex); uint16_t startAtIndex);
protected: protected:
FaultCounter strangeReplyCount; FaultCounter strangeReplyCount;

3
doc/doxy/.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
html
latex
rtf

2609
doc/doxy/OPUS.doxyfile Normal file

File diff suppressed because it is too large Load Diff

View File

@ -6,6 +6,7 @@
#include "../ipc/QueueFactory.h" #include "../ipc/QueueFactory.h"
#include "../ipc/MutexFactory.h" #include "../ipc/MutexFactory.h"
MessageQueueId_t EventManagerIF::eventmanagerQueue = MessageQueueIF::NO_QUEUE;
// If one checks registerListener calls, there are around 40 (to max 50) // If one checks registerListener calls, there are around 40 (to max 50)
// objects registering for certain events. // objects registering for certain events.

View File

@ -1,11 +1,12 @@
#ifndef EVENTMANAGERIF_H_ #ifndef FSFW_EVENTS_EVENTMANAGERIF_H_
#define EVENTMANAGERIF_H_ #define FSFW_EVENTS_EVENTMANAGERIF_H_
#include "EventMessage.h" #include "EventMessage.h"
#include "eventmatching/eventmatching.h" #include "eventmatching/eventmatching.h"
#include "../objectmanager/ObjectManagerIF.h" #include "../objectmanager/ObjectManagerIF.h"
#include "../ipc/MessageQueueSenderIF.h" #include "../ipc/MessageQueueSenderIF.h"
#include "../ipc/MessageQueueIF.h" #include "../ipc/MessageQueueIF.h"
#include "../serviceinterface/ServiceInterface.h"
class EventManagerIF { class EventManagerIF {
public: public:
@ -41,11 +42,19 @@ public:
static void triggerEvent(EventMessage* message, static void triggerEvent(EventMessage* message,
MessageQueueId_t sentFrom = 0) { MessageQueueId_t sentFrom = 0) {
static MessageQueueId_t eventmanagerQueue = MessageQueueIF::NO_QUEUE;
if (eventmanagerQueue == MessageQueueIF::NO_QUEUE) { if (eventmanagerQueue == MessageQueueIF::NO_QUEUE) {
EventManagerIF *eventmanager = objectManager->get<EventManagerIF>( EventManagerIF *eventmanager = objectManager->get<EventManagerIF>(
objects::EVENT_MANAGER); objects::EVENT_MANAGER);
if (eventmanager == nullptr) { if (eventmanager == nullptr) {
#if FSFW_VERBOSE_LEVEL >= 1
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning << "EventManagerIF::triggerEvent: EventManager invalid or not found!"
<< std::endl;
#else
sif::printWarning("EventManagerIF::triggerEvent: "
"EventManager invalid or not found!");
#endif /* FSFW_CPP_OSTREAM_ENABLED == 1 */
#endif /* FSFW_VERBOSE_LEVEL >= 1 */
return; return;
} }
eventmanagerQueue = eventmanager->getEventReportQueue(); eventmanagerQueue = eventmanager->getEventReportQueue();
@ -53,6 +62,10 @@ public:
MessageQueueSenderIF::sendMessage(eventmanagerQueue, message, sentFrom); MessageQueueSenderIF::sendMessage(eventmanagerQueue, message, sentFrom);
} }
private:
//! Initialized by EventManager (C++11 does not allow header-only static member initialization).
static MessageQueueId_t eventmanagerQueue;
}; };
#endif /* EVENTMANAGERIF_H_ */ #endif /* FSFW_EVENTS_EVENTMANAGERIF_H_ */

View File

@ -58,14 +58,14 @@ FaultCounter::FaultCounter() :
parameterDomain(0), timer(), faultCount(0), failureThreshold(0) { parameterDomain(0), timer(), faultCount(0), failureThreshold(0) {
} }
ReturnValue_t FaultCounter::getParameter(uint8_t domainId, uint16_t parameterId, ReturnValue_t FaultCounter::getParameter(uint8_t domainId, uint8_t uniqueId,
ParameterWrapper* parameterWrapper, const ParameterWrapper* newValues, ParameterWrapper* parameterWrapper, const ParameterWrapper* newValues,
uint16_t startAtIndex) { uint16_t startAtIndex) {
if (domainId != parameterDomain) { if (domainId != parameterDomain) {
return INVALID_DOMAIN_ID; return INVALID_DOMAIN_ID;
} }
switch (parameterId) { switch (uniqueId) {
case 0: case 0:
parameterWrapper->set(failureThreshold); parameterWrapper->set(failureThreshold);
break; break;

View File

@ -23,7 +23,7 @@ public:
void setFailureThreshold(uint32_t failureThreshold); void setFailureThreshold(uint32_t failureThreshold);
void setFaultDecrementTimeMs(uint32_t timeMs); void setFaultDecrementTimeMs(uint32_t timeMs);
virtual ReturnValue_t getParameter(uint8_t domainId, uint16_t parameterId, virtual ReturnValue_t getParameter(uint8_t domainId, uint8_t uniqueId,
ParameterWrapper *parameterWrapper, ParameterWrapper *parameterWrapper,
const ParameterWrapper *newValues, uint16_t startAtIndex); const ParameterWrapper *newValues, uint16_t startAtIndex);

View File

@ -176,7 +176,7 @@ void HousekeepingMessage::setUpdateNotificationVariableCommand(
void HousekeepingMessage::setUpdateSnapshotSetCommand(CommandMessage *command, void HousekeepingMessage::setUpdateSnapshotSetCommand(CommandMessage *command,
sid_t sid, store_address_t storeId) { sid_t sid, store_address_t storeId) {
command->setCommand(UPDATE_SNAPSHOT_VARIABLE); command->setCommand(UPDATE_SNAPSHOT_SET);
setSid(command, sid); setSid(command, sid);
command->setParameter3(storeId.raw); command->setParameter3(storeId.raw);
} }

View File

@ -1,24 +1,37 @@
#ifndef FSFW_HOUSEKEEPING_HOUSEKEEPINGPACKETUPDATE_H_ #ifndef FSFW_HOUSEKEEPING_HOUSEKEEPINGSNAPSHOT_H_
#define FSFW_HOUSEKEEPING_HOUSEKEEPINGPACKETUPDATE_H_ #define FSFW_HOUSEKEEPING_HOUSEKEEPINGSNAPSHOT_H_
#include "../serialize/SerialBufferAdapter.h" #include "../serialize/SerialBufferAdapter.h"
#include "../serialize/SerialLinkedListAdapter.h" #include "../serialize/SerialLinkedListAdapter.h"
#include "../datapoollocal/LocalPoolDataSetBase.h" #include "../datapoollocal/LocalPoolDataSetBase.h"
#include "../datapoollocal/LocalPoolObjectBase.h"
#include "../timemanager/CCSDSTime.h"
/** /**
* @brief This helper class will be used to serialize and deserialize * @brief This helper class will be used to serialize and deserialize update housekeeping packets
* update housekeeping packets into the store. * into the store.
*/ */
class HousekeepingPacketUpdate: public SerializeIF { class HousekeepingSnapshot: public SerializeIF {
public: public:
/** /**
* Update packet constructor for datasets * Update packet constructor for datasets.
* @param timeStamp * @param cdsShort If a CSD short timestamp is used, a reference should be
* @param timeStampSize * supplied here
* @param hkData * @param dataSetPtr Pointer to the dataset instance to serialize or deserialize the
* @param hkDataSize * data into
*/ */
HousekeepingPacketUpdate(uint8_t* timeStamp, size_t timeStampSize, HousekeepingSnapshot(CCSDSTime::CDS_short* cdsShort, LocalPoolDataSetBase* dataSetPtr):
timeStamp(reinterpret_cast<uint8_t*>(cdsShort)),
timeStampSize(sizeof(CCSDSTime::CDS_short)), updateData(dataSetPtr) {};
/**
* Update packet constructor for datasets.
* @param timeStamp Pointer to the buffer where the timestamp will be stored.
* @param timeStampSize Size of the timestamp
* @param dataSetPtr Pointer to the dataset instance to deserialize the data into
*/
HousekeepingSnapshot(uint8_t* timeStamp, size_t timeStampSize,
LocalPoolDataSetBase* dataSetPtr): LocalPoolDataSetBase* dataSetPtr):
timeStamp(timeStamp), timeStampSize(timeStampSize), timeStamp(timeStamp), timeStampSize(timeStampSize),
updateData(dataSetPtr) {}; updateData(dataSetPtr) {};
@ -29,7 +42,7 @@ public:
* @param timeStampSize * @param timeStampSize
* @param dataSetPtr * @param dataSetPtr
*/ */
HousekeepingPacketUpdate(uint8_t* timeStamp, size_t timeStampSize, HousekeepingSnapshot(uint8_t* timeStamp, size_t timeStampSize,
LocalPoolObjectBase* dataSetPtr): LocalPoolObjectBase* dataSetPtr):
timeStamp(timeStamp), timeStampSize(timeStampSize), timeStamp(timeStamp), timeStampSize(timeStampSize),
updateData(dataSetPtr) {}; updateData(dataSetPtr) {};
@ -89,4 +102,4 @@ private:
}; };
#endif /* FSFW_HOUSEKEEPING_HOUSEKEEPINGPACKETUPDATE_H_ */ #endif /* FSFW_HOUSEKEEPING_HOUSEKEEPINGSNAPSHOT_H_ */

View File

@ -37,16 +37,16 @@ public:
} }
} }
virtual ReturnValue_t getParameter(uint8_t domainId, uint16_t parameterId, virtual ReturnValue_t getParameter(uint8_t domainId, uint8_t uniqueId,
ParameterWrapper *parameterWrapper, ParameterWrapper *parameterWrapper, const ParameterWrapper *newValues,
const ParameterWrapper *newValues, uint16_t startAtIndex) { uint16_t startAtIndex) {
ReturnValue_t result = this->MonitorBase<T>::getParameter(domainId, ReturnValue_t result = this->MonitorBase<T>::getParameter(domainId,
parameterId, parameterWrapper, newValues, startAtIndex); uniqueId, parameterWrapper, newValues, startAtIndex);
//We'll reuse the DOMAIN_ID of MonitorReporter, as we know the parameterIds used there. //We'll reuse the DOMAIN_ID of MonitorReporter, as we know the parameterIds used there.
if (result != this->INVALID_IDENTIFIER_ID) { if (result != this->INVALID_IDENTIFIER_ID) {
return result; return result;
} }
switch (parameterId) { switch (uniqueId) {
case 10: case 10:
parameterWrapper->set(this->lowerLimit); parameterWrapper->set(this->lowerLimit);
break; break;

View File

@ -51,13 +51,13 @@ public:
return state; return state;
} }
virtual ReturnValue_t getParameter(uint8_t domainId, uint16_t parameterId, virtual ReturnValue_t getParameter(uint8_t domainId, uint8_t uniqueId,
ParameterWrapper *parameterWrapper, ParameterWrapper *parameterWrapper, const ParameterWrapper *newValues,
const ParameterWrapper *newValues, uint16_t startAtIndex) { uint16_t startAtIndex) {
if (domainId != monitorId) { if (domainId != monitorId) {
return INVALID_DOMAIN_ID; return INVALID_DOMAIN_ID;
} }
switch (parameterId) { switch (uniqueId) {
case 0: case 0:
parameterWrapper->set(this->confirmationLimit); parameterWrapper->set(this->confirmationLimit);
break; break;

View File

@ -10,7 +10,7 @@
#include "../serialize/SerialFixedArrayListAdapter.h" #include "../serialize/SerialFixedArrayListAdapter.h"
#include "../serialize/SerializeElement.h" #include "../serialize/SerializeElement.h"
#include "../serialize/SerialLinkedListAdapter.h" #include "../serialize/SerialLinkedListAdapter.h"
#include "../serviceinterface/ServiceInterfaceStream.h" #include "../serviceinterface/ServiceInterface.h"
#include "../timemanager/TimeStamperIF.h" #include "../timemanager/TimeStamperIF.h"
namespace Factory{ namespace Factory{

View File

@ -71,13 +71,13 @@ public:
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
} }
ReturnValue_t getParameter(uint8_t domainId, uint16_t parameterId, ReturnValue_t getParameter(uint8_t domainId, uint8_t uniqueId,
ParameterWrapper *parameterWrapper, ParameterWrapper *parameterWrapper, const ParameterWrapper *newValues,
const ParameterWrapper *newValues, uint16_t startAtIndex) { uint16_t startAtIndex) {
if (domainId != this->domainId) { if (domainId != this->domainId) {
return INVALID_DOMAIN_ID; return INVALID_DOMAIN_ID;
} }
switch (parameterId) { switch (uniqueId) {
case 0: case 0:
parameterWrapper->set(limit); parameterWrapper->set(limit);
break; break;

View File

@ -1,5 +1,5 @@
#include "ObjectManager.h" #include "ObjectManager.h"
#include "../serviceinterface/ServiceInterfaceStream.h" #include "../serviceinterface/ServiceInterface.h"
#if FSFW_CPP_OSTREAM_ENABLED == 1 #if FSFW_CPP_OSTREAM_ENABLED == 1
#include <iomanip> #include <iomanip>
@ -75,6 +75,8 @@ void ObjectManager::initialize() {
#if FSFW_CPP_OSTREAM_ENABLED == 1 #if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "ObjectManager::initialize: Passed produceObjects " sif::error << "ObjectManager::initialize: Passed produceObjects "
"functions is nullptr!" << std::endl; "functions is nullptr!" << std::endl;
#else
sif::printError("ObjectManager::initialize: Passed produceObjects functions is nullptr!\n");
#endif #endif
return; return;
} }

View File

@ -5,13 +5,17 @@
SystemObject::SystemObject(object_id_t setObjectId, bool doRegister) : SystemObject::SystemObject(object_id_t setObjectId, bool doRegister) :
objectId(setObjectId), registered(doRegister) { objectId(setObjectId), registered(doRegister) {
if (registered) { if (registered) {
objectManager->insert(objectId, this); if(objectManager != nullptr) {
objectManager->insert(objectId, this);
}
} }
} }
SystemObject::~SystemObject() { SystemObject::~SystemObject() {
if (registered) { if (registered) {
objectManager->remove(objectId); if(objectManager != nullptr) {
objectManager->remove(objectId);
}
} }
} }

View File

@ -1,30 +1,35 @@
#ifndef FSFW_OBJECTMANAGER_FRAMEWORKOBJECTS_H_ #ifndef FSFW_OBJECTMANAGER_FRAMEWORKOBJECTS_H_
#define FSFW_OBJECTMANAGER_FRAMEWORKOBJECTS_H_ #define FSFW_OBJECTMANAGER_FRAMEWORKOBJECTS_H_
#include <fsfw/objectmanager/SystemObjectIF.h>
namespace objects { namespace objects {
enum framework_objects { enum framework_objects: object_id_t {
// Default verification reporter. FSFW_OBJECTS_START = 0x53000000,
PUS_SERVICE_1_VERIFICATION = 0x53000001, // Default verification reporter.
PUS_SERVICE_2_DEVICE_ACCESS = 0x53000002, PUS_SERVICE_1_VERIFICATION = 0x53000001,
PUS_SERVICE_3_HOUSEKEEPING = 0x53000003, PUS_SERVICE_2_DEVICE_ACCESS = 0x53000002,
PUS_SERVICE_5_EVENT_REPORTING = 0x53000005, PUS_SERVICE_3_HOUSEKEEPING = 0x53000003,
PUS_SERVICE_8_FUNCTION_MGMT = 0x53000008, PUS_SERVICE_5_EVENT_REPORTING = 0x53000005,
PUS_SERVICE_9_TIME_MGMT = 0x53000009, PUS_SERVICE_8_FUNCTION_MGMT = 0x53000008,
PUS_SERVICE_17_TEST = 0x53000017, PUS_SERVICE_9_TIME_MGMT = 0x53000009,
PUS_SERVICE_200_MODE_MGMT = 0x53000200, PUS_SERVICE_17_TEST = 0x53000017,
PUS_SERVICE_20_PARAMETERS = 0x53000020,
PUS_SERVICE_200_MODE_MGMT = 0x53000200,
//Generic IDs for IPC, modes, health, events //Generic IDs for IPC, modes, health, events
HEALTH_TABLE = 0x53010000, HEALTH_TABLE = 0x53010000,
// MODE_STORE = 0x53010100, // MODE_STORE = 0x53010100,
EVENT_MANAGER = 0x53030000, EVENT_MANAGER = 0x53030000,
INTERNAL_ERROR_REPORTER = 0x53040000, INTERNAL_ERROR_REPORTER = 0x53040000,
IPC_STORE = 0x534f0300, IPC_STORE = 0x534f0300,
//IDs for PUS Packet Communication //IDs for PUS Packet Communication
TC_STORE = 0x534f0100, TC_STORE = 0x534f0100,
TM_STORE = 0x534f0200, TM_STORE = 0x534f0200,
TIME_STAMPER = 0x53500010, TIME_STAMPER = 0x53500010,
NO_OBJECT = 0xFFFFFFFF FSFW_OBJECTS_END = 0x53ffffff,
NO_OBJECT = 0xFFFFFFFF
}; };
} }

View File

@ -25,7 +25,8 @@
#else #else
#ifdef WIN32 #ifdef WIN32
#include <Windows.h> #include <winsock2.h>
#include <windows.h>
#if REG_DWORD == REG_DWORD_LITTLE_ENDIAN #if REG_DWORD == REG_DWORD_LITTLE_ENDIAN
#define BYTE_ORDER_SYSTEM LITTLE_ENDIAN #define BYTE_ORDER_SYSTEM LITTLE_ENDIAN
#else #else

View File

@ -3,7 +3,7 @@
#include <chrono> #include <chrono>
#if defined(WIN32) #if defined(WIN32)
#include <windows.h> #include <sysinfoapi.h>
#elif defined(LINUX) #elif defined(LINUX)
#include <fstream> #include <fstream>
#endif #endif
@ -15,35 +15,34 @@ using SystemClock = std::chrono::system_clock;
uint32_t Clock::getTicksPerSecond(void){ uint32_t Clock::getTicksPerSecond(void){
#if FSFW_CPP_OSTREAM_ENABLED == 1 #if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning << "Clock::getTicksPerSecond: not implemented yet" << std::endl; sif::warning << "Clock::getTicksPerSecond: Not implemented for host OSAL" << std::endl;
#else
sif::printWarning("Clock::getTicksPerSecond: Not implemented for host OSAL\n");
#endif #endif
return 0; /* To avoid division by zero */
//return CLOCKS_PER_SEC; return 1;
//uint32_t ticks = sysconf(_SC_CLK_TCK);
//return ticks;
} }
ReturnValue_t Clock::setClock(const TimeOfDay_t* time) { ReturnValue_t Clock::setClock(const TimeOfDay_t* time) {
// do some magic with chrono /* I don't know why someone would need to set a clock which is probably perfectly fine on a
host system with internet access so this is not implemented for now. */
#if FSFW_CPP_OSTREAM_ENABLED == 1 #if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning << "Clock::setClock: not implemented yet" << std::endl; sif::warning << "Clock::setClock: Not implemented for host OSAL" << std::endl;
#else
sif::printWarning("Clock::setClock: Not implemented for host OSAL\n");
#endif #endif
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
} }
ReturnValue_t Clock::setClock(const timeval* time) { ReturnValue_t Clock::setClock(const timeval* time) {
// do some magic with chrono /* I don't know why someone would need to set a clock which is probably perfectly fine on a
#if defined(WIN32) host system with internet access so this is not implemented for now. */
return HasReturnvaluesIF::RETURN_OK;
#elif defined(LINUX)
return HasReturnvaluesIF::RETURN_OK;
#else
#endif
#if FSFW_CPP_OSTREAM_ENABLED == 1 #if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning << "Clock::getUptime: Not implemented for found OS" << std::endl; sif::warning << "Clock::setClock: Not implemented for host OSAL" << std::endl;
#else
sif::printWarning("Clock::setClock: Not implemented for host OSAL\n");
#endif #endif
return HasReturnvaluesIF::RETURN_FAILED; return HasReturnvaluesIF::RETURN_OK;
} }
ReturnValue_t Clock::getClock_timeval(timeval* time) { ReturnValue_t Clock::getClock_timeval(timeval* time) {
@ -53,8 +52,7 @@ ReturnValue_t Clock::getClock_timeval(timeval* time) {
auto epoch = now.time_since_epoch(); auto epoch = now.time_since_epoch();
time->tv_sec = std::chrono::duration_cast<std::chrono::seconds>(epoch).count(); time->tv_sec = std::chrono::duration_cast<std::chrono::seconds>(epoch).count();
auto fraction = now - secondsChrono; auto fraction = now - secondsChrono;
time->tv_usec = std::chrono::duration_cast<std::chrono::microseconds>( time->tv_usec = std::chrono::duration_cast<std::chrono::microseconds>(fraction).count();
fraction).count();
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
#elif defined(LINUX) #elif defined(LINUX)
timespec timeUnix; timespec timeUnix;
@ -67,7 +65,9 @@ ReturnValue_t Clock::getClock_timeval(timeval* time) {
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
#else #else
#if FSFW_CPP_OSTREAM_ENABLED == 1 #if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning << "Clock::getUptime: Not implemented for found OS" << std::endl; sif::warning << "Clock::getUptime: Not implemented for found OS!" << std::endl;
#else
sif::printWarning("Clock::getUptime: Not implemented for found OS!\n");
#endif #endif
return HasReturnvaluesIF::RETURN_FAILED; return HasReturnvaluesIF::RETURN_FAILED;
#endif #endif
@ -75,10 +75,11 @@ ReturnValue_t Clock::getClock_timeval(timeval* time) {
} }
ReturnValue_t Clock::getClock_usecs(uint64_t* time) { ReturnValue_t Clock::getClock_usecs(uint64_t* time) {
// do some magic with chrono if(time == nullptr) {
#if FSFW_CPP_OSTREAM_ENABLED == 1 return HasReturnvaluesIF::RETURN_FAILED;
sif::warning << "Clock::gerClock_usecs: not implemented yet" << std::endl; }
#endif using namespace std::chrono;
*time = duration_cast<microseconds>(system_clock::now().time_since_epoch()).count();
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
} }
@ -120,9 +121,9 @@ ReturnValue_t Clock::getUptime(uint32_t* uptimeMs) {
ReturnValue_t Clock::getDateAndTime(TimeOfDay_t* time) { ReturnValue_t Clock::getDateAndTime(TimeOfDay_t* time) {
// do some magic with chrono (C++20!) /* Do some magic with chrono (C++20!) */
// Right now, the library doesn't have the new features yet. /* Right now, the library doesn't have the new features to get the required values yet.
// so we work around that for now. so we work around that for now. */
auto now = SystemClock::now(); auto now = SystemClock::now();
auto seconds = std::chrono::time_point_cast<std::chrono::seconds>(now); auto seconds = std::chrono::time_point_cast<std::chrono::seconds>(now);
auto fraction = now - seconds; auto fraction = now - seconds;
@ -137,10 +138,6 @@ ReturnValue_t Clock::getDateAndTime(TimeOfDay_t* time) {
time->second = timeInfo->tm_sec; time->second = timeInfo->tm_sec;
auto usecond = std::chrono::duration_cast<std::chrono::microseconds>(fraction); auto usecond = std::chrono::duration_cast<std::chrono::microseconds>(fraction);
time->usecond = usecond.count(); time->usecond = usecond.count();
#if FSFW_CPP_OSTREAM_ENABLED == 1
//sif::warning << "Clock::getDateAndTime: not implemented yet" << std::endl;
#endif
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
} }

View File

@ -9,7 +9,7 @@
#include <chrono> #include <chrono>
#if defined(WIN32) #if defined(WIN32)
#include <windows.h> #include <processthreadsapi.h>
#elif defined(LINUX) #elif defined(LINUX)
#include <pthread.h> #include <pthread.h>
#endif #endif

View File

@ -5,13 +5,13 @@ target_sources(${LIB_FSFW_NAME}
InitTask.cpp InitTask.cpp
InternalErrorCodes.cpp InternalErrorCodes.cpp
MessageQueue.cpp MessageQueue.cpp
MultiObjectTask.cpp PeriodicTask.cpp
Mutex.cpp Mutex.cpp
MutexFactory.cpp MutexFactory.cpp
PollingTask.cpp FixedTimeslotTask.cpp
QueueFactory.cpp QueueFactory.cpp
RtemsBasic.cpp RtemsBasic.cpp
TaskBase.cpp RTEMSTaskBase.cpp
TaskFactory.cpp TaskFactory.cpp
) )

View File

@ -104,9 +104,13 @@ ReturnValue_t Clock::getClock_usecs(uint64_t* time) {
} }
ReturnValue_t Clock::getDateAndTime(TimeOfDay_t* time) { ReturnValue_t Clock::getDateAndTime(TimeOfDay_t* time) {
// TIsn't this a bug? Are RTEMS ticks always microseconds? /* 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 = reinterpret_cast<rtems_time_of_day*>(time);
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
to rtems_clock_get_ticks_per_second() minus one. We calculate the microseconds accordingly */
timeRtems->ticks = static_cast<float>(timeRtems->ticks) /
rtems_clock_get_ticks_per_second() * 1e6;
switch (status) { switch (status) {
case RTEMS_SUCCESSFUL: case RTEMS_SUCCESSFUL:
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;

View File

@ -164,7 +164,7 @@ ReturnValue_t CpuUsage::ThreadData::deSerialize(const uint8_t** buffer,
if (result != HasReturnvaluesIF::RETURN_OK) { if (result != HasReturnvaluesIF::RETURN_OK) {
return result; return result;
} }
if ((*size = *size - MAX_LENGTH_OF_THREAD_NAME) < 0) { if (*size < MAX_LENGTH_OF_THREAD_NAME) {
return STREAM_TOO_SHORT; return STREAM_TOO_SHORT;
} }
memcpy(name, *buffer, MAX_LENGTH_OF_THREAD_NAME); memcpy(name, *buffer, MAX_LENGTH_OF_THREAD_NAME);

View File

@ -0,0 +1,140 @@
#include "FixedTimeslotTask.h"
#include "RtemsBasic.h"
#include "../../tasks/FixedSequenceSlot.h"
#include "../../objectmanager/SystemObjectIF.h"
#include "../../objectmanager/ObjectManagerIF.h"
#include "../../returnvalues/HasReturnvaluesIF.h"
#include "../../serviceinterface/ServiceInterface.h"
#include <rtems/bspIo.h>
#include <rtems/io.h>
#include <rtems/rtems/ratemon.h>
#include <rtems/rtems/status.h>
#include <rtems/rtems/tasks.h>
#include <rtems/rtems/types.h>
#include <sys/_stdint.h>
#if FSFW_CPP_OSTREAM_ENABLED == 1
#include <iostream>
#endif
#include <cstddef>
#include <list>
uint32_t FixedTimeslotTask::deadlineMissedCount = 0;
FixedTimeslotTask::FixedTimeslotTask(const char *name, rtems_task_priority setPriority,
size_t setStack, uint32_t setOverallPeriod, void (*setDeadlineMissedFunc)(void)):
RTEMSTaskBase(setPriority, setStack, name), periodId(0), pst(setOverallPeriod) {
// All additional attributes are applied to the object.
this->deadlineMissedFunc = setDeadlineMissedFunc;
}
FixedTimeslotTask::~FixedTimeslotTask() {
}
rtems_task FixedTimeslotTask::taskEntryPoint(rtems_task_argument argument) {
/* The argument is re-interpreted as a FixedTimeslotTask */
FixedTimeslotTask *originalTask(reinterpret_cast<FixedTimeslotTask*>(argument));
/* The task's functionality is called. */
return originalTask->taskFunctionality();
/* Should never be reached */
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "Polling task " << originalTask->getId() << " returned from taskFunctionality." <<
std::endl;
#endif
}
void FixedTimeslotTask::missedDeadlineCounter() {
FixedTimeslotTask::deadlineMissedCount++;
if (FixedTimeslotTask::deadlineMissedCount % 10 == 0) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "PST missed " << FixedTimeslotTask::deadlineMissedCount
<< " deadlines." << std::endl;
#endif
}
}
ReturnValue_t FixedTimeslotTask::startTask() {
rtems_status_code status = rtems_task_start(id, FixedTimeslotTask::taskEntryPoint,
rtems_task_argument((void *) this));
if (status != RTEMS_SUCCESSFUL) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "PollingTask::startTask for " << std::hex << this->getId()
<< std::dec << " failed." << std::endl;
#endif
}
switch(status){
case RTEMS_SUCCESSFUL:
//ask started successfully
return HasReturnvaluesIF::RETURN_OK;
default:
/*
RTEMS_INVALID_ADDRESS - invalid task entry point
RTEMS_INVALID_ID - invalid task id
RTEMS_INCORRECT_STATE - task not in the dormant state
RTEMS_ILLEGAL_ON_REMOTE_OBJECT - cannot start remote task */
return HasReturnvaluesIF::RETURN_FAILED;
}
}
ReturnValue_t FixedTimeslotTask::addSlot(object_id_t componentId,
uint32_t slotTimeMs, int8_t executionStep) {
ExecutableObjectIF* object = objectManager->get<ExecutableObjectIF>(componentId);
if (object != nullptr) {
pst.addSlot(componentId, slotTimeMs, executionStep, object, this);
return HasReturnvaluesIF::RETURN_OK;
}
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "Component " << std::hex << componentId <<
" not found, not adding it to pst" << std::endl;
#endif
return HasReturnvaluesIF::RETURN_FAILED;
}
uint32_t FixedTimeslotTask::getPeriodMs() const {
return pst.getLengthMs();
}
ReturnValue_t FixedTimeslotTask::checkSequence() const {
return pst.checkSequence();
}
void FixedTimeslotTask::taskFunctionality() {
/* A local iterator for the Polling Sequence Table is created to find the start time for
the first entry. */
FixedSlotSequence::SlotListIter it = pst.current;
/* Initialize the PST with the correct calling task */
pst.intializeSequenceAfterTaskCreation();
/* The start time for the first entry is read. */
rtems_interval interval = RtemsBasic::convertMsToTicks(it->pollingTimeMs);
RTEMSTaskBase::setAndStartPeriod(interval,&periodId);
//The task's "infinite" inner loop is entered.
while (1) {
if (pst.slotFollowsImmediately()) {
/* Do nothing */
}
else {
/* The interval for the next polling slot is selected. */
interval = RtemsBasic::convertMsToTicks(this->pst.getIntervalToNextSlotMs());
/* The period is checked and restarted with the new interval.
If the deadline was missed, the deadlineMissedFunc is called. */
rtems_status_code status = RTEMSTaskBase::restartPeriod(interval,periodId);
if (status == RTEMS_TIMEOUT) {
if (this->deadlineMissedFunc != nullptr) {
this->deadlineMissedFunc();
}
}
}
/* The device handler for this slot is executed and the next one is chosen. */
this->pst.executeAndAdvance();
}
}
ReturnValue_t FixedTimeslotTask::sleepFor(uint32_t ms){
return RTEMSTaskBase::sleepFor(ms);
};

View File

@ -0,0 +1,81 @@
#ifndef FSFW_OSAL_RTEMS_FIXEDTIMESLOTTASK_H_
#define FSFW_OSAL_RTEMS_FIXEDTIMESLOTTASK_H_
#include "RTEMSTaskBase.h"
#include "../../tasks/FixedSlotSequence.h"
#include "../../tasks/FixedTimeslotTaskIF.h"
class FixedTimeslotTask: public RTEMSTaskBase, public FixedTimeslotTaskIF {
public:
/**
* @brief The standard constructor of the class.
* @details
* This is the general constructor of the class. In addition to the TaskBase parameters,
* the following variables are passed:
* @param setDeadlineMissedFunc The function pointer to the deadline missed function
* that shall be assigned.
* @param getPst The object id of the completely initialized polling sequence.
*/
FixedTimeslotTask( const char *name, rtems_task_priority setPriority, size_t setStackSize,
uint32_t overallPeriod, void (*setDeadlineMissedFunc)());
/**
* @brief The destructor of the class.
* @details
* The destructor frees all heap memory that was allocated on thread initialization
* for the PST andthe device handlers. This is done by calling the PST's destructor.
*/
virtual ~FixedTimeslotTask( void );
ReturnValue_t startTask( void );
/**
* This static function can be used as #deadlineMissedFunc.
* It counts missedDeadlines and prints the number of missed deadlines every 10th time.
*/
static void missedDeadlineCounter();
/**
* A helper variable to count missed deadlines.
*/
static uint32_t deadlineMissedCount;
ReturnValue_t addSlot(object_id_t componentId, uint32_t slotTimeMs, int8_t executionStep);
uint32_t getPeriodMs() const;
ReturnValue_t checkSequence() const;
ReturnValue_t sleepFor(uint32_t ms);
protected:
/**
* @brief id of the associated OS period
*/
rtems_id periodId;
FixedSlotSequence pst;
/**
* @brief This attribute holds a function pointer that is executed when a deadline was missed.
*
* @details
* Another function may be announced to determine the actions to perform when a deadline
* was missed. Currently, only one function for missing any deadline is allowed.
* If not used, it shall be declared NULL.
*/
void ( *deadlineMissedFunc )( void ) = nullptr;
/**
* @brief This is the entry point in a new polling thread.
* @details This method is the entry point in the new thread
*/
static rtems_task taskEntryPoint( rtems_task_argument argument );
/**
* @brief This function holds the main functionality of the thread.
* @details
* Holding the main functionality of the task, this method is most important.
* It links the functionalities provided by FixedSlotSequence with the OS's system calls to
* keep the timing of the periods.
*/
void taskFunctionality( void );
};
#endif /* FSFW_OSAL_RTEMS_FIXEDTIMESLOTTASK_H_ */

View File

@ -1,92 +0,0 @@
/**
* @file MultiObjectTask.cpp
* @brief This file defines the MultiObjectTask class.
* @date 30.01.2014
* @author baetz
*/
#include "../../serviceinterface/ServiceInterfaceStream.h"
#include "../../tasks/ExecutableObjectIF.h"
#include "MultiObjectTask.h"
MultiObjectTask::MultiObjectTask(const char *name, rtems_task_priority setPriority,
size_t setStack, rtems_interval setPeriod, void (*setDeadlineMissedFunc)()) :
TaskBase(setPriority, setStack, name), periodTicks(
RtemsBasic::convertMsToTicks(setPeriod)), periodId(0), deadlineMissedFunc(
setDeadlineMissedFunc) {
}
MultiObjectTask::~MultiObjectTask(void) {
//Do not delete objects, we were responsible for ptrs only.
rtems_rate_monotonic_delete(periodId);
}
rtems_task MultiObjectTask::taskEntryPoint(rtems_task_argument argument) {
//The argument is re-interpreted as MultiObjectTask. The Task object is global, so it is found from any place.
MultiObjectTask *originalTask(reinterpret_cast<MultiObjectTask*>(argument));
originalTask->taskFunctionality();
}
ReturnValue_t MultiObjectTask::startTask() {
rtems_status_code status = rtems_task_start(id, MultiObjectTask::taskEntryPoint,
rtems_task_argument((void *) this));
if (status != RTEMS_SUCCESSFUL) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "ObjectTask::startTask for " << std::hex << this->getId()
<< std::dec << " failed." << std::endl;
#endif
}
switch(status){
case RTEMS_SUCCESSFUL:
//ask started successfully
return HasReturnvaluesIF::RETURN_OK;
default:
/* RTEMS_INVALID_ADDRESS - invalid task entry point
RTEMS_INVALID_ID - invalid task id
RTEMS_INCORRECT_STATE - task not in the dormant state
RTEMS_ILLEGAL_ON_REMOTE_OBJECT - cannot start remote task */
return HasReturnvaluesIF::RETURN_FAILED;
}
}
ReturnValue_t MultiObjectTask::sleepFor(uint32_t ms) {
return TaskBase::sleepFor(ms);
}
void MultiObjectTask::taskFunctionality() {
TaskBase::setAndStartPeriod(periodTicks,&periodId);
//The task's "infinite" inner loop is entered.
while (1) {
for (ObjectList::iterator it = objectList.begin();
it != objectList.end(); ++it) {
(*it)->performOperation();
}
rtems_status_code status = TaskBase::restartPeriod(periodTicks,periodId);
if (status == RTEMS_TIMEOUT) {
char nameSpace[8] = { 0 };
char* ptr = rtems_object_get_name(getId(), sizeof(nameSpace),
nameSpace);
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "ObjectTask: " << ptr << " Deadline missed." << std::endl;
#endif
if (this->deadlineMissedFunc != nullptr) {
this->deadlineMissedFunc();
}
}
}
}
ReturnValue_t MultiObjectTask::addComponent(object_id_t object) {
ExecutableObjectIF* newObject = objectManager->get<ExecutableObjectIF>(
object);
if (newObject == nullptr) {
return HasReturnvaluesIF::RETURN_FAILED;
}
objectList.push_back(newObject);
newObject->setTaskIF(this);
return HasReturnvaluesIF::RETURN_OK;
}
uint32_t MultiObjectTask::getPeriodMs() const {
return RtemsBasic::convertTicksToMs(periodTicks);
}

View File

@ -1,18 +1,20 @@
#include "Mutex.h" #include "Mutex.h"
#include "../../serviceinterface/ServiceInterfaceStream.h" #include "../../serviceinterface/ServiceInterface.h"
uint8_t Mutex::count = 0; uint8_t Mutex::count = 0;
Mutex::Mutex() : Mutex::Mutex() {
mutexId(0) {
rtems_name mutexName = ('M' << 24) + ('T' << 16) + ('X' << 8) + count++; rtems_name mutexName = ('M' << 24) + ('T' << 16) + ('X' << 8) + count++;
rtems_status_code status = rtems_semaphore_create(mutexName, 1, rtems_status_code status = rtems_semaphore_create(mutexName, 1,
RTEMS_BINARY_SEMAPHORE | RTEMS_PRIORITY | RTEMS_INHERIT_PRIORITY, 0, RTEMS_BINARY_SEMAPHORE | RTEMS_PRIORITY | RTEMS_INHERIT_PRIORITY, 0,
&mutexId); &mutexId);
if (status != RTEMS_SUCCESSFUL) { if (status != RTEMS_SUCCESSFUL) {
#if FSFW_CPP_OSTREAM_ENABLED == 1 #if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "Mutex: creation with name, id " << mutexName << ", " << mutexId sif::error << "Mutex::Mutex: Creation with name, id " << mutexName << ", " << mutexId <<
<< " failed with " << status << std::endl; " failed with " << status << std::endl;
#else
sif::printError("Mutex::Mutex: Creation with name, id %s, %d failed with %d\n", mutexName,
static_cast<int>(mutexId), static_cast<int>(status));
#endif #endif
} }
} }

View File

@ -11,7 +11,7 @@ public:
ReturnValue_t lockMutex(TimeoutType timeoutType, uint32_t timeoutMs = 0); ReturnValue_t lockMutex(TimeoutType timeoutType, uint32_t timeoutMs = 0);
ReturnValue_t unlockMutex(); ReturnValue_t unlockMutex();
private: private:
rtems_id mutexId; rtems_id mutexId = 0;
static uint8_t count; static uint8_t count;
}; };

View File

@ -1,6 +1,7 @@
#include "../../ipc/MutexFactory.h"
#include "Mutex.h" #include "Mutex.h"
#include "RtemsBasic.h"
#include "../../ipc/MutexFactory.h"
MutexFactory* MutexFactory::factoryInstance = new MutexFactory(); MutexFactory* MutexFactory::factoryInstance = new MutexFactory();

View File

@ -0,0 +1,83 @@
#include "PeriodicTask.h"
#include "../../serviceinterface/ServiceInterface.h"
#include "../../tasks/ExecutableObjectIF.h"
PeriodicTask::PeriodicTask(const char *name, rtems_task_priority setPriority,
size_t setStack, rtems_interval setPeriod, void (*setDeadlineMissedFunc)()) :
RTEMSTaskBase(setPriority, setStack, name),
periodTicks(RtemsBasic::convertMsToTicks(setPeriod)),
deadlineMissedFunc(setDeadlineMissedFunc) {
}
PeriodicTask::~PeriodicTask(void) {
/* Do not delete objects, we were responsible for pointers only. */
rtems_rate_monotonic_delete(periodId);
}
rtems_task PeriodicTask::taskEntryPoint(rtems_task_argument argument) {
/* The argument is re-interpreted as MultiObjectTask. The Task object is global,
so it is found from any place. */
PeriodicTask *originalTask(reinterpret_cast<PeriodicTask*>(argument));
return originalTask->taskFunctionality();;
}
ReturnValue_t PeriodicTask::startTask() {
rtems_status_code status = rtems_task_start(id, PeriodicTask::taskEntryPoint,
rtems_task_argument((void *) this));
if (status != RTEMS_SUCCESSFUL) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "ObjectTask::startTask for " << std::hex << this->getId()
<< std::dec << " failed." << std::endl;
#endif
}
switch(status){
case RTEMS_SUCCESSFUL:
/* Task started successfully */
return HasReturnvaluesIF::RETURN_OK;
default:
/* RTEMS_INVALID_ADDRESS - invalid task entry point
RTEMS_INVALID_ID - invalid task id
RTEMS_INCORRECT_STATE - task not in the dormant state
RTEMS_ILLEGAL_ON_REMOTE_OBJECT - cannot start remote task */
return HasReturnvaluesIF::RETURN_FAILED;
}
}
ReturnValue_t PeriodicTask::sleepFor(uint32_t ms) {
return RTEMSTaskBase::sleepFor(ms);
}
void PeriodicTask::taskFunctionality() {
RTEMSTaskBase::setAndStartPeriod(periodTicks,&periodId);
for (const auto& object: objectList) {
object->initializeAfterTaskCreation();
}
/* The task's "infinite" inner loop is entered. */
while (1) {
for (const auto& object: objectList) {
object->performOperation();
}
rtems_status_code status = RTEMSTaskBase::restartPeriod(periodTicks,periodId);
if (status == RTEMS_TIMEOUT) {
if (this->deadlineMissedFunc != nullptr) {
this->deadlineMissedFunc();
}
}
}
}
ReturnValue_t PeriodicTask::addComponent(object_id_t object) {
ExecutableObjectIF* newObject = objectManager->get<ExecutableObjectIF>(object);
if (newObject == nullptr) {
return HasReturnvaluesIF::RETURN_FAILED;
}
objectList.push_back(newObject);
newObject->setTaskIF(this);
return HasReturnvaluesIF::RETURN_OK;
}
uint32_t PeriodicTask::getPeriodMs() const {
return RtemsBasic::convertTicksToMs(periodTicks);
}

View File

@ -1,10 +1,10 @@
#ifndef FSFW_OSAL_RTEMS_MULTIOBJECTTASK_H_ #ifndef FSFW_OSAL_RTEMS_PERIODICTASK_H_
#define FSFW_OSAL_RTEMS_MULTIOBJECTTASK_H_ #define FSFW_OSAL_RTEMS_PERIODICTASK_H_
#include "RTEMSTaskBase.h"
#include "../../objectmanager/ObjectManagerIF.h" #include "../../objectmanager/ObjectManagerIF.h"
#include "../../tasks/PeriodicTaskIF.h" #include "../../tasks/PeriodicTaskIF.h"
#include "TaskBase.h"
#include <vector> #include <vector>
class ExecutableObjectIF; class ExecutableObjectIF;
@ -18,7 +18,7 @@ class ExecutableObjectIF;
* @author baetz * @author baetz
* @ingroup task_handling * @ingroup task_handling
*/ */
class MultiObjectTask: public TaskBase, public PeriodicTaskIF { class PeriodicTask: public RTEMSTaskBase, public PeriodicTaskIF {
public: public:
/** /**
* @brief Standard constructor of the class. * @brief Standard constructor of the class.
@ -35,13 +35,13 @@ public:
* @param setDeadlineMissedFunc The function pointer to the deadline missed function * @param setDeadlineMissedFunc The function pointer to the deadline missed function
* that shall be assigned. * that shall be assigned.
*/ */
MultiObjectTask(const char *name, rtems_task_priority setPriority, size_t setStack, rtems_interval setPeriod, PeriodicTask(const char *name, rtems_task_priority setPriority, size_t setStack,
void (*setDeadlineMissedFunc)()); rtems_interval setPeriod, void (*setDeadlineMissedFunc)());
/** /**
* @brief Currently, the executed object's lifetime is not coupled with the task object's * @brief Currently, the executed object's lifetime is not coupled with the task object's
* lifetime, so the destructor is empty. * lifetime, so the destructor is empty.
*/ */
virtual ~MultiObjectTask(void); virtual ~PeriodicTask(void);
/** /**
* @brief The method to start the task. * @brief The method to start the task.
@ -76,7 +76,7 @@ protected:
/** /**
* @brief id of the associated OS period * @brief id of the associated OS period
*/ */
rtems_id periodId; rtems_id periodId = 0;
/** /**
* @brief The pointer to the deadline-missed function. * @brief The pointer to the deadline-missed function.
* @details This pointer stores the function that is executed if the task's deadline is missed. * @details This pointer stores the function that is executed if the task's deadline is missed.
@ -104,4 +104,4 @@ protected:
void taskFunctionality(void); void taskFunctionality(void);
}; };
#endif /* FSFW_OSAL_RTEMS_MULTIOBJECTTASK_H_ */ #endif /* FSFW_OSAL_RTEMS_PERIODICTASK_H_ */

View File

@ -1,131 +0,0 @@
#include "../../tasks/FixedSequenceSlot.h"
#include "../../objectmanager/SystemObjectIF.h"
#include "../../objectmanager/ObjectManagerIF.h"
#include "PollingTask.h"
#include "RtemsBasic.h"
#include "../../returnvalues/HasReturnvaluesIF.h"
#include "../../serviceinterface/ServiceInterfaceStream.h"
#include <rtems/bspIo.h>
#include <rtems/rtems/ratemon.h>
#include <rtems/rtems/status.h>
#include <rtems/rtems/tasks.h>
#include <rtems/rtems/types.h>
#include <stddef.h>
#include <sys/_stdint.h>
#include <iostream>
#include <list>
uint32_t PollingTask::deadlineMissedCount = 0;
PollingTask::PollingTask(const char *name, rtems_task_priority setPriority,
size_t setStack, uint32_t setOverallPeriod,
void (*setDeadlineMissedFunc)()) :
TaskBase(setPriority, setStack, name), periodId(0), pst(
setOverallPeriod) {
// All additional attributes are applied to the object.
this->deadlineMissedFunc = setDeadlineMissedFunc;
}
PollingTask::~PollingTask() {
}
rtems_task PollingTask::taskEntryPoint(rtems_task_argument argument) {
//The argument is re-interpreted as PollingTask.
PollingTask *originalTask(reinterpret_cast<PollingTask*>(argument));
//The task's functionality is called.
originalTask->taskFunctionality();
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::debug << "Polling task " << originalTask->getId()
<< " returned from taskFunctionality." << std::endl;
#endif
}
void PollingTask::missedDeadlineCounter() {
PollingTask::deadlineMissedCount++;
if (PollingTask::deadlineMissedCount % 10 == 0) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "PST missed " << PollingTask::deadlineMissedCount
<< " deadlines." << std::endl;
#endif
}
}
ReturnValue_t PollingTask::startTask() {
rtems_status_code status = rtems_task_start(id, PollingTask::taskEntryPoint,
rtems_task_argument((void *) this));
if (status != RTEMS_SUCCESSFUL) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "PollingTask::startTask for " << std::hex << this->getId()
<< std::dec << " failed." << std::endl;
#endif
}
switch(status){
case RTEMS_SUCCESSFUL:
//ask started successfully
return HasReturnvaluesIF::RETURN_OK;
default:
/* RTEMS_INVALID_ADDRESS - invalid task entry point
RTEMS_INVALID_ID - invalid task id
RTEMS_INCORRECT_STATE - task not in the dormant state
RTEMS_ILLEGAL_ON_REMOTE_OBJECT - cannot start remote task */
return HasReturnvaluesIF::RETURN_FAILED;
}
}
ReturnValue_t PollingTask::addSlot(object_id_t componentId,
uint32_t slotTimeMs, int8_t executionStep) {
ExecutableObjectIF* object = objectManager->get<ExecutableObjectIF>(componentId);
if (object != nullptr) {
pst.addSlot(componentId, slotTimeMs, executionStep, object, this);
return HasReturnvaluesIF::RETURN_OK;
}
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "Component " << std::hex << componentId <<
" not found, not adding it to pst" << std::endl;
#endif
return HasReturnvaluesIF::RETURN_FAILED;
}
uint32_t PollingTask::getPeriodMs() const {
return pst.getLengthMs();
}
ReturnValue_t PollingTask::checkSequence() const {
return pst.checkSequence();
}
#include <rtems/io.h>
void PollingTask::taskFunctionality() {
// A local iterator for the Polling Sequence Table is created to find the start time for the first entry.
FixedSlotSequence::SlotListIter it = pst.current;
//The start time for the first entry is read.
rtems_interval interval = RtemsBasic::convertMsToTicks(it->pollingTimeMs);
TaskBase::setAndStartPeriod(interval,&periodId);
//The task's "infinite" inner loop is entered.
while (1) {
if (pst.slotFollowsImmediately()) {
//Do nothing
} else {
//The interval for the next polling slot is selected.
interval = RtemsBasic::convertMsToTicks(this->pst.getIntervalToNextSlotMs());
//The period is checked and restarted with the new interval.
//If the deadline was missed, the deadlineMissedFunc is called.
rtems_status_code status = TaskBase::restartPeriod(interval,periodId);
if (status == RTEMS_TIMEOUT) {
if (this->deadlineMissedFunc != nullptr) {
this->deadlineMissedFunc();
}
}
}
//The device handler for this slot is executed and the next one is chosen.
this->pst.executeAndAdvance();
}
}
ReturnValue_t PollingTask::sleepFor(uint32_t ms){
return TaskBase::sleepFor(ms);
};

View File

@ -1,85 +0,0 @@
#ifndef FSFW_OSAL_RTEMS_POLLINGTASK_H_
#define FSFW_OSAL_RTEMS_POLLINGTASK_H_
#include "../../tasks/FixedSlotSequence.h"
#include "../../tasks/FixedTimeslotTaskIF.h"
#include "TaskBase.h"
class PollingTask: public TaskBase, public FixedTimeslotTaskIF {
public:
/**
* @brief The standard constructor of the class.
*
* @details This is the general constructor of the class. In addition to the TaskBase parameters,
* the following variables are passed:
*
* @param (*setDeadlineMissedFunc)() The function pointer to the deadline missed function that shall be assigned.
*
* @param getPst The object id of the completely initialized polling sequence.
*/
PollingTask( const char *name, rtems_task_priority setPriority, size_t setStackSize, uint32_t overallPeriod, void (*setDeadlineMissedFunc)());
/**
* @brief The destructor of the class.
*
* @details The destructor frees all heap memory that was allocated on thread initialization for the PST and
* the device handlers. This is done by calling the PST's destructor.
*/
virtual ~PollingTask( void );
ReturnValue_t startTask( void );
/**
* This static function can be used as #deadlineMissedFunc.
* It counts missedDeadlines and prints the number of missed deadlines every 10th time.
*/
static void missedDeadlineCounter();
/**
* A helper variable to count missed deadlines.
*/
static uint32_t deadlineMissedCount;
ReturnValue_t addSlot(object_id_t componentId, uint32_t slotTimeMs, int8_t executionStep);
uint32_t getPeriodMs() const;
ReturnValue_t checkSequence() const;
ReturnValue_t sleepFor(uint32_t ms);
protected:
/**
* @brief id of the associated OS period
*/
rtems_id periodId;
FixedSlotSequence pst;
/**
* @brief This attribute holds a function pointer that is executed when a deadline was missed.
*
* @details Another function may be announced to determine the actions to perform when a deadline was missed.
* Currently, only one function for missing any deadline is allowed.
* If not used, it shall be declared NULL.
*/
void ( *deadlineMissedFunc )( void );
/**
* @brief This is the entry point in a new polling thread.
*
* @details This method, that is the generalOSAL::checkAndRestartPeriod( this->periodId, interval ); entry point in the new thread, is here set to generate
* and link the Polling Sequence Table to the thread object and start taskFunctionality()
* on success. If operation of the task is ended for some reason,
* the destructor is called to free allocated memory.
*/
static rtems_task taskEntryPoint( rtems_task_argument argument );
/**
* @brief This function holds the main functionality of the thread.
*
*
* @details Holding the main functionality of the task, this method is most important.
* It links the functionalities provided by FixedSlotSequence with the OS's System Calls
* to keep the timing of the periods.
*/
void taskFunctionality( void );
};
#endif /* FSFW_OSAL_RTEMS_POLLINGTASK_H_ */

View File

@ -1,9 +1,9 @@
#include "../../serviceinterface/ServiceInterfaceStream.h" #include "RTEMSTaskBase.h"
#include "TaskBase.h" #include "../../serviceinterface/ServiceInterface.h"
const size_t PeriodicTaskIF::MINIMUM_STACK_SIZE=RTEMS_MINIMUM_STACK_SIZE; const size_t PeriodicTaskIF::MINIMUM_STACK_SIZE = RTEMS_MINIMUM_STACK_SIZE;
TaskBase::TaskBase(rtems_task_priority set_priority, size_t stack_size, RTEMSTaskBase::RTEMSTaskBase(rtems_task_priority set_priority, size_t stack_size,
const char *name) { const char *name) {
rtems_name osalName = 0; rtems_name osalName = 0;
for (uint8_t i = 0; i < 4; i++) { for (uint8_t i = 0; i < 4; i++) {
@ -14,7 +14,7 @@ TaskBase::TaskBase(rtems_task_priority set_priority, size_t stack_size,
} }
//The task is created with the operating system's system call. //The task is created with the operating system's system call.
rtems_status_code status = RTEMS_UNSATISFIED; rtems_status_code status = RTEMS_UNSATISFIED;
if (set_priority >= 0 && set_priority <= 99) { if (set_priority <= 99) {
status = rtems_task_create(osalName, status = rtems_task_create(osalName,
(0xFF - 2 * set_priority), stack_size, (0xFF - 2 * set_priority), stack_size,
RTEMS_PREEMPT | RTEMS_NO_TIMESLICE | RTEMS_NO_ASR, RTEMS_PREEMPT | RTEMS_NO_TIMESLICE | RTEMS_NO_ASR,
@ -31,21 +31,21 @@ TaskBase::TaskBase(rtems_task_priority set_priority, size_t stack_size,
} }
} }
TaskBase::~TaskBase() { RTEMSTaskBase::~RTEMSTaskBase() {
rtems_task_delete(id); rtems_task_delete(id);
} }
rtems_id TaskBase::getId() { rtems_id RTEMSTaskBase::getId() {
return this->id; return this->id;
} }
ReturnValue_t TaskBase::sleepFor(uint32_t ms) { ReturnValue_t RTEMSTaskBase::sleepFor(uint32_t ms) {
rtems_status_code status = rtems_task_wake_after(RtemsBasic::convertMsToTicks(ms)); rtems_status_code status = rtems_task_wake_after(RtemsBasic::convertMsToTicks(ms));
return convertReturnCode(status); return convertReturnCode(status);
} }
ReturnValue_t TaskBase::convertReturnCode(rtems_status_code inValue) { ReturnValue_t RTEMSTaskBase::convertReturnCode(rtems_status_code inValue) {
switch (inValue) { switch (inValue) {
case RTEMS_SUCCESSFUL: case RTEMS_SUCCESSFUL:
return HasReturnvaluesIF::RETURN_OK; return HasReturnvaluesIF::RETURN_OK;
@ -68,7 +68,7 @@ ReturnValue_t TaskBase::convertReturnCode(rtems_status_code inValue) {
} }
ReturnValue_t TaskBase::setAndStartPeriod(rtems_interval period, rtems_id *periodId) { ReturnValue_t RTEMSTaskBase::setAndStartPeriod(rtems_interval period, rtems_id *periodId) {
rtems_name periodName = (('P' << 24) + ('e' << 16) + ('r' << 8) + 'd'); rtems_name periodName = (('P' << 24) + ('e' << 16) + ('r' << 8) + 'd');
rtems_status_code status = rtems_rate_monotonic_create(periodName, periodId); rtems_status_code status = rtems_rate_monotonic_create(periodName, periodId);
if (status == RTEMS_SUCCESSFUL) { if (status == RTEMS_SUCCESSFUL) {
@ -77,7 +77,7 @@ ReturnValue_t TaskBase::setAndStartPeriod(rtems_interval period, rtems_id *perio
return convertReturnCode(status); return convertReturnCode(status);
} }
rtems_status_code TaskBase::restartPeriod(rtems_interval period, rtems_id periodId){ rtems_status_code RTEMSTaskBase::restartPeriod(rtems_interval period, rtems_id periodId){
//This is necessary to avoid a call with period = 0, which does not start the period. //This is necessary to avoid a call with period = 0, which does not start the period.
rtems_status_code status = rtems_rate_monotonic_period(periodId, period + 1); rtems_status_code status = rtems_rate_monotonic_period(periodId, period + 1);
return status; return status;

View File

@ -1,5 +1,5 @@
#ifndef FSFW_OSAL_RTEMS_TASKBASE_H_ #ifndef FSFW_OSAL_RTEMS_RTEMSTASKBASE_H_
#define FSFW_OSAL_RTEMS_TASKBASE_H_ #define FSFW_OSAL_RTEMS_RTEMSTASKBASE_H_
#include "RtemsBasic.h" #include "RtemsBasic.h"
#include "../../tasks/PeriodicTaskIF.h" #include "../../tasks/PeriodicTaskIF.h"
@ -9,7 +9,7 @@
* *
* @details Task creation base class for rtems. * @details Task creation base class for rtems.
*/ */
class TaskBase { class RTEMSTaskBase {
protected: protected:
/** /**
* @brief The class stores the task id it got assigned from the operating system in this attribute. * @brief The class stores the task id it got assigned from the operating system in this attribute.
@ -26,11 +26,11 @@ public:
* @param stack_size The stack size reserved by the operating system for the task. * @param stack_size The stack size reserved by the operating system for the task.
* @param nam The name of the Task, as a null-terminated String. Currently max 4 chars supported (excluding Null-terminator), rest will be truncated * @param nam The name of the Task, as a null-terminated String. Currently max 4 chars supported (excluding Null-terminator), rest will be truncated
*/ */
TaskBase( rtems_task_priority priority, size_t stack_size, const char *name); RTEMSTaskBase( rtems_task_priority priority, size_t stack_size, const char *name);
/** /**
* @brief In the destructor, the created task is deleted. * @brief In the destructor, the created task is deleted.
*/ */
virtual ~TaskBase(); virtual ~RTEMSTaskBase();
/** /**
* @brief This method returns the task id of this class. * @brief This method returns the task id of this class.
*/ */
@ -44,4 +44,4 @@ private:
}; };
#endif /* FSFW_OSAL_RTEMS_TASKBASE_H_ */ #endif /* FSFW_OSAL_RTEMS_RTEMSTASKBASE_H_ */

View File

@ -1,5 +1,6 @@
#include "RtemsBasic.h" #include "RtemsBasic.h"
// TODO: Can this be removed?
//ReturnValue_t RtemsBasic::convertReturnCode(rtems_status_code inValue) { //ReturnValue_t RtemsBasic::convertReturnCode(rtems_status_code inValue) {
// if (inValue == RTEMS_SUCCESSFUL) { // if (inValue == RTEMS_SUCCESSFUL) {

View File

@ -2,12 +2,13 @@
#define FSFW_OSAL_RTEMS_RTEMSBASIC_H_ #define FSFW_OSAL_RTEMS_RTEMSBASIC_H_
#include "../../returnvalues/HasReturnvaluesIF.h" #include "../../returnvalues/HasReturnvaluesIF.h"
#include <rtems.h> #include <rtems.h>
#include <rtems/libio.h> #include <rtems/libio.h>
#include <rtems/error.h> #include <rtems/error.h>
#include <rtems/stackchk.h> #include <rtems/stackchk.h>
#include <stddef.h>
#include <cstddef>
class RtemsBasic { class RtemsBasic {
public: public:

View File

@ -1,8 +1,9 @@
#include "../../tasks/TaskFactory.h" #include "FixedTimeslotTask.h"
#include "MultiObjectTask.h" #include "PeriodicTask.h"
#include "PollingTask.h"
#include "InitTask.h" #include "InitTask.h"
#include "RtemsBasic.h" #include "RtemsBasic.h"
#include "../../tasks/TaskFactory.h"
#include "../../returnvalues/HasReturnvaluesIF.h" #include "../../returnvalues/HasReturnvaluesIF.h"
//TODO: Different variant than the lazy loading in QueueFactory. What's better and why? //TODO: Different variant than the lazy loading in QueueFactory. What's better and why?
@ -15,15 +16,21 @@ TaskFactory* TaskFactory::instance() {
return TaskFactory::factoryInstance; return TaskFactory::factoryInstance;
} }
PeriodicTaskIF* TaskFactory::createPeriodicTask(TaskName name_,TaskPriority taskPriority_,TaskStackSize stackSize_,TaskPeriod periodInSeconds_,TaskDeadlineMissedFunction deadLineMissedFunction_) { PeriodicTaskIF* TaskFactory::createPeriodicTask(TaskName name_, TaskPriority taskPriority_,
TaskStackSize stackSize_,TaskPeriod periodInSeconds_,
TaskDeadlineMissedFunction deadLineMissedFunction_) {
rtems_interval taskPeriod = periodInSeconds_ * Clock::getTicksPerSecond(); rtems_interval taskPeriod = periodInSeconds_ * Clock::getTicksPerSecond();
return static_cast<PeriodicTaskIF*>(new MultiObjectTask(name_,taskPriority_,stackSize_,taskPeriod,deadLineMissedFunction_)); return static_cast<PeriodicTaskIF*>(new PeriodicTask(name_, taskPriority_, stackSize_,
taskPeriod,deadLineMissedFunction_));
} }
FixedTimeslotTaskIF* TaskFactory::createFixedTimeslotTask(TaskName name_,TaskPriority taskPriority_,TaskStackSize stackSize_,TaskPeriod periodInSeconds_,TaskDeadlineMissedFunction deadLineMissedFunction_) { FixedTimeslotTaskIF* TaskFactory::createFixedTimeslotTask(TaskName name_,
TaskPriority taskPriority_,TaskStackSize stackSize_,TaskPeriod periodInSeconds_,
TaskDeadlineMissedFunction deadLineMissedFunction_) {
rtems_interval taskPeriod = periodInSeconds_ * Clock::getTicksPerSecond(); rtems_interval taskPeriod = periodInSeconds_ * Clock::getTicksPerSecond();
return static_cast<FixedTimeslotTaskIF*>(new PollingTask(name_,taskPriority_,stackSize_,taskPeriod,deadLineMissedFunction_)); return static_cast<FixedTimeslotTaskIF*>(new FixedTimeslotTask(name_, taskPriority_,
stackSize_, taskPeriod, deadLineMissedFunction_));
} }
ReturnValue_t TaskFactory::deleteTask(PeriodicTaskIF* task) { ReturnValue_t TaskFactory::deleteTask(PeriodicTaskIF* task) {

View File

@ -52,9 +52,8 @@ public:
return id; return id;
} }
static uint32_t getFullParameterId(uint8_t domainId, static uint32_t getFullParameterId(uint8_t domainId, uint8_t uniqueId, uint16_t linearIndex) {
uint8_t uniqueIdentifier, uint16_t linearIndex) { return (domainId << 24) + (uniqueId << 16) + linearIndex;
return (domainId << 24) + (uniqueIdentifier << 16) + linearIndex;
} }
virtual ~HasParametersIF() {} virtual ~HasParametersIF() {}
@ -74,9 +73,9 @@ public:
* matrix indexes. * matrix indexes.
* @return * @return
*/ */
virtual ReturnValue_t getParameter(uint8_t domainId, virtual ReturnValue_t getParameter(uint8_t domainId, uint8_t uniqueIdentifier,
uint16_t uniqueIdentifier, ParameterWrapper *parameterWrapper, ParameterWrapper *parameterWrapper, const ParameterWrapper *newValues,
const ParameterWrapper *newValues, uint16_t startAtIndex) = 0; uint16_t startAtIndex) = 0;
}; };
#endif /* FSFW_PARAMETERS_HASPARAMETERSIF_H_ */ #endif /* FSFW_PARAMETERS_HASPARAMETERSIF_H_ */

View File

@ -90,7 +90,7 @@ ReturnValue_t ParameterHelper::sendParameter(MessageQueueId_t to, uint32_t id,
const ParameterWrapper* description) { const ParameterWrapper* description) {
size_t serializedSize = description->getSerializedSize(); size_t serializedSize = description->getSerializedSize();
uint8_t *storeElement; uint8_t *storeElement = nullptr;
store_address_t address; store_address_t address;
ReturnValue_t result = storage->getFreeElement(&address, serializedSize, ReturnValue_t result = storage->getFreeElement(&address, serializedSize,

View File

@ -38,7 +38,7 @@ void ParameterMessage::setParameterLoadCommand(CommandMessage* message,
store_address_t ParameterMessage::getParameterLoadCommand( store_address_t ParameterMessage::getParameterLoadCommand(
const CommandMessage *message, ParameterId_t* parameterId, uint8_t *ptc, const CommandMessage *message, ParameterId_t* parameterId, uint8_t *ptc,
uint8_t *pfc, uint8_t *rows, uint8_t *columns) { uint8_t *pfc, uint8_t *rows, uint8_t *columns) {
*parameterId = message->getParameter2(); *parameterId = message->getParameter();
uint32_t packedParamSettings = message->getParameter3(); uint32_t packedParamSettings = message->getParameter3();
*ptc = packedParamSettings >> 24 & 0xff; *ptc = packedParamSettings >> 24 & 0xff;
*pfc = packedParamSettings >> 16 & 0xff; *pfc = packedParamSettings >> 16 & 0xff;

View File

@ -1,17 +1,19 @@
#include "ParameterWrapper.h" #include "ParameterWrapper.h"
#include <FSFWConfig.h>
#include <fsfw/serviceinterface/ServiceInterface.h>
ParameterWrapper::ParameterWrapper() : ParameterWrapper::ParameterWrapper() :
pointsToStream(false), type(Type::UNKNOWN_TYPE) { pointsToStream(false), type(Type::UNKNOWN_TYPE) {
} }
ParameterWrapper::ParameterWrapper(Type type, uint8_t rows, uint8_t columns, ParameterWrapper::ParameterWrapper(Type type, uint8_t rows, uint8_t columns,
void *data) : void *data):
pointsToStream(false), type(type), rows(rows), columns(columns), pointsToStream(false), type(type), rows(rows), columns(columns),
data(data), readonlyData(data) { data(data), readonlyData(data) {
} }
ParameterWrapper::ParameterWrapper(Type type, uint8_t rows, uint8_t columns, ParameterWrapper::ParameterWrapper(Type type, uint8_t rows, uint8_t columns,
const void *data) : const void *data):
pointsToStream(false), type(type), rows(rows), columns(columns), pointsToStream(false), type(type), rows(rows), columns(columns),
data(nullptr), readonlyData(data) { data(nullptr), readonlyData(data) {
} }
@ -40,8 +42,8 @@ ReturnValue_t ParameterWrapper::serialize(uint8_t **buffer, size_t *size,
return result; return result;
} }
//serialize uses readonlyData, as it is always valid /* serialize uses readonlyData, as it is always valid */
if (readonlyData == NULL) { if (readonlyData == nullptr) {
return NOT_SET; return NOT_SET;
} }
switch (type) { switch (type) {
@ -75,7 +77,7 @@ ReturnValue_t ParameterWrapper::serialize(uint8_t **buffer, size_t *size,
result = serializeData<double>(buffer, size, maxSize, streamEndianness); result = serializeData<double>(buffer, size, maxSize, streamEndianness);
break; break;
default: default:
result = UNKNOW_DATATYPE; result = UNKNOWN_DATATYPE;
break; break;
} }
return result; return result;
@ -220,22 +222,48 @@ ReturnValue_t ParameterWrapper::set(const uint8_t *stream, size_t streamSize,
ReturnValue_t ParameterWrapper::copyFrom(const ParameterWrapper *from, ReturnValue_t ParameterWrapper::copyFrom(const ParameterWrapper *from,
uint16_t startWritingAtIndex) { uint16_t startWritingAtIndex) {
// TODO: Optional diagnostic output (which can be disabled in FSFWConfig)
// to determined faulty implementations and configuration errors quickly.
if (data == nullptr) { if (data == nullptr) {
#if FSFW_VERBOSE_LEVEL >= 1
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning << "ParameterWrapper::copyFrom: Called on read-only variable!" << std::endl;
#else
sif::printWarning("ParameterWrapper::copyFrom: Called on read-only variable!\n");
#endif
#endif /* FSFW_VERBOSE_LEVEL >= 1 */
return READONLY; return READONLY;
} }
if (from->readonlyData == nullptr) { if (from->readonlyData == nullptr) {
#if FSFW_VERBOSE_LEVEL >= 1
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning << "ParameterWrapper::copyFrom: Source not set!" << std::endl;
#else
sif::printWarning("ParameterWrapper::copyFrom: Source not set!\n");
#endif
#endif /* FSFW_VERBOSE_LEVEL >= 1 */
return SOURCE_NOT_SET; return SOURCE_NOT_SET;
} }
if (type != from->type) { if (type != from->type) {
#if FSFW_VERBOSE_LEVEL >= 1
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning << "ParameterWrapper::copyFrom: Datatype missmatch!" << std::endl;
#else
sif::printWarning("ParameterWrapper::copyFrom: Datatype missmatch!\n");
#endif
#endif /* FSFW_VERBOSE_LEVEL >= 1 */
return DATATYPE_MISSMATCH; return DATATYPE_MISSMATCH;
} }
// The smallest allowed value for rows and columns is one. // The smallest allowed value for rows and columns is one.
if(rows == 0 or columns == 0) { if(rows == 0 or columns == 0) {
#if FSFW_VERBOSE_LEVEL >= 1
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning << "ParameterWrapper::copyFrom: Columns or rows zero!" << std::endl;
#else
sif::printWarning("ParameterWrapper::copyFrom: Columns or rows zero!\n");
#endif
#endif /* FSFW_VERBOSE_LEVEL >= 1 */
return COLUMN_OR_ROWS_ZERO; return COLUMN_OR_ROWS_ZERO;
} }
@ -289,7 +317,7 @@ ReturnValue_t ParameterWrapper::copyFrom(const ParameterWrapper *from,
from->readonlyData, from->rows, from->columns); from->readonlyData, from->rows, from->columns);
break; break;
default: default:
result = UNKNOW_DATATYPE; result = UNKNOWN_DATATYPE;
break; break;
} }
} }

View File

@ -8,14 +8,23 @@
#include <cstddef> #include <cstddef>
/** /**
* @brief * @brief This wrapper encapsulates the access to parameters provided by HasParametersIF.
* @details * @details
* This wrapper is used by the ParameterHelper to interface with the on-board parameters
* exposed by the software via the HasParametersIF. A handle of this wrapper is passed
* to the user which then can be used to set or dump the parameters.
*
* The wrapper provides a set of setter functions. The user should call those setter functions,
* supplying an address to the local parameters. The user can also deserialize or
* serialize the parameter data. Please note that this will also serialize and deserialize
* the parameter information field (4 bytes) containing the ECSS PTC, PFC and rows and columns
* number.
*/ */
class ParameterWrapper: public SerializeIF { class ParameterWrapper: public SerializeIF {
friend class DataPoolParameterWrapper; friend class DataPoolParameterWrapper;
public: public:
static const uint8_t INTERFACE_ID = CLASS_ID::PARAMETER_WRAPPER; static const uint8_t INTERFACE_ID = CLASS_ID::PARAMETER_WRAPPER;
static const ReturnValue_t UNKNOW_DATATYPE = MAKE_RETURN_CODE(0x01); static const ReturnValue_t UNKNOWN_DATATYPE = MAKE_RETURN_CODE(0x01);
static const ReturnValue_t DATATYPE_MISSMATCH = MAKE_RETURN_CODE(0x02); static const ReturnValue_t DATATYPE_MISSMATCH = MAKE_RETURN_CODE(0x02);
static const ReturnValue_t READONLY = MAKE_RETURN_CODE(0x03); static const ReturnValue_t READONLY = MAKE_RETURN_CODE(0x03);
static const ReturnValue_t TOO_BIG = MAKE_RETURN_CODE(0x04); static const ReturnValue_t TOO_BIG = MAKE_RETURN_CODE(0x04);
@ -26,8 +35,7 @@ public:
ParameterWrapper(); ParameterWrapper();
ParameterWrapper(Type type, uint8_t rows, uint8_t columns, void *data); ParameterWrapper(Type type, uint8_t rows, uint8_t columns, void *data);
ParameterWrapper(Type type, uint8_t rows, uint8_t columns, ParameterWrapper(Type type, uint8_t rows, uint8_t columns, const void *data);
const void *data);
virtual ~ParameterWrapper(); virtual ~ParameterWrapper();
virtual ReturnValue_t serialize(uint8_t** buffer, size_t* size, virtual ReturnValue_t serialize(uint8_t** buffer, size_t* size,
@ -77,11 +85,23 @@ public:
this->pointsToStream = false; this->pointsToStream = false;
} }
/**
* Setter function for scalar non-const entries
* @tparam T
* @param member
*/
template<typename T> template<typename T>
void set(T& member) { void set(T& member) {
this->set(&member, 1, 1); this->set(&member, 1, 1);
} }
/**
* Setter function for scalar const entries.
* TODO: This is confusing, it should not be called set. Maybe we should call all functions
* assign instead?
* @tparam T
* @param readonlyMember
*/
template<typename T> template<typename T>
void set(const T& readonlyMember) { void set(const T& readonlyMember) {
this->set(&readonlyMember, 1, 1); this->set(&readonlyMember, 1, 1);
@ -89,12 +109,16 @@ public:
template<typename T> template<typename T>
void setVector(T& member) { void setVector(T& member) {
this->set(member, sizeof(member)/sizeof(member[0]), 1); /* For a vector entry, the number of rows will be one
(left to right, top to bottom indexing) */
this->set(member, 1, sizeof(member) / sizeof(member[0]));
} }
template<typename T> template<typename T>
void setVector(const T& member) { void setVector(const T& member) {
this->set(member, 1, sizeof(member)/sizeof(member[0])); /* For a vector entry, the number of rows will be one
(left to right, top to bottom indexing) */
this->set(member, 1, sizeof(member) / sizeof(member[0]));
} }
template<typename T> template<typename T>
void setMatrix(T& member) { void setMatrix(T& member) {

View File

@ -210,15 +210,15 @@ void Fuse::setDataPoolEntriesInvalid() {
set.commit(); set.commit();
} }
ReturnValue_t Fuse::getParameter(uint8_t domainId, uint16_t parameterId, ReturnValue_t Fuse::getParameter(uint8_t domainId, uint8_t uniqueId,
ParameterWrapper* parameterWrapper, const ParameterWrapper* newValues, ParameterWrapper* parameterWrapper, const ParameterWrapper* newValues,
uint16_t startAtIndex) { uint16_t startAtIndex) {
ReturnValue_t result = currentLimit.getParameter(domainId, parameterId, ReturnValue_t result = currentLimit.getParameter(domainId, uniqueId,
parameterWrapper, newValues, startAtIndex); parameterWrapper, newValues, startAtIndex);
if (result != INVALID_DOMAIN_ID) { if (result != INVALID_DOMAIN_ID) {
return result; return result;
} }
result = powerMonitor.getParameter(domainId, parameterId, parameterWrapper, result = powerMonitor.getParameter(domainId, uniqueId, parameterWrapper,
newValues, startAtIndex); newValues, startAtIndex);
return result; return result;
} }

View File

@ -62,9 +62,9 @@ public:
ReturnValue_t setHealth(HealthState health); ReturnValue_t setHealth(HealthState health);
HasHealthIF::HealthState getHealth(); HasHealthIF::HealthState getHealth();
ReturnValue_t getParameter(uint8_t domainId, uint16_t parameterId, ReturnValue_t getParameter(uint8_t domainId, uint8_t uniqueId,
ParameterWrapper *parameterWrapper, ParameterWrapper *parameterWrapper, const ParameterWrapper *newValues,
const ParameterWrapper *newValues, uint16_t startAtIndex); uint16_t startAtIndex);
private: private:
uint8_t oldFuseState; uint8_t oldFuseState;

View File

@ -61,13 +61,13 @@ ReturnValue_t PowerComponent::deSerialize(const uint8_t** buffer, size_t* size,
return SerializeAdapter::deSerialize(&max, buffer, size, streamEndianness); return SerializeAdapter::deSerialize(&max, buffer, size, streamEndianness);
} }
ReturnValue_t PowerComponent::getParameter(uint8_t domainId, ReturnValue_t PowerComponent::getParameter(uint8_t domainId, uint8_t uniqueId,
uint16_t parameterId, ParameterWrapper* parameterWrapper, ParameterWrapper* parameterWrapper, const ParameterWrapper* newValues,
const ParameterWrapper* newValues, uint16_t startAtIndex) { uint16_t startAtIndex) {
if (domainId != moduleId) { if (domainId != moduleId) {
return INVALID_DOMAIN_ID; return INVALID_DOMAIN_ID;
} }
switch (parameterId) { switch (uniqueId) {
case 0: case 0:
parameterWrapper->set<>(min); parameterWrapper->set<>(min);
break; break;

View File

@ -31,9 +31,9 @@ public:
ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size, ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size,
Endianness streamEndianness) override; Endianness streamEndianness) override;
ReturnValue_t getParameter(uint8_t domainId, uint16_t parameterId, ReturnValue_t getParameter(uint8_t domainId, uint8_t uniqueId,
ParameterWrapper *parameterWrapper, ParameterWrapper *parameterWrapper, const ParameterWrapper *newValues,
const ParameterWrapper *newValues, uint16_t startAtIndex); uint16_t startAtIndex);
private: private:
const object_id_t deviceObjectId = objects::NO_OBJECT; const object_id_t deviceObjectId = objects::NO_OBJECT;
const uint8_t switchId1; const uint8_t switchId1;

View File

@ -119,15 +119,15 @@ HasHealthIF::HealthState PowerSensor::getHealth() {
return healthHelper.getHealth(); return healthHelper.getHealth();
} }
ReturnValue_t PowerSensor::getParameter(uint8_t domainId, uint16_t parameterId, ReturnValue_t PowerSensor::getParameter(uint8_t domainId, uint8_t uniqueId,
ParameterWrapper* parameterWrapper, const ParameterWrapper* newValues, ParameterWrapper* parameterWrapper, const ParameterWrapper* newValues,
uint16_t startAtIndex) { uint16_t startAtIndex) {
ReturnValue_t result = currentLimit.getParameter(domainId, parameterId, ReturnValue_t result = currentLimit.getParameter(domainId, uniqueId,
parameterWrapper, newValues, startAtIndex); parameterWrapper, newValues, startAtIndex);
if (result != INVALID_DOMAIN_ID) { if (result != INVALID_DOMAIN_ID) {
return result; return result;
} }
result = voltageLimit.getParameter(domainId, parameterId, parameterWrapper, result = voltageLimit.getParameter(domainId, uniqueId, parameterWrapper,
newValues, startAtIndex); newValues, startAtIndex);
return result; return result;
} }

View File

@ -48,7 +48,7 @@ public:
float getPower(); float getPower();
ReturnValue_t setHealth(HealthState health); ReturnValue_t setHealth(HealthState health);
HasHealthIF::HealthState getHealth(); HasHealthIF::HealthState getHealth();
ReturnValue_t getParameter(uint8_t domainId, uint16_t parameterId, ReturnValue_t getParameter(uint8_t domainId, uint8_t uniqueId,
ParameterWrapper *parameterWrapper, ParameterWrapper *parameterWrapper,
const ParameterWrapper *newValues, uint16_t startAtIndex); const ParameterWrapper *newValues, uint16_t startAtIndex);
private: private:

View File

@ -1,12 +1,12 @@
target_sources(${LIB_FSFW_NAME} target_sources(${LIB_FSFW_NAME} PRIVATE
PRIVATE Service1TelecommandVerification.cpp
CService200ModeCommanding.cpp Service2DeviceAccess.cpp
CService201HealthCommanding.cpp Service3Housekeeping.cpp
Service17Test.cpp Service5EventReporting.cpp
Service1TelecommandVerification.cpp Service8FunctionManagement.cpp
Service2DeviceAccess.cpp Service9TimeManagement.cpp
Service3Housekeeping.cpp Service17Test.cpp
Service5EventReporting.cpp Service20ParameterManagement.cpp
Service8FunctionManagement.cpp CService200ModeCommanding.cpp
Service9TimeManagement.cpp CService201HealthCommanding.cpp
) )

View File

@ -15,7 +15,7 @@ Service17Test::~Service17Test() {
} }
ReturnValue_t Service17Test::handleRequest(uint8_t subservice) { ReturnValue_t Service17Test::handleRequest(uint8_t subservice) {
switch(subservice){ switch(subservice) {
case Subservice::CONNECTION_TEST: { case Subservice::CONNECTION_TEST: {
TmPacketStored connectionPacket(apid, serviceId, TmPacketStored connectionPacket(apid, serviceId,
Subservice::CONNECTION_TEST_REPORT, packetSubCounter++); Subservice::CONNECTION_TEST_REPORT, packetSubCounter++);

View File

@ -0,0 +1,186 @@
#include "Service20ParameterManagement.h"
#include "servicepackets/Service20Packets.h"
#include <fsfw/serviceinterface/ServiceInterface.h>
#include <fsfw/parameters/HasParametersIF.h>
#include <fsfw/parameters/ParameterMessage.h>
#include <fsfw/parameters/ReceivesParameterMessagesIF.h>
#include <tmtc/pusIds.h>
Service20ParameterManagement::Service20ParameterManagement(object_id_t objectId, uint16_t apid,
uint8_t serviceId, uint8_t numberOfParallelCommands, uint16_t commandTimeoutSeconds) :
CommandingServiceBase(objectId, apid, serviceId,
numberOfParallelCommands,commandTimeoutSeconds) {}
Service20ParameterManagement::~Service20ParameterManagement() {}
ReturnValue_t Service20ParameterManagement::isValidSubservice(
uint8_t subservice) {
switch(static_cast<Subservice>(subservice)) {
case Subservice::PARAMETER_LOAD:
case Subservice::PARAMETER_DUMP:
return HasReturnvaluesIF::RETURN_OK;
default:
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "Invalid Subservice for Service 20" << std::endl;
#else
sif::printError("Invalid Subservice for Service 20\n");
#endif
return AcceptsTelecommandsIF::INVALID_SUBSERVICE;
}
}
ReturnValue_t Service20ParameterManagement::getMessageQueueAndObject(
uint8_t subservice, const uint8_t* tcData, size_t tcDataLen,
MessageQueueId_t* id, object_id_t* objectId) {
ReturnValue_t result = checkAndAcquireTargetID(objectId,tcData,tcDataLen);
if(result != RETURN_OK) {
return result;
}
return checkInterfaceAndAcquireMessageQueue(id,objectId);
}
ReturnValue_t Service20ParameterManagement::checkAndAcquireTargetID(
object_id_t* objectIdToSet, const uint8_t* tcData, size_t tcDataLen) {
if(SerializeAdapter::deSerialize(objectIdToSet, &tcData, &tcDataLen,
SerializeIF::Endianness::BIG) != HasReturnvaluesIF::RETURN_OK) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "Service20ParameterManagement::checkAndAcquireTargetID: "
<< "Invalid data." << std::endl;
#else
sif::printError("Service20ParameterManagement::"
"checkAndAcquireTargetID: Invalid data.\n");
#endif
return CommandingServiceBase::INVALID_TC;
}
return HasReturnvaluesIF::RETURN_OK;
}
ReturnValue_t Service20ParameterManagement::checkInterfaceAndAcquireMessageQueue(
MessageQueueId_t* messageQueueToSet, object_id_t* objectId) {
// check ReceivesParameterMessagesIF property of target
ReceivesParameterMessagesIF* possibleTarget =
objectManager->get<ReceivesParameterMessagesIF>(*objectId);
if(possibleTarget == nullptr) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::error << "Service20ParameterManagement::checkInterfaceAndAcquire"
<<"MessageQueue: Can't access object" << std::endl;
sif::error << "Object ID: " << std::hex << objectId << std::dec << std::endl;
sif::error << "Make sure it implements ReceivesParameterMessagesIF!" << std::endl;
#else
sif::printError("Service20ParameterManagement::checkInterfaceAndAcquire"
"MessageQueue: Can't access object\n");
sif::printError("Object ID: 0x%08x\n", objectId);
sif::printError("Make sure it implements "
"ReceivesParameterMessagesIF!\n");
#endif
return CommandingServiceBase::INVALID_OBJECT;
}
*messageQueueToSet = possibleTarget->getCommandQueue();
return HasReturnvaluesIF::RETURN_OK;
}
ReturnValue_t Service20ParameterManagement::prepareCommand(
CommandMessage* message, uint8_t subservice, const uint8_t* tcData,
size_t tcDataLen, uint32_t* state, object_id_t objectId) {
switch(static_cast<Subservice>(subservice)){
case Subservice::PARAMETER_DUMP: {
return prepareDumpCommand(message, tcData, tcDataLen);
}
break;
case Subservice::PARAMETER_LOAD: {
return prepareLoadCommand(message, tcData, tcDataLen);
}
break;
default:
return HasReturnvaluesIF::RETURN_FAILED;
}
}
ReturnValue_t Service20ParameterManagement::prepareDumpCommand(
CommandMessage* message, const uint8_t* tcData, size_t tcDataLen) {
/* the first part is the objectId, but we have extracted that earlier
and only need the parameterId */
tcData += sizeof(object_id_t);
tcDataLen -= sizeof(object_id_t);
ParameterId_t parameterId;
if(SerializeAdapter::deSerialize(&parameterId, &tcData, &tcDataLen,
SerializeIF::Endianness::BIG) != HasReturnvaluesIF::RETURN_OK) {
return CommandingServiceBase::INVALID_TC;
}
/* The length should have been decremented to 0 by this point */
if(tcDataLen != 0) {
return CommandingServiceBase::INVALID_TC;
}
ParameterMessage::setParameterDumpCommand(message, parameterId);
return HasReturnvaluesIF::RETURN_OK;
}
ReturnValue_t Service20ParameterManagement::prepareLoadCommand(
CommandMessage* message, const uint8_t* tcData, size_t tcDataLen) {
if(tcDataLen < sizeof(object_id_t) + sizeof(ParameterId_t) +
sizeof(uint32_t)) {
return CommandingServiceBase::INVALID_TC;
}
uint8_t* storePointer = nullptr;
store_address_t storeAddress;
size_t parameterDataLen = tcDataLen - sizeof(object_id_t) - sizeof(ParameterId_t) -
sizeof(uint32_t);
ReturnValue_t result = IPCStore->getFreeElement(&storeAddress,
parameterDataLen, &storePointer);
if(result != HasReturnvaluesIF::RETURN_OK) {
return result;
}
/* Following format is expected: The first 4 bytes in the TC data are the 4 byte
parameter ID (ParameterId_t). The second 4 bytes are the parameter information field,
containing the following 1 byte fields:
1. ECSS PTC field
2. ECSS PFC field
3. Number of rows
4. Number of columns */
ParameterLoadCommand command(storePointer, parameterDataLen);
result = command.deSerialize(&tcData, &tcDataLen,
SerializeIF::Endianness::BIG);
if(result != HasReturnvaluesIF::RETURN_OK) {
return result;
}
ParameterMessage::setParameterLoadCommand(message, command.getParameterId(), storeAddress,
command.getPtc(), command.getPfc(), command.getRows(), command.getColumns());
return HasReturnvaluesIF::RETURN_OK;
}
ReturnValue_t Service20ParameterManagement::handleReply(
const CommandMessage* reply, Command_t previousCommand, uint32_t* state,
CommandMessage* optionalNextCommand, object_id_t objectId,
bool* isStep) {
Command_t replyId = reply->getCommand();
switch(replyId) {
case ParameterMessage::REPLY_PARAMETER_DUMP: {
ConstAccessorPair parameterData = IPCStore->getData(
ParameterMessage::getStoreId(reply));
if(parameterData.first != HasReturnvaluesIF::RETURN_OK) {
return HasReturnvaluesIF::RETURN_FAILED;
}
ParameterId_t parameterId = ParameterMessage::getParameterId(reply);
ParameterDumpReply parameterReply(objectId, parameterId,
parameterData.second.data(), parameterData.second.size());
sendTmPacket(static_cast<uint8_t>(
Subservice::PARAMETER_DUMP_REPLY), &parameterReply);
return HasReturnvaluesIF::RETURN_OK;
}
default:
return CommandingServiceBase::INVALID_REPLY;
}
}

View File

@ -0,0 +1,60 @@
#ifndef FSFW_PUS_SERVICE20PARAMETERMANAGEMENT_H_
#define FSFW_PUS_SERVICE20PARAMETERMANAGEMENT_H_
#include <fsfw/tmtcservices/CommandingServiceBase.h>
/**
* @brief PUS Service 20 Parameter Service implementation
* @details
* This service handles PUS service requests related to parameter management and forwards
* them to the internal software bus.
* @author J. Gerhards
*
*/
class Service20ParameterManagement : public CommandingServiceBase
{
public:
Service20ParameterManagement(object_id_t objectId, uint16_t apid, uint8_t serviceId,
uint8_t numberOfParallelCommands = 4, uint16_t commandTimeoutSeconds = 60);
virtual ~Service20ParameterManagement();
static constexpr uint8_t NUM_OF_PARALLEL_COMMANDS = 4;
static constexpr uint16_t COMMAND_TIMEOUT_SECONDS = 60;
protected:
/* CommandingServiceBase (CSB) abstract functions. See CSB documentation. */
ReturnValue_t isValidSubservice(uint8_t subservice) override;
ReturnValue_t getMessageQueueAndObject(uint8_t subservice,
const uint8_t *tcData, size_t tcDataLen, MessageQueueId_t *id,
object_id_t *objectId) override;
ReturnValue_t prepareCommand(CommandMessage* message, uint8_t subservice,
const uint8_t *tcData, size_t tcDataLen, uint32_t *state,
object_id_t objectId) override;
ReturnValue_t handleReply(const CommandMessage* reply,
Command_t previousCommand, uint32_t *state,
CommandMessage* optionalNextCommand, object_id_t objectId,
bool *isStep) override;
private:
ReturnValue_t checkAndAcquireTargetID(object_id_t* objectIdToSet,
const uint8_t* tcData, size_t tcDataLen);
ReturnValue_t checkInterfaceAndAcquireMessageQueue(
MessageQueueId_t* messageQueueToSet, object_id_t* objectId);
ReturnValue_t prepareDirectCommand(CommandMessage* message,
const uint8_t* tcData, size_t tcDataLen);
ReturnValue_t prepareDumpCommand(CommandMessage* message,
const uint8_t* tcData, size_t tcDataLen);
ReturnValue_t prepareLoadCommand(CommandMessage* message,
const uint8_t* tcData, size_t tcDataLen);
enum class Subservice {
PARAMETER_LOAD = 128, //!< [EXPORT] : Load a Parameter
PARAMETER_DUMP = 129, //!< [EXPORT] : Dump a Parameter
PARAMETER_DUMP_REPLY = 130, //!< [EXPORT] : Dump a Parameter
};
};
#endif /* FSFW_PUS_SERVICE20PARAMETERMANAGEMENT_H_ */

View File

@ -104,12 +104,14 @@ ReturnValue_t Service8FunctionManagement::handleReply(
break; break;
} }
case ActionMessage::DATA_REPLY: { case ActionMessage::DATA_REPLY: {
/* Multiple data replies are possible, so declare data reply as step */
*isStep = true;
result = handleDataReply(reply, objectId, actionId); result = handleDataReply(reply, objectId, actionId);
break; break;
} }
case ActionMessage::STEP_FAILED: case ActionMessage::STEP_FAILED:
*isStep = true; *isStep = true;
/*No break, falls through*/ /* No break, falls through */
case ActionMessage::COMPLETION_FAILED: case ActionMessage::COMPLETION_FAILED:
result = ActionMessage::getReturnCode(reply); result = ActionMessage::getReturnCode(reply);
break; break;

View File

@ -0,0 +1,142 @@
#ifndef FSFW_PUS_SERVICEPACKETS_SERVICE20PACKETS_H_
#define FSFW_PUS_SERVICEPACKETS_SERVICE20PACKETS_H_
#include <FSFWConfig.h>
#include <fsfw/parameters/HasParametersIF.h>
#include <fsfw/serialize/SerialBufferAdapter.h>
#include <fsfw/serialize/SerializeElement.h>
#include <fsfw/serialize/SerialLinkedListAdapter.h>
#include <fsfw/serviceinterface/ServiceInterface.h>
/**
* @brief This class encapsulates the packets sent to the PUS service 20 or sent by the
* PUS service 20
* @details
* This command can be used to handle both load and dump commands as well.
* @author
*/
class ParameterCommand: public SerialLinkedListAdapter<SerializeIF> { //!< [EXPORT] : [SUBSERVICE] 128, 129, 130
public:
/**
* This constructor is used for load replies. The data is expected in the correct formast
* in the store pointer.
* @param storePointer
* @param parameterDataLen
*/
ParameterCommand(uint8_t* storePointer, size_t parameterDataLen):
parameterBuffer(storePointer, parameterDataLen) {
#if FSFW_VERBOSE_LEVEL >= 1
if(parameterDataLen < sizeof(object_id_t) + sizeof(ParameterId_t) + 4) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
sif::warning << "ParameterCommand: Parameter data length is less than 12!"
<< std::endl;
#else
sif::printWarning("ParameterCommand: Parameter data length is less than 12!\n");
#endif
}
#endif /* FSFW_VERBOSE_LEVEL >= 1 */
setLoadLinks();
}
/**
* This constructor is used for dump replies. It is assumed the 4 byte parameter
* information field is located inside the parameter buffer.
* @param objectId
* @param parameterId
* @param parameterBuffer
* @param parameterBufferSize
*/
ParameterCommand(object_id_t objectId, ParameterId_t parameterId,
const uint8_t* parameterBuffer, size_t parameterBufferSize):
objectId(objectId), parameterId(parameterId),
parameterBuffer(parameterBuffer, parameterBufferSize) {
setDumpReplyLinks();
}
ParameterId_t getParameterId() const {
return parameterId.entry;
}
const uint8_t* getParameterBuffer() {
return parameterBuffer.entry.getConstBuffer();
}
size_t getParameterBufferLen() const {
return parameterBuffer.getSerializedSize();
}
uint8_t getDomainId() const {
return (parameterId.entry >> 24) & 0xff;
}
uint8_t getUniqueId() const {
return (parameterId.entry >> 16) & 0xff;
}
uint16_t getLinearIndex() const {
return parameterId.entry & 0xffff;
}
uint8_t getPtc() const {
return ccsdsType.entry >> 8 & 0xff;
}
uint8_t getPfc() const {
return ccsdsType.entry & 0xff;
}
uint8_t getRows() const {
return rows.entry;
}
uint8_t getColumns() const {
return columns.entry;
}
private:
void setLoadLinks() {
setStart(&objectId);
objectId.setNext(&parameterId);
parameterId.setNext(&ccsdsType);
ccsdsType.setNext(&rows);
rows.setNext(&columns);
columns.setNext(&parameterBuffer);
}
void setDumpReplyLinks() {
/* For a dump reply, the parameter information is contained in the parameter buffer
with the actual parameters */
setStart(&objectId);
objectId.setNext(&parameterId);
parameterId.setNext(&parameterBuffer);
}
void setDumpRequestLinks() {
setStart(&objectId);
objectId.setNext(&parameterId);
}
SerializeElement<object_id_t> objectId = 0;
SerializeElement<ParameterId_t> parameterId = 0;
//! [EXPORT] : [COMMENT] Type consisting of one byte PTC and one byte PFC.
SerializeElement<uint16_t> ccsdsType = 0;
SerializeElement<uint8_t> rows = 0;
SerializeElement<uint8_t> columns = 0;
SerializeElement<SerialBufferAdapter<uint8_t>> parameterBuffer;
};
class ParameterLoadCommand: public ParameterCommand {
public:
ParameterLoadCommand(uint8_t* parameterPacket, size_t parameterDataLen):
ParameterCommand(parameterPacket, parameterDataLen) {}
};
class ParameterDumpReply: public ParameterCommand {
public:
ParameterDumpReply(object_id_t objectId, ParameterId_t parameterId,
const uint8_t* parameterBuffer, size_t parameterBufferSize):
ParameterCommand(objectId, parameterId, parameterBuffer, parameterBufferSize) {}
};
#endif /* FSFW_PUS_SERVICEPACKETS_SERVICE20PACKETS_H_ */

View File

@ -29,7 +29,7 @@ ServiceInterfaceBuffer::ServiceInterfaceBuffer(std::string setMessage,
#if FSFW_COLORED_OUTPUT == 1 #if FSFW_COLORED_OUTPUT == 1
if(setMessage.find("DEBUG") != std::string::npos) { if(setMessage.find("DEBUG") != std::string::npos) {
colorPrefix = sif::ANSI_COLOR_MAGENTA; colorPrefix = sif::ANSI_COLOR_CYAN;
} }
else if(setMessage.find("INFO") != std::string::npos) { else if(setMessage.find("INFO") != std::string::npos) {
colorPrefix = sif::ANSI_COLOR_GREEN; colorPrefix = sif::ANSI_COLOR_GREEN;

View File

@ -45,7 +45,7 @@ void fsfwPrint(sif::PrintLevel printType, const char* fmt, va_list arg) {
len += sprintf(bufferPosition, sif::ANSI_COLOR_GREEN); len += sprintf(bufferPosition, sif::ANSI_COLOR_GREEN);
} }
else if(printType == sif::PrintLevel::DEBUG_LEVEL) { else if(printType == sif::PrintLevel::DEBUG_LEVEL) {
len += sprintf(bufferPosition, sif::ANSI_COLOR_MAGENTA); len += sprintf(bufferPosition, sif::ANSI_COLOR_CYAN);
} }
else if(printType == sif::PrintLevel::WARNING_LEVEL) { else if(printType == sif::PrintLevel::WARNING_LEVEL) {
len += sprintf(bufferPosition, sif::ANSI_COLOR_YELLOW); len += sprintf(bufferPosition, sif::ANSI_COLOR_YELLOW);

Some files were not shown because too many files have changed in this diff Show More